(57)【要約】【課題】  canary値の破壊検知に基づく従来の手法では、当該値を外部から推測できる場合に、防御機能が減殺される。別の従来手法では、スタック領域のみを保護対象としているため、スタック領域外のデータを対象とした攻撃に対しては防御できなかった。【解決手段】  配列を含む変数をスタック外の、書き込み不能領域に隣接した領域に配置する。また、スタック外の重要データに関しては、アドレスとその格納値のマッピングテーブルを用い、コードポインタなど不正な制御奪取の原因となる変数について、定義点で登録した値と使用点で確認した値が等しいか否かを確認するコードを生成することにより、不正な制御の奪取を検出する。  バッファオーバフローを利用した攻撃に対して、外部からの値の推測や、スタック上に割り当てられていないデータ領域の破壊による不正な制御の奪取を抑止することが可能となる。【選択図】  図１
2006185233.tif 000002
【特許請求の範囲】
【請求項１】
ソースプログラム中で定義された手続きに対して、当該手続き中で宣言された、配列変数、配列を含む複合データ型の変数その他の変数群を収集し、
収集された当該変数群を、動的に確保されるメモリ領域であって、書き込み不能メモリ領域の低位メモリアドレスに隣接するものに配置し、
前記収集前の前記変数群を参照する代わりに、前記配置後のメモリ領域を参照する変換済プログラムへ変換することを特徴とする、セキュリティ向上のためのプログラム変換方法。
【請求項２】
請求項１記載のセキュリティ向上のためのプログラム変換方法において、前記動的に確保されるメモリ領域の確保の仕方が、
予め、前記動的に確保されるメモリ領域の候補を確保し、
予め、前記確保したメモリ領域の候補を特定するテーブルを用意し、
前記メモリ領域の候補のうち未使用のものを前記テーブルに保持し、
プログラム中で定義された手続きである関数の入口で、未使用のメモリ領域の候補が前記テーブルに存在すれば、それを利用し、
前記関数の出口で、前記利用した、未使用のメモリ領域の候補を、未使用のものとして、前記テーブルに保持することである、セキュリティ向上のためのプログラム変換方法。
【請求項３】
変数の格納アドレスとその値のマッピングを行うテーブルを用意し、
ソースプログラム中で定義され、予め定められた変数について、その変数の値の定義点におけるアドレスとその値を前記テーブルに格納し、
前記変数の使用点におけるアドレスとその値を、前記テーブルに格納された当該変数のアドレスとその値と比較し、
比較の結果が異なる場合に、プログラムの実行に不正が生じたとする変換済プログラムへ変換することを特徴とする、セキュリティ向上のためのプログラム変換方法。
【請求項４】
請求項３記載のセキュリティ向上のためのプログラム変換方法において、
前記予め定められた変数が、間接関数呼び出しに用いられる関数ポインタ、又は、大域的な分岐に用いられるデータ構造である、セキュリティ向上のためのプログラム変換方法。
【請求項５】
ソースプログラムを入力し、変換済プログラムを出力するコンパイラプログラムであって、構文解析処理機能、シャドウスタック変換処理機能、重要変数値保護処理機能及びコード生成処理機能を有するものにおいて、
前記シャドウスタック変換処理機能が、請求項１記載のプログラム変換方法を使用したことを特徴とするコンパイラプログラム。
【請求項６】
ソースプログラムを入力し、変換済プログラムを出力するコンパイラプログラムであって、構文解析処理機能、シャドウスタック変換処理機能、重要変数値保護処理機能及びコード生成処理機能を有するものにおいて、
前記重要変数値保護処理機能が、請求項３記載のプログラム変換方法を使用したことを特徴とするコンパイラプログラム。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、外部からの不正操作・送信によって、プログラムが不具合を生じることを抑止する技術に関する。
【背景技術】
【０００２】
コンピュータウィルスやワームによる被害は、世界的規模で大きな社会的問題となっている。これら不正な動作を行うウイルス等の多くは、被害を受けるプログラムが有する欠陥(脆弱性)を利用し、プログラムの動作環境であるシステムの制御を不正に奪う。
セキュリティに関して配慮されていないプログラム制御下のシステムでは、バッファへの書き込みを行うに際して、書き込むべきデータと、その格納領域の領域長の検査が十分でない場合がある。このようなプログラム制御下では、ウイルス等は、バッファ周辺のデータ領域を容易に破壊し得る。
例えば図２に示す、ウイルス等のバッファオーバフロー攻撃は、外部からの入力に使用されるバッファに対して、システムが実際に確保した格納領域よりも大きなデータを書き込むことにより、バッファ周辺のデータ領域を破壊して、スタックフレーム上に確保された手続きの戻りアドレスなどを書き換えて、不正にプログラムの制御を奪う攻撃手法である。
【０００３】
図２(a)で定義される関数foo(204)では、10バイトの配列buf(205)をスタックフレーム上に確保し、関数getenvの返却文字列をbufに書き込む処理206を行なう。この時の典型的な実行時スタックの状態を図２(b)に示す。ここで、getenvの返却する文字列長には制限が無いため、文字列長が10バイトより大きな場合はbufに後続する領域が破壊されることとなる。
図２(b)に示すように、スタック上のbufより下位のアドレスには関数fooのリターンアドレスが存在する。ウイルス等が、バッファオーバフロー攻撃によってプログラムの制御を奪う方法の１つは、このような領域長を越えるデータをフレーム上の領域に書き込むことにより、関数リターンアドレスを書き換えるというものである。この様子を図2(c)に示す。
ウイルス等による バッファオーバフローにより、フレーム上に攻撃用コード列が書き込まれると共に、関数fooのリターンアドレスが攻撃用コード列を指すように書き換えられる。この結果、関数fooから呼び出し元に戻る際に、ウイルス等の意図した攻撃用コードへ分岐して、システムの制御が奪われる結果となる。
ここで示したような、リターンアドレスの書き換えによる攻撃以外に、バッファの後方に保存された関数ポインタの書き換え、フレームポインタの書き換えなどによっても、ウイルス等は、プログラムによるシステムの制御を奪うことが可能である。
【０００４】
バッファオーバフローによる攻撃を防御するための手法については、これまでにさまざまな手法が提案されている。
StackGuard (非特許文献1) では、図３(a)に示すように、関数をコンパイルする際に、canary値と呼ばれる特殊な値をフレームのデータ領域の最後に配置する。攻撃によってリターンアドレスの格納域が破壊される場合、バッファとリターンアドレスの格納域の間に配置されるcanary値も同時に破壊される。従って、関数呼び出しから戻る点でcanary値の破壊の有無を検査することにより、攻撃の有無を確認できる。canary値としては、外部からの推測が困難な乱数値などを利用する。
StackShield (非特許文献2) は、スタックフレームとは別の領域にリターンアドレススタックを確保する(図３(b))。実行する関数の入口では、リターンアドレススタックへ、戻りアドレスを退避し、関数から呼び元へ戻る際にはリターンアドレススタックから取り出したアドレスを、戻りアドレスとして使用する。この結果、スタック上の戻りアドレスの破壊によって不正に制御が奪われることはなくなる。また、StackShieldでは、関数ポインタの指示先がコード領域内であるかどうかを確認することによって限定的な関数ポインタの保護も行なっている。
【０００５】
SSP (非特許文献3)は、スタック上に配置されるデータのうち、配列が高位アドレス、その他のデータが低位アドレスに配置されるようStackGuardの方式を改良したものである(図３(c))。この結果、バッファオーバフローによってパラメータを除く非配列変数を破壊する事がなくなる。
【０００６】
【非特許文献１】C.Cowan他, StackGuard: Automatic Adaptive Detection and Prevention of Buffer-Overflow Attacks, In Proceedings of the 7th USENIX Security Conference, 1997.
【非特許文献２】Vendicator, Stack Shield - A "stack smashing" technique protection tool for Linux, http://www.angelfire.com/sk/stackshield/info.html, 2000.
【非特許文献３】H.Etoh, GCC extensions for protecting applications from stack-smashing attacks, http://www.trl.ibm.com/projects/security/ssp/, 2004.
【発明の開示】
【発明が解決しようとする課題】
【０００７】
StackGuardやSSPなど、canary値の破壊検査に基づいた防御手法は、canary値が予測不能であることを前提としている。このため何らかの手段によりcanary値が推定可能であれば、保護を無効とし得る。
従来の防御手法は、基本的に、スタック上に割り当てられるデータを対象とする保護である。よって、これらの手法は、スタック以外の領域に確保された関数ポインタを対象とする破壊によって制御を奪う、ウイルス等の攻撃には対処できない。
【０００８】
また別のウイルス等は、スタック上にある、バッファと関数ポインタを共に含むような複合型のデータを攻撃対象とする。この場合には、ウイルス等は、canary値を破壊することなく関数ポインタを破壊できる。
例えば、図２(a)の例では、10バイトの配列array(201)と、関数ポインタfunc(202)を含むような構造体S(203)が定義されている。ここで、文206のbufの代わりに、S.arrayがstrcpyの第一引数として用いられた場合を考える。この場合、S.arrayへ余分なデータを書き込むことにより関数ポインタS.funcを破壊することができる。S.funcは間接関数呼び出しの際に利用されるため、その呼出し点において不正に制御を取得することが可能となる。S.arrayとS.funcの間にはcanary値は存在しないため、このようなケースでは従来の防御手法は有効でない。
【０００９】
本発明では、従来の防御手法において、(a)スタック上のデータの保護が、canary値の予測によって無効化され得ること、(b) スタック外のデータや、複合型データの内部のデータが、従来手法によっては保護できないこと等、を解決することを目的としている。
【課題を解決するための手段】
【００１０】
上記(a)の課題を解決するため、スタック上の配列データをスタックとは異なる領域に配置し、ページ保護を併用する。この結果、canary値の推測による、スタック上のデータ破壊の可能性を排除できる。
上記(b)の課題を解決するため、関数ポインタその他スタック外に配置され得るデータに関しては、アドレスとその値のマッピング表を管理し、値が不正に書き換えられていないことを確認することによりデータの保護を実現する。
【発明の効果】
【００１１】
従来技術で保護されなかった、ウイルス等によるバッファオーバフローを用いた攻撃を検知し、高いセキュリティを実現することができる。
【発明を実施するための最良の形態】
【００１２】
図４に、本発明が対象とするシステムの構成例を示す。
このシステムは、CPU401、メモリ402、外部記憶403から構成される。本発明を適用したコンパイラプログラムは、外部記憶403からメモリ402に読み出されて実行される。その実行時には、外部記憶403からソースコードを読み出し、生成したコードを外部記憶403へ書き戻す。
【００１３】
図1に本発明を適用したコンパイラプログラムの例を示す。
本コンパイラプログラム101は、ソースプログラム106を入力とし、セキュリティを強化したプログラム108を生成する。コンパイラの内部処理は、まず構文解析処理102によってソースプログラム106を入力し、中間語107を生成する。生成した中間語107は、本発明の特徴的な処理の1つである、シャドウスタック変換処理103に入力され、中間語107にスタック上のデータを保護する処理を追加する。
次に、重要変数値保護処理104により、スタック外に確保される、重要データを保護する処理を中間語107に追加する。最後に、コード生成処理105によって、中間語107を変換済プログラム108に変換する。
【００１４】
＜第１の特徴的処理＞
まず、本発明の特徴的な処理の1つであるシャドウスタック変換処理について説明する。シャドウスタック変換では、バッファオーバフロー攻撃の対象となる、配列を含む変数をスタック外に割当てるようにプログラムを変換する。
また、スタック外に割り当てた配列変数の後部に隣接して、書き込み不能なメモリ領域を配置することにより、バッファに後続する領域の破壊を検出することを可能とする。
【００１５】
図５に、シャドウスタック変換処理103（図１）を適用した場合のフレームの配置を示す。
従来のフレーム構成図２(b)のフレーム構成と異なり、変換後のフレーム構成では、配列領域505がスタック外の領域に配置される。ここで、配列領域505は、書き込み不能領域506に隣接するように配置される。スタック外に確保した配列領域505は、フレーム上の変数「_shadow_」502から指示する。
多くのオペレーティングシステムやプロセッサは、メモリ領域を書き込み不能とできる単位は、4Kバイトその他一定の単位またはその倍数である。このため、未使用領域504を配列領域505の前に置いてもよい。
シャドウスタック変換によって、従来のコンパイラ生成コードではスタック上に確保されていたバッファ変数が、スタック外に確保されることとなる。また、バッファオーバフローによって配列領域505を超えて書き込みが行われた場合は、書き込み対象アドレスが書き込み不能領域506へ到達し、不正メモリアクセスによる例外が発生するため、不正処理を検出することができる。
この結果、スタック上に確保された局所変数等501やリターンアドレス503は、バッファオーバフローによって破壊されることはなくなる。
【００１６】
図９に、シャドウスタック変換処理103の処理フローを示す。
同変換処理103では、処理901によって処理を開始し、処理902において、変数Fにプログラム中で定義された手続きの集合を求める。次に、処理903において変数Fが空集合か否かを確認する。Fが空集合の場合は、処理対象となる手続きが存在しないため、処理908に制御を移して処理を終了する。
【００１７】
処理対象となる手続きが存在する場合は、処理904においてFから手続きを1つ取り出して変数fに格納する。求めた手続きfに対して、f中で宣言された変数のうち、配列、又は、配列を含む複合データ型の変数の集合を、変数Aに求める。また、シャドウスタックへの割り当て対象とする変数の集合Eを空集合に初期化する。
判定処理905では、配列変数の集合Aが空集合か否かを確認する。空集合でなければ処理906に進む。処理906では、配列変数の集合Aから変数を1つ取り出し、変数aに格納する。次に、変数aの宣言を手続きfから削除し、変数Eに変数aを追加する。続いて処理905に制御を移して、次の変数の処理を行う。処理905において、集合Aが空集合であった場合、処理907に制御を移す。
【００１８】
処理907では、変数集合E内の配列変数をスタック外に割り当て、領域の先頭を変数「_shadow_」で指示する処理を、手続きfの先頭に追加し、割当てた領域を開放する処理を、手続きfの末尾に追加する。
また、変数集合E内の変数eについて、手続きfの参照を「_shadow_->e」で置き換える。処理907が完了すると、処理903に制御を移し、次の手続きの処理を行う。
ここで、手続きの呼び出し毎に、シャドウスタックの割り当てを行うと、高いオーバーヘッドを必要とする。このオーバーヘッド時間を減少させるためには、例えば、領域サイズをページサイズの倍数として、確保した領域サイズを基準として、領域をグループ化して未使用領域をテーブルに保存しておく。そして、領域の確保の際に未使用領域が存在すればそれを再利用し、領域の開放の際にはテーブルに登録するようにすればよい。
【００１９】
図１１に、未使用シャドウスタックの管理テーブルの例を示す。
管理テーブル1101は、領域サイズ毎のエントリから構成されている。例えば、領域サイズ1ページのシャドウスタック1102、1103と、領域サイズ2ページのシャドウスタック1104がテーブルに登録されている。登録すべきエントリのインデックスは、必要とする領域長をN、ページサイズをPとすると、「CEIL (N/P) + 1」となる。なお、ここで、CEIL(x)はx以上の最小の整数を求める関数であるものとする。
【００２０】
図６(a)に示すプログラムを対象として、シャドウスタック変換を適用した結果を図６(b)に示す。
図６(a)のプログラムでは、処理対象の手続きはfooのみであるので、処理902（図９）において「F={foo}」となる。判定処理903ではFが空集合でないので、処理904へ進む。処理904では、手続きfoo内で宣言された配列変数はbufのみであるので、「f=foo」、「A={buf}」となる。続く判定処理905 ではAが空集合でないので、処理906へ進み、「a=buf」、「A={}」、「E={buf}」とする。また、変数bufの宣言601を手続きfooから削除する。
判定処理905では、Aが空集合であるので、処理907へ制御を移す。処理907では、E中の変数、すなわち、bufをスタック外に割当てる処理603、604を手続きfooの先頭に挿入する。また、割当てた領域の削除処理606を手続きfooの最後に挿入する。続いて、プログラム中の変数bufの参照602を、「_shadow_->buf」605に置き換える。
【００２１】
＜第２の特徴的処理＞
次に、本発明の2つ目の特徴である、重要変数値の保護処理について説明する。
重要変数値の保護処理では、セキュリティ攻撃の対象となる重要な変数について、その値が不正に破壊されていないかを確認する。そのために、変数アドレスとその値のマッピングを行うためのテーブルを用意し、変数の値の定義点において、アドレスとその値をテーブルに格納し、使用点においてその変数の値が、前記テーブルに登録した値と異なっていないかを確認する。
異なっている場合、不正な操作によって値が破壊された可能性がある。よって、ユーザに報告をしてプログラムを停止するなどの措置を採る。
ここで、保護対象とする変数としては、間接関数呼び出しに利用される関数ポインタ値、大域的な分岐に利用されるjmpbufデータ構造などが挙げられる。
【００２２】
重要変数値の保護処理の処理フローを図１０に示す。
これは、処理1001で処理を開始し、処理1002で変数Sにプログラム中の文の集合を求める。次に、判定処理1003で文集合Sが空集合か否かを確認する。空集合の場合は、処理対象の文が存在しないため、処理1012に制御を移して処理を完了する。
処理対象の文が存在する場合は、処理1004に制御を移し、Sから文を1つ取り出し変数sに格納する。
【００２３】
処理1005で文s中に出現する変数の集合を変数Vに求める。判定処理1006で変数集合Vが空集合か否かを確認する。空集合の場合は、処理対象の変数が存在しないため、処理1003に制御を移して次の文を処理する。
処理1006において、処理対象の変数が存在する場合、処理1007においてVから変数を1つ取り出し変数vに格納する。次に、処理1008において変数vの出現位置が使用点であるか否かを確認する。
使用点である場合は、文sの前にvの値がマッピングテーブルの値と異なるか否かを検査するコードを挿入し、処理1006に制御を移して次の変数を処理する。使用点でない場合は、処理1010においてvが定義点であるか否かを確認する。
定義点でなければ処理1006に制御を移して次の変数を処理する。定義点である場合は、vのアドレスと値の対応関係をテーブルに登録する処理を文sの後に挿入し、処理1006に制御を移して次の変数を処理する。
【００２４】
図７(a)に示すプログラムを用いて、重要変数値の保護処理の適用例を示す。
処理1002(図１０)では、プログラム中の文の集合を変数Sに求める。ここでは、「S={701, 702}」とする。処理1003では、Sが空集合でないので、処理1004に制御を移し、「s=701」、「S={702}」とする。
処理1005において、文701（図７）に出現する重要変数の集合を変数Vに求める。ここでは、「V={func}」とする。処理1006では、Vが空集合でないため処理1007に制御を移し、「v=func」、「V={}」とする。処理1008、および、処理1010でfuncは定義点であるので処理1011に制御を移し、変数funcのアドレスとその値の対応関係をテーブルに登録する処理703を、文701の後に挿入する。
次に、処理1006に制御を移動する。ここで、Vが空集合となるため、処理1003へ制御を移動して次の文の処理を行う。同様に、文702の変数funcを処理すると、文702における変数funcは使用点であるため、文702の前に変数funcの値をチェックするコード704を挿入する。
【００２５】
図８に、変数のアドレスとその値の対応を登録するテーブルの例を示す。
テーブルはアドレス欄801とその値欄802から構成され、図７(b)で挿入された値の登録処理703によって、重要変数に関する値とアドレスの対応関係が登録され、値の確認処理704によってテーブル中の値が参照される。
変換後のコード(図７(b))において、文701と文702の間で変数funcが不正に変更された場合、文702で制御が不正に移動する前にチェック処理704で不正が検出される。
【産業上の利用可能性】
【００２６】
本発明は、プログラムのセキュリティ向上のために利用できる。
【図面の簡単な説明】
【００２７】
【図１】本発明を適用したコンパイラの例
【図２】バッファオーバフロー攻撃の例
【図３】従来のバッファオーバフロー攻撃の例
【図４】本発明を実施する計算機システムの例
【図５】シャドウスタックを利用したフレームの例
【図６】シャドウスタックによるプログラムの変換例
【図７】重要変数保護によるプログラムの変換例
【図８】重要変数保護で利用するテーブルの例
【図９】シャドウスタック変換処理の処理フロー
【図１０】重要変数値保護処理の処理フロー
【図１１】未使用シャドウスタックの管理テーブルの例
【符号の説明】
【００２８】
101…コンパイラ
102…構文解析処理
103…シャドウスタック変換処理
104…重要変数値保護処理
105…コード生成処理
106…ソースプログラム
107…中間語
108…変換済プログラム
【図１】
2006185233.tif 000003
【図２】
2006185233.tif 000004
【図３】
2006185233.tif 000005
【図４】
2006185233.tif 000006
【図５】
2006185233.tif 000007
【図６】
2006185233.tif 000008
【図７】
2006185233.tif 000009
【図８】
2006185233.tif 000010
【図９】
2006185233.tif 000011
【図１０】
2006185233.tif 000012
【図１１】
2006185233.tif 000013