パスワードを忘れた? アカウント作成
6646 story

CPUレベルでバッファオーバラン対策 93

ストーリー by yasu
管理者も一安心? 部門より

Jadawin 曰く、 "電机本舗が、バッファオーバランを根本的に解決するCPUアーキテクチャを提案し、特許出願中らしい。要するに一つのスタックに関数への引数と戻り番地を積むことが問題なのだから、それらを分ければ良いという発想。このアイデアの妥当性、特許として類例の有無など、/.諸兄の議論をお願いしたい。"

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by Anonymous Coward on 2003年10月06日 3時35分 (#409299)
    電机本舗の方法だと、関数へのポインタが引数にのってる場合の問題は解決しないぞ。

    CPUアーキテクチャを変更する前に、コンパイラによって解決する方法がいくつか提案されている。ひとまず日本語で読めるものとしてこれを読んでみよう。

    江藤 博明, 依田 邦和, propolice:スタックスマッシング攻撃検出手法の改良 [ipsj.or.jp], 情報処理学会論文誌, Vol.43 No.12, pp.4034-4041. (2002)

    • 「CPUの前にコンパイラ」に同意.

      いくらセキュアなCPUアーキテクチャを開発しても
      数千万台現存するであろうx86ベースPCの脆弱性解消
      には何の役にも立たないし.

      ・・・コンパイラレベルでセキュリティ問題を解決した
      OSが登場するとWindows支配がひっくり返るのかどう
      かはよくわからないが.
      親コメント
  • Forth (スコア:3, すばらしい洞察)

    by Motohiko (15295) on 2003年10月06日 2時34分 (#409289) ホームページ

    真っ先にForthが思い浮かびましたが。

    たしかスタックが2本あって、片方がリターンスタックと言ったような……

    • by prajna (18168) on 2003年10月06日 2時53分 (#409291)
      RedHatが、不正コードを実行しにくくするカーネル機構『Exec Shield』というものを開発していますが、これを思い浮かべます。
      http://people.redhat.com/mingo/exec-shield/
      原理は、実行コード領域を、下位メモリの「0x00000000~0x0100FFFF」にすることで、アドレス4バイトのどこかに必ず、`00'が入るため、文字列の終端となり、それ以上の不正コードを文字列としてスタックに積むことが難しくなる、ということです。
      “ASCII-armored Area”と呼ばれるそうですが、なんだかなぁ…
      そもそも、データ領域とコード領域をCPUレベルで区別し、データ領域のインストラクションの実行を防ぐは難しいのでしょうか? また、他にCPUレベルでスタックオーバーフロー特有のセキュリティホールを防御する研究というのはないのでしょうか?
      親コメント
      • by Anonymous Coward on 2003年10月06日 3時01分 (#409293)
        そもそも、データ領域とコード領域をCPUレベルで区別し、データ領域のインストラクションの実行を防ぐは難しいのでしょうか?
        Princeton/Harvard architectureの違いくらいは知ってるんでしょうね?
        親コメント
        • by SteppingWind (2654) on 2003年10月06日 10時06分 (#409362)

          > Princeton/Harvard architectureの違いくらいは知ってるんでしょうね?

          これだけだと何なんで, 参考になりそうなページ [yamanashi.ac.jp]を紹介しておきます. 多くのページではハーバードアーキテクチャをキャッシュ構成の話としてのみ扱っていますが, データとコードをバス上で分離するというアーキテクチャは特に組み込みCPUで多用されています. これによりコード部分はROM, データ部分はRAMに置くという経済的かつ安全な構成が簡単に実現できるわけです. 同様の機構は例えばMC68000の様な汎用CPUでも実装されていて, この場合プロセッサステータス信号でユーザモード/スーパバイザモード, コード/データの区分をつけられるようになっています.(普通のパソコンで使っている例はありませんが)

          親コメント
      • by Anonymous Coward on 2003年10月06日 3時49分 (#409302)
        80286以降にはセグメントでコード領域とデータ領域を分ける機構が備わってます。
        (386以降なら64Kの壁もない)
        だからスタックを書き換えてデータ領域にジャンプしても実行しないようには出来るはず。
        だけどその能力をOSを使ってるかはまた別の話。
        親コメント
      • CPUによっては (スコア:1, 参考になる)

        by Anonymous Coward on 2003年10月06日 10時16分 (#409371)
        ページ単位でリード権限と実行権限が独立して設定できるものも
        あります。この場合、バッファーオーバーフロー攻撃でスタック
        上に実行コードを置いてもアクセス違反で実行できません。
        IA32ではセグメントにはリード権限と実行権限が独立に設定可能
        なのですが、ページではリード・ライト権限しか設定できないの
        でこの方法で防御するのは面倒です。
        # それでも使ってる実装もLinuxのバリエーションであったはず
        親コメント
      • exec-shield より前にもいくつかハードウェアの機能を使った防御技術は提案されているよ。 例えば PaX プロジェクトとか。 http://pageexec.virtualave.net/

        ここだとセグメントを使った方法とページのフラグを使った方法が書いてある。セグメントはいわゆるコードセグメントとデータセグメントに分けて使う方式。フラグの方はスーパバイザフラグを流用して、non-exec のページに Supervisor フラグを立てておくと、アクセス時に fault が起きるのでそこでチェックする方式。詳細は上の URL からたどって読んでみてください。
        親コメント
  • たとえばCでいうところのsetjump()/longjump()みたいな、 関数の引数・返値が積まれるのと共通の スタック上にリターンアドレスがあることを前提にした 書き方がされることがあるプログラムは ユーザランドですら既にあるのをどう対処するか 困りそうじゃないですか。

    8087エミュレータやOSの未定義命令トラップをはじめとする 例外ハンドラのように、 スタック上のリターンアドレスを間接アドレシングのために プログラムで明示的に拾って使うプログラムでは以下同様

    結局、スタック上のリターンアドレスをデータとして叩く プログラムは結構あるので、 リターンアドレスの空間を分けちゃうとなると、 そちらを明示的に指定するインタフェース(=命令拡張)が 必要になるじゃない。 スタックに詰まれる物の数が変わるとオフセットだって変わるし。

    あ! オフセットが変わるといえば、 関数呼び出し時って、返値をレジスタ渡ししない場合は

    • 引数を積んで
    • 返値の格納スペースを積んで
    • callでリターンアドレスを積んで
    • 関数の作業領域としてスタックフレームを確保
    って順番だから、 少なくとも、引数や返値といった呼び出し元のスタックフレームへ アクセスする際はリターンアドレスを挟んだ向こう側の オフセットになるわけですから、 リターンアドレスとして積まれるものを よそへ持っていかれてしまうと 一発で互換性なくなりますね。 まあ、数合わせだけならそれこそデータ用のスタックに ダミーを積むような「慎重な実装」をすればいいのか。

    あと、IA32に限りませんが、 レジスタを増やすことはタスク構造体が膨らむことに 直結するわけで、OS自体のバイナリ互換性は損なわれますよね。

    結局、根本的なところで、リターンアドレスを扱う命令は call/return命令だけで収まるはずがないので、 ぱっと思いつくだけでも これだけ問題山積みなような気がする。 どう「慎重に実装」すればこの辺を透過に扱えるんだか 実施例に記載して欲しいな。

  • by Anonymous Coward on 2003年10月06日 3時28分 (#409298)
    ではないでしょうか。

    少なくとも、スタックをアドレスの下位から上位にとれば、文字列データが溢れても復帰番地を壊すことはありません。言語仕様からスタックをどの向きにとるかは、決められません。

    あるいは、スタックをリンクトリストとして構成すれば、文字列データが溢れた場合の壊れる場所が一定にならない。IBMのOS360では、セーブエリア=復帰用スタックはポインタでつながれたリストで構成されていました。

    以上、古代の計算機科学学習者の繰り言です。

    # なぜ人はいまだにCを使うのでしょうか。
  • よーし、じゃあ私は (スコア:2, おもしろおかしい)

    by Anonymous Coward on 2003年10月06日 4時17分 (#409306)
    IA-32をページ単位で実行可能/不可能を指定できるように拡張して
    特許取るぞ!
  • 80386系列の場合、せっかく保護モードがあるのですから、
    すべての関数呼び出しにおいて、保護モードを使うという
    方法では駄目なのでしょうか。near callではなくて、
    すべての関数呼び出しを、セグメントディスクリプタの
    切り替えを伴うfar call(でよかったんでしたっけ)にして、
    コード、データ、スタック等について細かくセグメント
    わけして保護を行なうという。

    オーバヘッドが猛烈にかかることは分かりますが。

    #昔メインフレームでそんなことしてたので。
  • リプレースの経済性 (スコア:2, すばらしい洞察)

    by Futaro (2025) on 2003年10月06日 14時03分 (#409467) ホームページ 日記
    こういった「後でおこなう対策」にとって肝要なことは、いままでのバイナリをそのまま使える、とか、せめて、ソースコードをコンパイルしただけで大丈夫、というような「後付け対策作業の経済性」だと思います。特にソフトウエアでできることはソフトウエアでしておかないと、経済的にまずいんじゃないかな?

    今回の方法だと、実際のセキュアなシステムにするための作業は、(1)ハードウエア取り換え、(2)ライブラリ取り換え、(3)場合によったらコンパイラなどのツール取り換え、etc..などが必要になりますが、ソフトウエアだけであれば、(1)の作業がなくなるので、単純に言って、経済性がよりすぐれたものになるかと思います。

    せっかくハードを取り換えるのでしたら、ハードの取り換え「だけ」で済むようなものでないとうけいれられにくいのではないかな?
    • by saitoh (10803) on 2003年10月06日 17時08分 (#409575)
      どうせCPUを変えるのだったら、実行可/不可属性をページ保護に持たせたMMUに 置き換えたi386系CPUを作った方が楽じゃないの? これなら、カーネルだけの書き換えで済むような。
      親コメント
    • by yasunori (1536) on 2003年10月06日 22時41分 (#409745)
      経済性ってコストのことだとしたら必ずソフトの方が安いとはかぎらない気がします。

      たとえば、コンパイラを変えたらコンパイラ自体の動作検証に加え、ソフトウェアを全部再コンパイルして各ソフトウェアの動作検証をしなければならなくなる(動かなくなるソフトの対応も含む)ので、全部ソフトでやる方が常にコストが安いとは言えないと考えています。ありがちですが適用領域を見て選ばなければならないと思います。

      もちろん、ハードやソフトの色々な対応が選択肢として提供されていることはとても重要なことなので、ソフトだけで OK とかハードだけで OK とかの風潮になるのは怖いですね。
      親コメント
  • by bero (5057) on 2003年10月06日 21時24分 (#409700) 日記
    ちょっと前に見たけど、なんだかよくわからない。

    「慎重に実装することにより、従来のIA32に対して100%互換性を維持できる。過去のソフトウェア資産を損なうことなくセキュリティを向上できる。」
    って可能だろうか?「慎重」なところが特許か?

    私見では、レジスタ増やしたらsetjmp/longjmp, thread, signal, kernelその他、context switchするところの変更や再コンパイルは避けられないと思う。
    で、再コンパイルするなら、適当なレジスタをデータスタックとして使うコードを吐くようなコンパイラを作ればいい話で、CPU変更の必要は無くなる。

    context switchを使ってないか、共有ライブラリ等で差し替え可能かつバイナリに埋め込まれたcontext保存領域(例えばjmp_buf)のサイズが変わらないのなら、userlandのバイナリ実行ファイルの互換性は保たれるかもしれない。

    とりあえず、いきなりCPU変更とか言い出す前にエミュレータかなにかで実用性を検証してほしいところだ。
  • インデックスレジスタで代用できるように思えるのだけど. 現に多くの RISC 系 CPU では,CPU アーキテクチャのレベルではスタックと言う概念は無くて,コンパイラ側の方で汎用レジスタのどれか1つを「こいつはスタックポインタとして使うぞ」と勝手に決めて使っているだけだし.

    というわけで,コンパイラ(と OS)の実装レベルで,例えば EAX ~ EDX のどれかを「データ用のスタックポインタ」として使うことにしてしまえば,CPU コアの変更はいらんと思うんだけど,どうなんでしょ. x86 では命令セットの関係で,こういうのは難しいのかなぁ.
    # まぁ,ただでさえ少ない汎用レジスタを更に減らす,というのもちと悲しい気もするが.

    • by saitoh (10803) on 2003年10月06日 11時51分 (#409414)
      コンパイラと(とOS)の実装レベルで実現すると、既存の プログラムとの(バイナリ)互換性がなくなりますね。 どうもこの特許のミソは、既存のアプリケーショバイナリを そのまま実行できるとこことみたい。 多分、OSは一部書き換えないといけないだろうけれど。
      親コメント
  • by suezo (2881) on 2003年10月06日 10時32分 (#409380) 日記
    CPUメーカーはわざわざ特許料まで払って実装するだろうか?
    まぁ、10年先のことはわからないので、なんともいえないですけどね
typodupeerror

弘法筆を選ばず、アレゲはキーボードを選ぶ -- アレゲ研究家

読み込み中...