Kの開発メモ #0001
- (by K, 2013.03.12)
- ここは川合の開発の進捗などをレポートするところです。
- 当初はその予定だったが、今ではむしろ主たる目的はKの備忘録になってしまっている(苦笑)。
2013.03.12 Tue
- 諸事情により、このプロジェクトを早期に立ち上げる必要が出てきた。ということで本気出す。
- 以下のページは内容が難しすぎるので、読まないでください or 内容がOSECPUと関係ないので読まないでください or 内容が既に古くて、正しくありません。
- ええとそれで、freeしたメモリを再利用できてしまう問題はどうなったんだっけ?
- 基本的な考え方として、たとえばGCみたいに、「メモリなんてどんどんアロケートして使えばいいんだよー、free()はシステムが自動でやってくれるんだよー」みたいなのは嫌だ。それはプログラマが楽できるけど、同時にバカになっていくような気がする。
- 僕としては、「プログラマのやることを減らす」方向ではなくて、「プログラマのバグ発見のお手伝いをする」方向でやりたい。
- 関数呼び出しについても考え始めました。 → page0007
2013.03.16 Sat
- やっぱり最初からJITしようかなと思案中・・・。
- インタプリタだと作りやすいけど、すごく遅くなってそれで可能性を見限られたら残念かなーと。
2013.03.19 Tue
- クラックするプログラムの多くは、まずみんなシェルを取ってルートになることを目指すパターンが多い。そんなにルートになりたいんだったら、ルートにしてやればいいじゃないかと急に思いつく。え・・・と思うかもしれないけど、何が言いたいのかというと、ルートにさせない方法を講じるのも大事だけど、ルートになっても大したことが出来なければいいんじゃないかなーと。
- いやもちろん、これは出発点だ。本当にルートになってやりたい放題されたら終わってしまう。・・・僕の言いたいことは、結局はパスワードさえわかれば何でもできますみたいなOSだとパスワードが狙われるだけなので、パスワードが分かっても悪いことはできません、みたいなことを目指すべきなんじゃないかなと。というか最初のログイン時以外にはパスワードは要求されない、というのはどうか?それ以降はどれほどたくさんパスワードを持っていても何もできない、と。
- もう少し考えた!
- 唐突だけど、ブラウザのプラグインみたいなものを考えてみる。もし自作のブラウザにプラグインを付けられるようにしようと思ったらどうするだろうか?なんらかの独自の言語処理系を付けるだろうか。まあその路線で考えてみよう。
- そうすると問題が出てくる。プラグインが悪さをしたらどうしよう、ということだ。ということで悪さできないように念入りに設計する。何をやってもOSや他のアプリやブラウザそのものや他のプラグインの迷惑にはならないようになっている、と。それが無事にできるのであればそれは素晴らしい。
- しかしきっとどこかでミスる。・・・そしてそこがセキュリティホールになる。まあこのセキュリティホールをつついたところで、せいぜい破壊できるのはブラウザや他のプラグインくらいにはとどまると思うが、しかしそれでも十分に残念だ。
- これを防ぐにはどうしたらいいだろう。そう、独自の言語処理系を作らせなければいい。既存の枯れた言語処理系を使わせればいい。・・・そもそもどうしてプラグインのために独自の言語処理系を作ることになったんだ?それは、ブラウザの子プロセスではどうしていけないのか?そう、子プロセスだとなんでも好き放題できてしまうから駄目なんだ。セキュアなプログラムが阻止すべき最初のことは「任意のプログラムが実行できてしまうこと」なくらいだから。
- しかし僕は逆で行く。子プロセスでいいんだ。子プロセスがいいんだ。それでも十分にセキュアなんだ。どんなに悪さをしようと思っても、必ず失敗するんだ。僕はそういう仕組みを作りたい。
- 僕は独自言語を作ることそのものは否定しない。プログラム言語はどんどん提案されるべきだし、プラグインに向いたプログラミング言語というのものだってきっとあるだろう。そのことを否定したいんじゃない。むしろその言語は独自ブラウザのプラグイン用の独自言語ではなくて、他の場面でも自由に使えるべきなんだ。テキストエディタや表計算のマクロを書いたり、普通にゲームを作ったり・・・。そうなればセキュリティはすぐに枯れる。
- つまり何が言いたいのかと言えば、「プラグイン機構は子プロセスで十分」なOSが現れれば、セキュアな世界はずっと広がる、ということなんだ!子プロセスというか、ただ関数をロードして実行するくらいのものしか考えていないので、DLLというべきかもしれない。
- 親プロセスは以下のことを制御できれば、プラグイン機構を子プロセスで代用できる。
- 関数ポインタを渡せる(親プロセスの機能を呼び出すため)。
- 渡していないオブジェクトには絶対にアクセスできない。
- システムコールが使えないか、もしくは使えるんだけど制限がかかっている。どんな制限にするかは親プロセスが自由に設定できる。
- 使ってもよいシステムコール、呼び出し回数、アクセス権など
- タイムアウト的なものがあり、いつまでも帰ってこないようなら打ち切らせる。
- これは実時間などではなく、分岐命令の実行回数を使いたい
- 使用できるリソース量も上限がある。
- ディレクトリパスについて。
- フルパスを許さない。これを許してしまえばどこへでも行けてしまう。
- 相対パスについて、..で親に戻る処理はAPIで行い、APIはどこまでなら戻れるのかを正確に把握している。
- システムコールについて。
- システムコールするにはハンドルが必須。まずハンドルがもらえなければシステムコールはすべてできないということになる。そしてハンドルごとに何がどこまで許されるのかという設定が細かく設定されていて、それによって子プロセスは制約を受けている。
- とりあえず、JITできるプログラムを作ってみた。まだNOPと整数レジスタへの即値ロードと加算演算しか作ってないけど。
2013.03.21 Thu
- (1) neriさんがJavaやC++の例外(try-catch)について書いてくれています。
- 僕はpage0009の(9)でmallocやfopenなどのエラー処理について書いたばかりだったので、この記事は興味深く読みました。もちろん僕もJavaは何年も前からかじってはいるので、例外処理のことは知っていますが、でも改めて自分の考えたエラー処理の仕方は例外処理と比べてどうなのかなと比較してみたくなったのです。
- 「例外」は結局、プログラマにエラー処理を忘れさせないための仕組みだったのだと思います。それでも忘れたい人は何もしないcatch節を書いて握りつぶすわけですが、とにかく例外は「これはエラーが起きるかもしれないんだ」ということを意識させる仕組みだと思います。つまり注意力が乏しいから思い出させようというわけですね。それと同時に例外処理はプログラム的には少々ややこしくもなっています。例外処理を持つ処理系は例外処理のためにランタイムルーチンが複雑になっています。
- 一方で僕が今回考えた方法はどうでしょうか。まず出発点として、僕はfopen()して結果がNULLだったら「fopen-errorとか表示してexit(1)する」みたいな処理を毎回書いているという事実があります。毎回毎回書くから、だんだんバカらしくなってきます。だったらエラー処理付きのfopenがあればいいじゃないかと思いました。このmy_fopenはfopenに失敗したら規定のエラーメッセージを出力してexit(1)するという関数です。
- このmy_fopenを使っている限り、僕はこいつがもしかしたらNULLを返すんじゃないかということを完全に忘れていられます。もちろんときには「エラーになったからって勝手に終了しないでくれよー、その場合はやるべき後処理があるんだ」ということだってあります。そういうときはmy_fopenを使うのをやめて、fopenに戻ればいいだけです。
- これで思ったのは、実はmy_fopenこそデフォルトで、fopenのほうがオプショナルであるほうが自然じゃないかということでした。そして第二世代OSASKではAPIをそのように設計して、エラー処理はAPIに任せるのを基本にしてみました。するとどうでしょう、プログラムはとても書きやすくなり、それでいてエラー処理を忘れているというわけでもなく(十分ではないかもしれないが、とにかく最低限のエラー処理はできている)、そしてプログラムは単純で短くなったのです。・・・僕は「これだ!」と思い、今回のOSECPUでもこの思想を採用しました。
- そもそもみんなそんなにエラー処理をしたいのでしょうか?理想はエラー処理を忘れてもそれなりになんとかなることなんじゃないでしょうか?ある関数を使うときに、全ての起こりうるエラーについて熟知しなければ使ってはいけないというのが果たしてよいことなんでしょうか?どんなエラーが起こるのかを完全に知っているのはむしろfopenのほうなのですから、基本的にはエラー処理もfopenに任せるほうがうまくやってくれるのではないでしょうか?もちろん自分でやりたいときはありますし、自分でやったほうがうまく行くことだってあります。でもデフォルトがどちらであるべきかといえば、断然OSECPUのやりかたのほうがうまいのではないかと思うのです。
- 僕のやっていることは、昔のBASICの「ON ERROR GOTO」命令を思い出せます。つまり全ての命令はデフォルトでエラー時にはメッセージを出して終了だったのです。そしてエラーハンドラを書いたときだけ、そちらに制御が移るわけです。今の常識的なエラー処理の考え方は違っていて(これには例外によるプログラミングスタイルも含みます)、全てのプログラムにエラー処理コードを要求するのです。それで書き忘れると誤動作するのです。
- 結局僕は何も新しいことを考えたわけではなくて、昔のやり方に戻っただけなのです。
- (2) 現状のOSECPUは実レジスタを仮想レジスタに一つも割り当てていません。そのせいでたぶん性能が出ていないと思います。これはいつか改善すべきポイントですが、しかしこれをやるとコードが複雑になってOSECPUの「教材向け」の側面が弱くなってしまうので、当面は先送りにしようと思います。すみません。
- JITにするかしないかは多分10倍くらいの性能差があると思います。実レジスタを仮想レジスタに割り当てるようにすれば、おそらくさらに2倍くらいは性能が変わると思います。・・・つまり何を言いたいのかというと、単純化を目指すとはいっても10倍も性能が変わるインタプリタ方式を検討するのかといえば、それはさすがないないかなといいたいわけです。一方で、2倍くらいの性能差であれば、OSECPUでは単純化のほうを選ぶこともありうる、というわけです。
- (3) OSECPUに費やせる当面の時間がどのくらいあるかを考えてみた。これはセキュリティキャンプ関連ということで会社の時間も投入しているので、時間は結構ある(セキュアなOSの自作ブームを起こしたい・・・小さいものでいいので)。ある程度のコミュニティを作るためには、やはりゲームを作れる環境になっていなければいけない。あとさすがにDB命令やバイナリエディタでゲームを作ってねというのはひどすぎるので、簡単な言語処理系も作る必要があるだろう。まあ1ヶ月くらいでできるところまでやってみるか。
こめんと欄