セキュリティキャンプ2019 OS開発ゼミ体験記
この度セキュリティキャンプ2019全国大会を修了しました。関係者各位はお疲れ様でした。
この記事では自分が受講したYトラックのOS開発ゼミ、テーマ「フルスクラッチOSを書こう!」を中心に、キャンプについて感想を述べていきたいと思います。
事前学習期間
キャンプの選考に通ってから、キャンプ当日に向けて事前学習を行いました。
当初の予定
まず選考時点では自分のOSは
- ブートローダ
- 画面描画関数
しかありませんでした。
当初は、キャンプ当日ではファイルシステムを実装して、コマンドを打ち込んで操作できる状態までやろうと思っていました。
なので、事前課題では以下のことをやろうと思いました。
- 64bitモードへの移行
- GDTとIDTの初期化
- キーボード入力
- ページングテーブルの初期化とページングの有効化
- コンソールを作り、コマンド入力をできるようにする
実際の進行
kintoneで講師の内田さん (@uchan_nos) やチューターさんに質問したり進捗報告したりしていました。 やっていてだらけそうだなと思った(事前学習期間が2ヶ月くらいある)ので、途中から専用スレッドを立ててもらいそこで日報を書き始めました。
日報には、一日のはじめに目標とそれに対してやることを書き、一日の終わりにやったことと疑問点を書きました。 これは結構良かったです。最後の方は学校の行事とかぶって少し失速しましたが、概ねペースを保てたかなと思います。
最終的に事前学習でやれたことは
- 64bitモードへの移行(実は最初からできていたことが調査でわかった)
- GDT,IDTの初期化
- キーボード入力
- ページングテーブルの初期化とページングの有効化
- コンソールを途中まで作った
でした。
キャンプ当日のやること決め
キャンプ数週間前に、当日にやることを決めました。
当初はファイルシステムの実装を目標にしていましたが、自分がファイルシステムがなんなのかわかっておらず、またファイルシステムについて勉強する時間が取れなさそうだったので、タイマ割り込みの実装と、タイマ割り込みを使ったコマンドの作成に変更しました。
前日のトラブル
事前学習中に運営局から実機検証用のボードが送られてきたのですが、自分はめんどくさがって実機検証を行っていませんでした。
キャンプ前日に実機のことを思い出し実機検証をしようとしたら、シリアル通信用のケーブルが入っていないことに気づきました(キーボード入力をシリアル通信で行うように設計していた)。 運営局も用意はしていないということで、前日に大慌てで秋葉原まで行き、シリアル通信ケーブルを購入しました。 秋月電子が夏季休業していたときは絶望しましたが、マルツが開いていたのでなんとか手に入れることができました。
これを読んでいる2020年以降のキャンパーさんたちは、キャンプ1週間前くらいには必要機材の確認などは済ませておきましょう。おじさんとの約束だぞ!!!
キャンプ期間中
1日目
メシ食って開会式や全体講義、グループワークがありました。
講義は法律についてとコミュニティについてでした。倫理観身につけていきたいです。
名刺交換もいろんな時間にしました。200枚持っていったんですけどコミュ力不足で50枚位しか消費しませんでした。自分のコミュ力に合った枚数を持っていこうな。
2日目
この日から専門講義が始まりました。と言っても自分のゼミはひたすら開発!開発!開発!でした。
消すと動かなくなるバグが発生
この日の前半はバグを潰す活動をしていました。バグの症状としては、無駄な処理を消すと動作が止まってしまうというものでした。 例外ハンドラは作成していて検知できるようになっていましたが、例外ハンドラを読み込む部分より前でバグっているようだったのでそれは使えません。
そこでシリアルに出力をしてどこが原因かまず特定したらどうかと講師の内田さんから提案されたのでそうすることにしました。 色々やった結果、GDTの設定周辺の無駄な処理を消すと動作が止まることがわかりました。 バイナリを逆アセンブルしてみたりQEMU Monitorでメモリを覗いたりと四苦八苦していたところ、なんだかわからないけど安定動作するようになりました。 何だったんだろう……
ACPI PMタイマとLocal APICの設定
後半はLocal APICのタイマを動作させるべく、ACPI PMタイマの設定を始めました。
ACPI PMタイマは周波数が決まっているので、PMタイマでLocal APICタイマの周波数を計測して、その周波数をもとにメインのタイマとしてLocal APICを使用するといったことをしました。 チューターのPG_MANAさんが持ってきてくれた「Local APICタイマー入門」(著者は講師の内田さんです)を読んで設定をしました。 この日はPMタイマの設定まで終わりました。
3日目
この日も開発です。
タイマ割り込みが呼び出せない
この日は1日中タイマの設定がうまく行かず苦しんでいました。
タイマ割り込みのハンドラを呼び出そうとすると一般保護例外が出ているようだったので、一般保護例外のエラーコードを取ろうということになりました。
コンパイラの拡張の __attribute__((interrupt))
を関数の頭につけると引数にエラーコードが取れるので、それを使おうとしましたが、GCCではうまくいかなかったのでclangに変更したらうまくいきました。
そうしてエラーコードを読もうとしましたがエラーコードを正しく取れておらず、結局QEMU Monitorでメモリを直接覗いて確認しました。
そうしてエラーコードを見たのですが、なんだかよくわからない値が入っていて解決ならず。
IDTへのハンドラの登録がおかしいのではないかという話になったので確認してみてもおかしいところは……ありました。 IDT自体の設定がミスっていて、IDTのリミットを設定する部分が小さくなっていました…… 一般保護例外とページフォルトのハンドラはギリギリカバーできるリミット設定で、タイマ割り込みのハンドラはリミット外に位置していたので範囲外にアクセスしていたようです……
講義時間終了後にちょっと作業して、タイマが動くようになりました。
自作OSのタイマー動いた!タイマー動いたあああああああああ!!!!
— Note:まずソースを探す癖をつける (@totsugeki8) 2019年8月15日
今日ずっとバグ取りしてたので喜びもひとしお😂😂😂#seccamp pic.twitter.com/S2L8ZaNVEL
4日目
開発最終日! sleepコマンドとdelayコマンドを作るべく頑張りました。
sleepから戻ってこないバグ
午前中はsleepコマンドを作っていました。
簡単にできるかと思いきや、デバッグ用の関数を消してsleepしたら一生戻ってこないバグが出ました。
一般保護例外やページフォルトも出なかったのでobjdumpしてみると [rbp+0x8]
のようなアドレスを読んでいて、むちゃくちゃな値がsleepの引数に渡っていることがわかりました。
しかしそうなった原因がわからず、ウンウン唸ってもどうにもわからなかったので、同じ部屋で活動しているコンパイラゼミの講師であるhikaliumさんに助けを求めたところ、Red Zoneの可能性があると言われました。
そこでRed Zoneを抑制する -mno-red-zone
をコンパイラオプションにつけてビルドしてみると、正常に動くようになりました(Red Zoneについては下にアップするスライドで解説しています)。
時間切れ
午後はdelayコマンドの実装をはじめました。
delayコマンドは第一引数に秒数を、第二引数以降に行いたいコマンドを取り、指定秒数後に指定コマンドを実行する、なお指定秒数までは通常のコマンド操作はできるように実装する、といったようなものを想定して作りました。
戦略としては、
- コンソール側にタスクキューとフラグをもたせる
- タスクは実行する予定時刻と文字列を持つ
- delayコマンドはタスクキューにタスクを詰める
- タイマはタスクキューを見て、予定時刻を過ぎているタスクが詰まっていたらフラグを立てる
- コンソールはフラグが立ったらキューに詰まっているタスクを実行する
というものを考えました。
これを実装しようとガチャガチャやっていましたが、自分のコンソール関数の設計上の問題でプログラムが難しく、あえなく時間切れになってしまいました。
5日目
成果報告会で発表しました。
その後は他の人の発表を聴いたり、閉会式で修了証書を受け取るのを見たりしました。
そんなこんなしてセキュリティキャンプ2019は閉会しました。
感想
月並みですが参加してよかったです。
もちろん講師さんやチューターさんが横にいる環境で開発できたというのもそうですが、同年代の優秀な人たちと触れ合えたというのも良かったし、モチベーションが高まったというのも得たことの1つです。 今後も精進するぞ。
今後の予定
OS開発は続けていきます(学校での自主課題でもあり、ラボユースのテーマでもあるので)。 キャンプ中にできなかったdelayコマンドの実装もやりたいと思います。
また並行してOSのドキュメントも作っていきたいと思います。
最後になりましたが
講師陣の皆さん、チューターの皆さん、運営に関わった皆さん、全ての関係者各位に感謝します。
ありがとうございました!
終了
終了!