JP2007004647A - 不正コードの実行を防ぐプログラムの生成方法、及び、そのプログラム - Google Patents

不正コードの実行を防ぐプログラムの生成方法、及び、そのプログラム Download PDF

Info

Publication number
JP2007004647A
JP2007004647A JP2005185921A JP2005185921A JP2007004647A JP 2007004647 A JP2007004647 A JP 2007004647A JP 2005185921 A JP2005185921 A JP 2005185921A JP 2005185921 A JP2005185921 A JP 2005185921A JP 2007004647 A JP2007004647 A JP 2007004647A
Authority
JP
Japan
Prior art keywords
program
function
variable
code
buffer
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
JP2005185921A
Other languages
English (en)
Inventor
志泰 ▲高▼畠
Yukiyasu Takahata
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Hitachi Ltd
Original Assignee
Hitachi Ltd
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Hitachi Ltd filed Critical Hitachi Ltd
Priority to JP2005185921A priority Critical patent/JP2007004647A/ja
Publication of JP2007004647A publication Critical patent/JP2007004647A/ja
Pending legal-status Critical Current

Links

Images

Abstract

【課題】バッファーオーバーフローによる不正コードの実行を防ぐ。
【解決手段】プログラムを構成する関数からコールグラフを作り102、コールグラフ中にループ(再帰呼び出し)があることを検出し103、そのループ中に含まれる関数には従来方法によるセキュリティー対策を施し108、そのループに含まれない関数は自動変数をグローバル変数又は静的変数へ変換110して実行する。
【選択図】図1

Description

本発明は、不正を働くプログラムから計算機システムを防御する技術に係り、特に、バッファーオーバーフローを利用した不正コードの実行を防ぐ、プログラムの生成技術に関する。
サーバプログラムには、C言語やC++言語で記述されたプログラムが多数あり、これらの言語では、配列の宣言範囲を超えないにようにプログラムを記述する必要がある。しかし、プログラムのバグにより、宣言範囲を超える場合がある。
悪意のある者、または、悪意のある者が作成したプログラム(以降、両方をまとめて悪意者とする)が、このようなプログラムに存在するバグを利用し、本来のプログラム動作とは異なる動作をさせ、不正に計算機システムを利用するという、セキュリティーの問題がある。かかる問題を解決するには、いくつか方法があるが、不正なコードの実行を検出し回避することと、検出時のオーバーヘッドを小さくすることが重要である。
不正な動作は、プログラム中の関数内にある自動変数の配列(バッファー)のオーバーフローを利用したものが多い。ここで、「オーバーフローを利用する」とは、配列変数の宣言における添え字の範囲を超えた部分への書き込みをいう。
通常、関数内にある自動変数は、スタックと呼ばれる領域に置かれる。スタックには、関数呼び出しのための、引数やスタックのフレームポインタ、関数の戻りアドレスその他所定の情報が置かれる。悪意者が、バッファーのオーバーフローにより範囲外の部分へ、何らかのコードその他不正な情報を書き込み、さらに、スタック上の関数の戻りアドレスを不正なコードが存在するアドレスへ書き換えた場合を考える。このとき、関数が呼び出し元へ戻る際に、この書き換えられた不正なコードのアドレスへ移動し、以後、不正なコードが実行され、悪意者の意図する不正動作が行われる。
図6にバッファーオーバーフローの具体例を示す。
プログラム701は、2行目で配列変数bufferを宣言している。この配列変数bufferは、関数subの実行時にスタック上に置かれる自動変数である。この関数subを呼び出したときのスタックの状態を、スタック702に示す。関数subを呼び出した手続きへ戻るためのアドレス(ret. addr.)、スタックのフレームポインタ(sfp)、自動変数の配列変数buffer[0-3]、… buffer[124-127] が配置されている。
プログラム701の3行目に従い、関数subが関数set_bufferを呼び出し、関数set_buffer内で配列変数bufferへの書き込みが行なわれるときに、配列変数bufferの添え字の値が128以上になった場合には、配列変数bufferが宣言した範囲以外の部分へアクセスすることができることとなる(バッファーオーバーフロー)。これを利用して悪意者は、本来のプログラムの関数の戻りアドレス、スタックのフレームポインタその他の情報を書き換えることができ、また、不正なコードを書き込むこともできるようになる。このようにして、不正なコードの実行が可能となる。このような問題を解決するために、以下の方法がある。
非特許文献1のStackGuardは、スタック上にある戻りアドレスが格納されている場所と、バッファーが格納されている場所の間に、書き換えを検出するための値を入れる、canaryと呼ばれる場所を設ける。このcanaryへ不規則な値を入れておく。バッファーのオーバーフローによる戻りアドレスの書き換えが起きると、canaryの値も書き換えられるため、関数が呼び出し元へ戻る直前に、この値が書き換えられていることをチェックすることで、オーバーフローを検出することができ、不正なコードへの移動を回避できる。
図7に非特許文献1を適用した例を示す。
プログラム701(図6)は、プログラム801のように変換される。プログラム801の2行目で、書き換え動作を検出するための値を入れる場所であるcanaryを宣言する。この環境下で、関数subが呼び出されたときのスタックの状態をスタック802に示す。スタック802に示すようにcanaryがスタックのフレームポインタ(sfp)と配列変数bufferの間に置かれる。
プログラム801の4行目で、関数subの本来の処理を行なう前にcanaryへ不規則な値を代入し、プログラム801の6行目で、関数subの本来の処理が終わった後にcanaryの値をチェックする。配列変数bufferのオーバーフローが起きると、canaryの値も書き換えられるので、canaryの値が4行目で代入した値と異なる値が入る。そのため、canaryの値をチェックすることでバッファーのオーバーフローを検出することができる。バッファーのオーバーフローを検出したら、プログラム801の7行目でオーバーフローが起きたときの処理を行なう。
非特許文献2の方法は、スタックを制御用とデータ用に分け、制御用のスタックに戻りアドレスやスタックのフレームポインタを置き、関数呼び出しの引数や関数内の自動変数はスタックに配置することで、プログラムの不正な動作を防ぐものである。これによりスタック上にあるバッファーの範囲外へデータを書き込んでも、関数の戻りアドレスが制御用のスタック上にあるために書き換えられず、不正なコードへの移動を回避できる。
非特許文献3のLibsafeは、範囲チェックを行なっていない危険なライブラリを、範囲チェックを行なう安全なライブラリへ置き換えることにより、オーバーフローを検出する方法である。これにより、不正なコードの書き込みや、戻りアドレスの書き換えを行なえないようにすることができる。
Crispin Cowan, Calton Pu, Dave Maier, Heather Hinton, "StackGuard: Automatic Adaptive Detection and Prevention of Buffer-Overflow Attacks", Proc. 7th USENIX Security Conference, (1998). Jun Xu, Zbigniew Kalbarczyk, Sanjay Patel and Ravishankar K. Iyer, "Architecture Support for Defending Against Buffer Overflow Attacks", EASY-2 Workshop, (2002). Timothy K. Tsai, Navjot Singh, "Libsafe: Protecting Critical Elements of Stacks", White Paper http://www.research.avayalabs.com/ project/libsafe/, (1999).
非特許文献1では、canaryへ値を代入し、また、canaryの値を調べ、オーバーフローが起きたか否かを検査する。このため検査の時間を費やすこととなるので(実行時のオーバーヘッド)、プログラムの実行速度が低下してしまう。
図9を用いて、バッファーを引数として関数呼び出しを行なった場合、呼び出し先で、そのバッファーのオーバーフローのチェックを行なっていないと生じる問題を説明する。もし、呼び出し先の関数内において引数で渡されたバッファーのオーバーフローが起き、呼び出し先の関数の戻りアドレスが書き換えられたとしても、呼び出し先の関数から呼び出し元関数へ戻る時にはオーバーフローの検査が行なわれずに、不正なアドレスへ移動することが可能になる。
図7のプログラム801において、関数set_bufferを呼び出した時のスタックの状態が図9のスタック1100である。スタック802の状態と異なり、スタックに引数変数のbufferが置かれ、関数set_bufferが呼び出されて関数set_bufferの戻りアドレスが置かれ、関数set_bufferのスタックのフレームポインタが置かれ、関数set_bufferの自動変数が置かれる。この状態で、関数set_buffer内において、配列変数bufferの添え字が0以下で書き込みが起きた場合、バッファーオーバーフローにより、悪意者は、関数set_bufferの戻りアドレスを変更することができる。この後、関数set_bufferが終了し、関数subへ戻るときに、書き換えられた不正なアドレスへフレームポインタが移動する。関数set_bufferでcanaryが置かれていても、canaryの位置までオーバーフローが起きなければ、オーバーフローの検出ができない。
非特許文献2の方法は、ハードウェアの変更が必要であり、システム変更のためのコストが高いという問題がある。
非特許文献3の方法は、ライブラリを置き換えるだけなので、ライブラリ以外のプログラム部分にあるバッファーオーバーフローには対応できないという問題がある。
プログラム中で使用する変数が置かれるメモリ領域には、自動変数が置かれるスタック、初期値の有る変数が置かれるデータセクション、初期値がない変数が置かれるBSSセクションがある。自動変数はスタックに置かれるが、グローバル変数や静的変数は、データセクションやBSSセクションに置かれる。このことを利用し、自動変数のバッファーをグローバル変数か、あるいは、静的変数へ変換することにより、バッファーへの書き込みをスタックへ行なわないようにする。これにより、悪意者は、バッファーオーバーフローによる戻りアドレスやフレームポインタの書き換えが行なえなくなり、不正なコードの存在するアドレスへの移動が出来なくなる。
自動変数をグローバル変数や静的変数へ変換すると、再帰呼び出しができなくなるので、再帰呼び出しがない部分にのみ適用する。再帰呼び出しを行なう関数には、従来の方法、例えば非特許文献1の方法を利用する。
非特許文献1で行っているような実行時のバッファーオーバーフローの検出を行なわないので、実行時オーバーヘッドがない。また、常にスタックにバッファーが存在しないので、戻りアドレスは書き換えられず、安全に戻りアドレスへ移動できる。
非特許文献2のようなハードウェアの変更も必要ない。
非特許文献3で対応していないプログラム部分のオーバーフローに対応している。再帰呼び出しを行なう関数に自動変数のバッファーがある場合、実行時に再帰呼び出しを行なうとスタック領域を全て使ってしまい、プログラムの実行が止まる可能性が高い。通常、このような再帰呼び出しを行なう関数には、バッファーを使わないように記述する。そのため、本発明は、再帰呼び出しを行なわない部分のみに対して適用しても有効である。
情報処理装置300の構成を図2に示す。情報処理装置300は、CPU301、入力装置302、出力装置303、主記憶装置304、外部記憶装置307を備えて構成される。CPU301は情報処理装置の全体の制御を司るもので、外部記憶装置307に記憶される本実施の形態に係る各種動作を行なうためのコードから構成されるコード変換プログラム308を実行することにより、本実施形態に係る情報処理装置300としての各種機能を実現する。
主記憶装置304は、CPU301によりワークエリアとして用いられるほか、後述するコールグラフ305と中間コード306を記憶する。外部記憶装置307には、コード変換プログラム308、ソースコード309、オブジェクトコード310、実行コード311が記憶されている。
なお、コールグラフとは、プログラムに含まれる1の手続を点で表す場合に、ある手続(A)が別の手続(B)を呼び出す関係があるとき、(A)から(B)へ向けた矢印で、呼び出し関係を表したグラフをいう。例えば、手続(A)が、手続(B)及び手続(C)を呼び出す場合には、(A)を起点として、(B)と(C)へ矢印の終点が位置するよう、それぞれ、2つの矢印が示されることとなる。コールグラフで表すには、プログラムに含まれる手続間の呼び出し関係が決定することを要する。
入力装置302は、情報処理装置300へのデータ入力等のために用いられる装置であり、ユーザインターフェースとして機能する。出力装置303は、情報を外部へ出力するための装置であり、ユーザインターフェースとして機能する。
ソースコード309は、C言語やC++言語で記述されたプログラムである。オブジェクトコード310は、コード変換プログラム308によりソースコード309から生成される、情報処理装置300が実行可能なプログラムコードである。この場合、コード変換プログラム308は、コンパイラとして機能する。実行コード311は、複数のオブジェクトコード310からコード変換プログラム308により生成される、情報処理装置300が実行可能なプログラムコードである。この場合、コード変換プログラム308は、リンカとして機能する。
図3に、コンパイル及びリンクの手順を示す。まずコンパイラ401(つまりコード変換プログラム308)にソースコード309が入力されるとオブジェクトコード310が生成される。そしてリンカ402(つまりコード変換プログラム308)にオブジェクトコード310が入力されると実行コード311が生成される。
オブジェクトコード310には、コールグラフ作成のために、ソースコード309から生成される中間コード306(図2)が含まれている。また、そのためにコンパイラ401は、中間コード306を含んだオブジェクトコード310を生成する。コンパイラ401は、複数のソースコード309を入力することができるが、makeコマンドなどのツールを利用する場合は、1つのソースコード309を入力し、1つのオブジェクトコード310を生成する。
リンカ402は、プログラムコードを構成するすべてのオブジェクトコード310を入力とするため、リンカ402では、プログラムコードを構成する全ての関数がそろう。そのため、プログラムコードを構成する全ての関数の呼び出し関係をコールグラフ305(図2)として作成することができる。
図4に、コンパイラ401の構成図を示す。
ますコンパイラ401は、ソースコード309を入力とし、中間コード生成501により中間コード306を生成する。制御フロー解析502では、中間コード306を入力とし制御フローを解析する。データフロー解析503では、中間コード306を入力としデータフローを解析する。最適化504では、制御フロー解析502の解析結果とデータフロー解析503の解析結果を用いて中間コード306を合理化し、情報処理装置100で実行可能なコードへ変換する。コンパイラ401は最適化504で変換したコードと中間コード306を含んだオブジェクトコード310を出力する。
図5に、リンカ402の構成図を示す。
まずリンカ402は、オブジェクトコード310を入力とし、中間コード読取601において中間コード306を取り出す。次に、自動変数変換602において、本発明による自動変数の変換を行なう。その後、制御フロー解析502、データフロー解析503、最適化504を行い、実行コード311を出力する。
自動変数をグローバル変数へ変換する方法について述べる。自動変数変換602のアルゴリズムを図1に示す。
まず、START101から始まり、ステップ102において中間コード306を入力としコールグラフ305(図2)を作成する。コールグラフの詳細については、文献「D. C. Atkinson. " Call graph extraction in the presence of function pointers", In Proc. 2002 Int. Conf. On Softw. Eng. Res. Prac., Page 579-584, (2002).」が参考となる。
ステップ103(図1)では、コールグラフ305をたどりループを検出する。つまり、コールグラフ305のデータの中に、手続(A)→手続(B)、手続(B)→手続(C)、手続(C)→手続(A)の関係があれば、手続(A)(B)(C)はループを構成している。ループの検出方法の詳細については、文献「M. Wolfe, "High Performance Compilers for parallel computing", Addison-Wesley Publishing Company, Page 60-64, (1996).」が参照となる。ステップ104では、ステップ103で検出したループに含まれる関数に対して、再帰の印をつける。ステップ105では、コールグラフ305に含まれる全ての手続きに対して、ステップ107以降の処理を適用するようにする。ここでは、107からの一連の処理を行なう対象の関数をfとする。
ステップ107では、現在処理中の関数fに再帰の印がついているか否かを調べる。再帰の印がついていればステップ108へ進み、なければステップ109へ進む。ステップ108では、関数fに対して従来のセキュリティー対策を適用する。例えば非特許文献1の方法を適用する。その後、ステップ105へ戻る。ステップ110では、関数fにある配列の自動変数をグローバル変数へ変更する。ステップ111では、ステップ110で変換したグローバル変数の名前を一意になるように名前を変更し、ステップ105へ戻る。ステップ105で処理する手続きがなくなればEND106へ進む。
図1のアルゴリズムを図6のプログラム701に適用した例を図8に示す。
関数subが再帰呼び出し関数でないと仮定すると、図1のアルゴリズムでは、ステップ102のコールグラフ作成後、ステップ103でループを検出し、ステップ104では関数subは再帰の印がつかない。ステップ105で全ての関数に対してステップ107以降の処理が繰り返され、ステップ107で関数subが対象になった場合は、再帰の印がついていないので、ステップ110へ進む。ステップ110では、図6のプログラム701の2行目の配列変数bufferを、図8の1行目のようにグローバル変数へ変換する。ステップ111では、ステップ110で変換した配列変数bufferの名前をsub_bufferと変更する。
かかる名前の変更は、同じ名前のグローバル変数で、異なる意味に用いられる変数が、同じ記憶領域を使うようになる問題を避けるために行なう。互いに異なる関数内では、同じ名前の自動変数がそれぞれ異なった意味に使え、それぞれ異なる領域に置かれる。そして、これらの自動変数が共にグローバル変数へ変更された場合、同じ名前のグローバル変数にならぬようにするため、名前の変更をするのである。
配列変数bufferをグローバル変数へ変更すると、変数に初期値がないためBSSセクション903に置かれ、スタックの状態はスタック702からスタック902のようになる。これにより、悪意者により、配列変数bufferにオーバーフローが起きても、戻りアドレスの書き換えが出来なくなる。
自動変数を静的変数へ変換する方法について述べる。自動変数変換602のアルゴリズムは、図1のステップ110及びステップ111の部分に代えて、ステップ210(配列の自動変数を静的変数へ変更)としたものである。残りは図1のステップと同様であり説明を省略する。
ステップ210では、関数fの配列の自動変数を静的変数へ変更し、ステップ105へ戻る。
自動変数変換602のアルゴリズムを図6のプログラム701に適用することを考える。実施例1と同じように、関数subが再帰呼び出し関数でないと仮定すると、ステップ107までは実施例1と同様である。ステップ210で、図6のプログラム701の2行目の配列変数bufferを、「static char buffer[128];」のように静的変数へ変換する。配列変数bufferを静的変数へ変更すると、変数に初期値がないためBSSセクションに置かれ、スタックの状態は図8のスタック902と同様になる。これにより、配列変数bufferにオーバーフローが起きても、戻りアドレスの書き換えが起きなくなる。
実行時のオーバーヘッドを費やすことなく、プログラムにおけるスタック上のデータ破壊を回避し、悪意者による不正なコードの実行を阻止して、セキュリティーホールのない計算機システムを構築することに貢献できる。
自動変数をグローバル変数へ変換する自動変数変換602のアルゴリズムである。 情報処理装置300の構成図である。 コンパイルおよびリンクの手順を示す図である。 コンパイラ401の構成図である。 リンカ402の構成図である。 バッファーオーバーフローの具体例を説明するための、プログラムとそのスタックの状態を示す図である。 非特許文献1のStackGuardを適用したときの、プログラムとそのスタックの状態を示す図である。 図1のアルゴリズムを図6のプログラム701に適用した結果を示す図である。 バッファーを引数として関数呼び出しを行なったときの問題点を説明するための図である。
符号の説明
108……従来のセキュリティー対策を実施
110……自動変数をグローバル変数へ変更
111……変数名を一意になるように変更
210……自動変数を静的変数へ変更

Claims (5)

  1. プログラムに含まれる、手続相互の呼び出し関係を作成する第1のステップと、
    前記呼び出し関係を用いて、前記プログラムの手続に含まれる関数を、再帰呼び出しを行なう関数と、行なわない関数に分ける第2のステップと、
    前記再帰呼び出しを行なわない関数に対して、その関数の自動変数をグローバル変数へ変換する第3のステップと、
    前記グローバル変数の名前を変更する第4のステップにより、前記プログラムのコードを生成する、プログラムの生成方法。
  2. プログラムに含まれる、手続相互の呼び出し関係を作成する第1のステップと、
    前記呼び出し関係を用いて、前記プログラムの手続に含まれる関数を、再帰呼び出しを行なう関数と、行なわない関数に分ける第2のステップと、
    前記再帰呼び出しを行なわない関数に対して、その関数の自動変数を静的変数へ変換する第3のステップにより、前記プログラムのコードを生成する、プログラムの生成方法。
  3. 請求項1又は請求項2記載のプログラムの生成方法において、前記呼び出し関係はコールグラフであるプログラムの生成方法。
  4. プログラムに含まれる手続相互の呼び出し関係から、当該プログラムの手続に含まれる関数であって再帰呼び出しを行なわないものを抽出し、当該関数の自動変数をグローバル変数へ変換するプログラム。
  5. プログラムに含まれる手続相互の呼び出し関係から、当該プログラムの手続に含まれる関数であって再帰呼び出しを行なわないものを抽出し、当該関数の自動変数を静的変数へ変換するプログラム。
JP2005185921A 2005-06-27 2005-06-27 不正コードの実行を防ぐプログラムの生成方法、及び、そのプログラム Pending JP2007004647A (ja)

Priority Applications (1)

Application Number Priority Date Filing Date Title
JP2005185921A JP2007004647A (ja) 2005-06-27 2005-06-27 不正コードの実行を防ぐプログラムの生成方法、及び、そのプログラム

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
JP2005185921A JP2007004647A (ja) 2005-06-27 2005-06-27 不正コードの実行を防ぐプログラムの生成方法、及び、そのプログラム

Publications (1)

Publication Number Publication Date
JP2007004647A true JP2007004647A (ja) 2007-01-11

Family

ID=37690186

Family Applications (1)

Application Number Title Priority Date Filing Date
JP2005185921A Pending JP2007004647A (ja) 2005-06-27 2005-06-27 不正コードの実行を防ぐプログラムの生成方法、及び、そのプログラム

Country Status (1)

Country Link
JP (1) JP2007004647A (ja)

Cited By (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
JP2011008778A (ja) * 2009-05-27 2011-01-13 Ntt Docomo Inc プログラム実行フローの修正を防止する方法及び装置

Cited By (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
JP2011008778A (ja) * 2009-05-27 2011-01-13 Ntt Docomo Inc プログラム実行フローの修正を防止する方法及び装置

Similar Documents

Publication Publication Date Title
US7380242B2 (en) Compiler and software product for compiling intermediate language bytecodes into Java bytecodes
US8341614B2 (en) Memory management for closures
US20070028225A1 (en) Method and apparatus for preemptive monitoring of software binaries by instruction interception and dynamic recompilation
CN110088736B (zh) 自调试方法和系统
US20100095281A1 (en) Internal Function Debugger
US8584102B2 (en) Creating and using deltas to modify existing computer code
WO2015164426A1 (en) Metadata-driven dynamic specialization
JP4806060B2 (ja) コンパイラ・プログラム、コンパイル方法及びコンピュータ・システム
KR20080005493A (ko) 소프트웨어 보호
US20230267067A1 (en) Software protection from attacks using self-debugging techniques
JP4754635B2 (ja) 制御フロー保護機構
JP2007004647A (ja) 不正コードの実行を防ぐプログラムの生成方法、及び、そのプログラム
Caromel et al. Robust exception handling in an asynchronous environment
KR101842263B1 (ko) 어플리케이션에 대한 역공학 차단 방법 및 장치
JP2009258796A (ja) プログラム開発装置及びプログラム開発方法
WO2022054206A1 (ja) 難読化装置、難読化方法および難読化プログラム
Shahriar et al. Rule-based source level patching of buffer overflow vulnerabilities
Song Computer Security Optional Notes
JP2009259078A (ja) バッファオーバーフロー検出方法、バッファオーバーフロー検出プログラム、およびバッファオーバーフロー検出装置
Maebe et al. Instrumenting JVMs at the machine code level
Breech et al. A framework for testing security mechanisms for program-based attacks
US20230418950A1 (en) Methods, Devices, and Systems for Control Flow Integrity
Lee et al. Detecting Suspicious Conditional Statement using App Execution Log
Ren et al. Detect Stack Overflow Bugs in Rust via Improved Fuzzing Technique.
Saeed et al. Tag‐Protector: An Effective and Dynamic Detection of Illegal Memory Accesses through Compile Time Code Instrumentation