(57)【特許請求の範囲】
【請求項１】
検査対象のソースコードの脆弱性を検査するソースコード脆弱性検査装置であって、
検査対象ソースコードの構文の解析を行い、該検査対象のソースコードの解析木を構築する構文解析手段と、
前記検査対象ソースコード内で使用されているライブラリに含まれる関数について、内部での処理による仮引数間のデータ遷移を記述した仮引数間遷移データベースと、
前記検査対象ソースコード内で定義されているユーザ定義関数について、内部での処理による仮引数間のデータ遷移と、該検査対象ソースコードをコンパイルして作成されたプログラムの実行時に該プログラムの外部から与えられた入力データを受け取ることのある仮引数の位置とを、組にして登録するための動的仮引数間遷移データベースと、
前記検査対象ソースコード内で使用されている変数の保持する値の種類を、外部から与えられた入力データであるか否かを区別して、記録するための変数テーブルと、
前記解析木を辿りながら、ユーザ定義関数があれば、そのユーザ定義関数を分析対象である対象関数とし、その部分解析木を探索して仮引数とローカル変数の定義を前記変数テーブルに登録し、変数間のデータ遷移や変数の外部出力の箇所があれば、前記仮引数間遷移データベースと前記動的仮引数間遷移データベースと前記変数テーブルとを参照して更新し、前記対象関数の部分解析木の探索が終了したら、その対象関数について変数テーブルの内容に基づき前記動的仮引数間遷移データベースの内容を更新し、このような処理を繰り返すことにより、解析木を辿って変数間のデータ遷移を追跡できるようにする手段と、
外部入力をパラメータとして使用すると脆弱な関数を登録した脆弱性データベースと、
前記脆弱性データベースを読み込み、前記変数間のデータ遷移が該脆弱性データベースの登録内容に合致する箇所を、脆弱性を有する箇所として警告する手段と
を備えることを特徴とするソースコード脆弱性検査装置。
【請求項２】
検査対象のソースコードの脆弱性を検査するソースコード脆弱性検査装置であって、
検査対象ソースコードの記述に用いたプログラミング言語の構文解析ルールに従って該検査対象ソースコードを構文解析して解析木を構築する構文解析手段と、
該検査対象ソースコード内で使用されているライブラリに含まれる関数について、内部での処理による仮引数間のデータ遷移を記述した仮引数間遷移データベースと、
該検査対象ソースコード内で定義されているユーザ定義関数について、内部での処理による仮引数間のデータ遷移と、該検査対象ソースコードをコンパイルして作成されたプログラムの実行時に該プログラムの外部から与えられた入力データを受け取ることのある仮引数の位置とを、組にして登録する動的仮引数間遷移データベースと、
該検査対象ソースコード内で使用されている変数の保持する値の種類を、該プログラムの外部から与えられた入力データであるか否かを区別して、記録する変数テーブルと、
プログラムの実行時に該プログラムの外部から与えられた入力データをある特定の仮引数で受け取って処理すると脆弱性を生じる可能性のある該ライブラリ内の関数と、該特定の仮引数の位置とを、組にして登録した脆弱性データベースと、
前記解析木のルートノードから該解析木の全体を所定の順序で繰り返し辿りながら、前記動的仮引数間遷移データベースと変数テーブルとを更新し、前記動的仮引数間遷移データベースに新たな更新がなくなった後に、再び該解析木のルートノードから該解析木の全体を所定の順序でたどりながら、前記仮引数間遷移データベースと前記動的仮引数間遷移データベースを参照して前記変数テーブルを更新し、さらに、前記脆弱性データベースを参照して、該脆弱性データベースに登録された関数が前記検査対象ソースコード内で呼び出される箇所において、該登録された関数と組の該特定の引数の位置で実引数として指定された変数について該変数テーブルに登録された該変数の保持する値の種類が該プログラムの外部からの入力データであれば、該箇所を脆弱性として脆弱性検査結果に出力する脆弱性検出手段と
を備え、
前記脆弱性検出手段は、前記解析木を所定の順序でたどって関数定義ノードに到達した時、該関数定義ノードの表すユーザ定義関数が前記動的仮引数間遷移データベースに登録されていなければ該ユーザ定義関数を登録し、
続いて該解析木の該関数定義ノードを頂点とする部分解析木を所定の順序でたどり、仮引数定義ノードに到達すれば、該仮引数ノードの表す該仮引数を前記変数テーブルに登録し、
また該ユーザ定義関数について該動的仮引数間遷移データベースに該仮引数が前記プログラムの外部からの入力データを受け取ることのある仮引数として登録されていれば、該変数テーブルに該仮引数の保持する値の種類として外部入力データを登録し、
また変数定義ノードに到達すれば、該変数定義ノードの表す変数を該変数テーブルに登録し、
また関数呼出しノードに到達すれば、該関数呼出しノードの表す関数について該仮引数間遷移ＤＢまたは該動的仮引数間遷移データベースに登録された仮引数間のデータ遷移を参照し、該仮引数間のデータ遷移を構成する、遷移元仮引数の値の種類、および遷移先仮引数の値の種類を取得し、
該遷移元仮引数の値の種類が該関数呼出しノードの表す関数の第１の仮引数であれば、該部分解析木を所定の順序でたどって該第１の仮引数の位置に当たる第１の実引数ノードに到達し、該第１の実引数ノードの表す第１の変数について前記変数テーブルに記録された変数の保持する値の種類を新たな遷移先の値の種類として取得し、
該遷移元仮引数の値の種類が外部入力データであれば新たな遷移先の値の種類を外部入力データとし、
該遷移先仮引数の値の種類が該関数呼出しノードの表す関数の第２の仮引数であれば、該部分解析木を所定の順序でたどって該第２の仮引数の位置に当たる第２の実引数ノードに到達し、該第２の実引数ノードの表す第２の変数について前記変数テーブルに記録された変数の保持する値の種類として、該新たな遷移先の値の種類を登録し、
さらに該新たな遷移先の値の種類に外部入力データを含み、かつ該関数呼出しノードの表す関数が前記動的仮引数遷移データベースに登録されていれば、該関数呼出しノードの表す関数について該第１の仮引数が該プログラムの外部から入力データを受け取ることを該動的仮引数間遷移データベースに登録し、
さらに該新たな遷移先の値の種類に外部入力データを含み、かつ該関数呼出しノードの表す関数と該第１の仮引数の位置との組が前記脆弱性データベースに登録されていれば、前記検査対象ソースコード内での該第１の変数の記述位置を脆弱性が生じる可能性のある箇所として出力し、
そして該部分解析木を所定の順序でたどり終えたら、該仮引数ごとに、該変数テーブルに記録された該仮引数の保持する値の種類を遷移元仮引数の保持する値の種類、該仮引数自身を遷移先仮引数の保持する値の種類とする新たな仮引数間のデータ遷移を作成し、該動的仮引数間遷移データベースの該ユーザ定義関数についての仮引数間のデータ遷移を該新たな引数間のデータ遷移で上書きする
ことを特徴とするソースコード脆弱性検査装置。
【請求項３】
請求項２に記載のソースコード脆弱性検査装置において、
前記脆弱性検出手段は、前記変数テーブルに記録される変数の保持する値の種類を、該変数について可能な間接参照の深さ毎に記録することを特徴とするソースコード脆弱性検査装置。
【請求項４】
請求項２または３に記載のソースコード脆弱性検査装置において、
前記脆弱性検出手段は、前記解析木を所定の順序でたどり、変数の定義ノードに到達したときに該変数の定義ノードの表す変数および該解析木内での深さを該変数テーブルに登録し、
さらに該解析木を所定の順序でたどって到達したノードの該解析木内での深さが該変数の定義ノードの深さより浅くなったときに該変数についての登録データを該変数テーブルから削除する
ことを特徴とするソースコード脆弱性検査装置。
【請求項５】
検査対象のソースコードの脆弱性を検査するソースコード脆弱性検査装置であって、
検査対象ソースコードの構文の解析を行う構文解析手段と、
ライブラリ関数に伴うデータ遷移をあらかじめ登録しておく固定関数遷移データベースと、
脆弱性の生じる可能性のある遷移先と、それを回避するための処理を経たことを表す値とを、あらかじめ登録しておく脆弱遷移先データベースと、
ソースコード内で定義される変数の種類と値とを記録する変数データベースと、
前記検査対象ソースコード内で定義した関数に伴うデータ遷移を記録する不定関数遷移データベースと、
前記検査対象ソースコードを辿りながら、前記固定関数遷移データベースと脆弱遷移先データベースとを参照し、前記変数データベースに前記検査対象ソースコード内で定義される変数の種類と値を記録し、前記不定関数遷移データベースを更新し、これによりデータ遷移を追跡できるようにし、脆弱性を回避する処理を受けていない外部入力値が、脆弱性の生じる可能性のある遷移先に遷移する、脆弱なデータ遷移が行われる関数呼び出し箇所を脆弱性として検出する脆弱性検出手段と
を備えることを特徴とするソースコード脆弱性検査装置。
【請求項６】
請求項５に記載のソースコード脆弱性検査装置において、
前記検査対象ソースコード中で定義された関数のうち、その内部で呼ばれる関数が、ライブラリ関数または既に処理を終えデータ遷移を登録したプログラマ定義関数のみである関数定義から処理するように、処理対象関数を決める手段を備えることを特徴とするソースコード脆弱性検査装置。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、ソフトウェアのソースコードを検査し、外部との入出力データを識別して関数間及び変数間の受け渡しを追跡し、さらに予め備えたルールに該当する脆弱性を有する箇所を検出するソースコード脆弱性検査装置に関するものである。
【背景技術】
【０００２】
ソフトウェアに含まれる脆弱性を検査する方法には、動作中のソフトウェアに様々なデータを入力して結果を調べる方法と、ソフトウェアのソースコードを検査する方法の２つがある。
【０００３】
ソースコードを検査する方法には、パターンマッチングを用いる手法と構文解析を用いる手法がある。パターンマッチングを用いる検査では、検査対象のソースコード内から、プログラミング言語の標準ライブラリなどに含まれる「危険な関数」の使用箇所を関数名などによるパターンマッチングで検出する。「危険な関数」とは、プログラマがその使用に注意しないとソフトウェアに脆弱性を生じさせる関数のことである。例えば、データ複製の際に複製先のデータ領域の範囲を超えて複製する可能性のある関数や、コンピュータリソースを使用する際に競合状態のためプログラマの意図したとおりに使用できない可能性のある関数などがある。特に前者はバッファオーバーラン（バッファオーバーフロー）脆弱性の原因として広く知られている。
【０００４】
構文解析を用いる検査では、予めソースコードに検査のための付加的な注釈を加えた上でソースコードの構文解析を行い、データ構造の遷移（メモリ管理エラーや型の不一致など）や「危険な関数」の使用などを解析して論理的な矛盾点を見つけ出す。
【０００５】
いずれのソースコード検査手法においても、その手法を自動で行うツールが開発されている。しかし、どのツールも誤検出が多く、検査結果をもとにプログラマがソースコードを確認して脆弱性であるか否か判断しなければならない。
【０００６】
なお、ソースコード検査手法については下記非特許文献１に、「危険な関数」の例やバッファオーバーランについては下記非特許文献２に、それぞれ、説明がある。
【非特許文献１】情報処理振興事業協会セキュリティセンター：オープンソース・ソフトウェアのセキュリティ確保に関する調査報告書  第II部  オープンソース・ソフトウェアの効率的な検査技術の調査：平成１５年２月、ｐ．II-２〜II-４
【非特許文献２】情報処理振興事業協会セキュリティセンター：セキュア・プログラミング講座：平成１４年３月、[１-２.]クロスサイトスクリプティング、他
【発明の開示】
【発明が解決しようとする課題】
【０００７】
ソフトウェアの脆弱性は、ソフトウェアが外部からの入力データを誤処理したり、誤処理した（あるいは未処理のまま）入力データを他のソフトウェアに出力したりすることで、生じる。ここで前者の代表例はバッファオーバーラン、後者の代表例はクロスサイトスクリプティング脆弱性やSQLコマンド挿入脆弱性であり、これらについては上記非特許文献２に詳しい説明がある。
【０００８】
ところで、パターンマッチングによるソースコード検査は「危険な関数」の使用箇所を検出するだけであり、その関数が処理するデータが外部からの入力データであるか否かを区別しない。そのため、実引数として渡されるデータの出所とは無関係に「危険な関数」の使用される全ての箇所が脆弱性として検知されてしまい、これらが本当に脆弱性であるかどうかを決定するためには、結局、プログラマがソースコードをインスペクションしなければならない。外部入力データを受け付ける関数は既知なのでその使用箇所をソースコードから検出可能であるが、パターンマッチングでは外部入力データのその後の使用箇所を追跡できず、プログラマによるインスペクション箇所を限定するには至らない。
【０００９】
構文解析によるソースコード検査では、構文解析を支援する注釈をプログラマが予めソースコードに詳細に記述しなければならない。そのため、ソースコード検査のための事前作業が大きく、プログラマの負担が大きい。
【００１０】
本発明は、上記の問題点を解決することを目的とするものであり、特に、脆弱性を有する部分を精度良く検出でき、単純なパターンマッチングで「危険な関数」の使用箇所を見つけるだけの方法と比較してプログラマがインスペクションする必要のある箇所を少なくでき、また、事前にプログラマが検査対象のソースコードに脆弱性検知の支援を目的とした注釈を記述する必要がなく、プログラマによるソースコード検査の作業負担を減らすことができるようにすることを目的とする。
【課題を解決するための手段】
【００１１】
上記の目的を達成するため、本発明に係るソースコード脆弱性検査装置は、検査対象のソースコードの脆弱性を検査するソースコード脆弱性検査装置であって、前記検査対象のソースコードを解析して、外部入力がどのように遷移するかを求める手段と、外部入力をパラメータとして使用すると脆弱な関数を登録した脆弱性データベースと、前記検査対象のソースコードにおける外部入力の遷移を追跡し、前記脆弱性データベースの登録内容に合致する箇所を、脆弱性を有する箇所として警告する手段とを備えることを特徴とする。
【００１２】
本発明では、例えば検査対象ソースコード内で使用されているライブラリに含まれる関数について、内部での処理によりどの仮引数の値がどの仮引数に移動またはコピーされるか、あるいは戻り値として返されるか、外部からの入力データを受け取るのはどの仮引数であるか、を表す仮引数間データ遷移を記述した仮引数間遷移ＤＢ（データベース）を予め備える。また、同ライブラリに含まれる、特定の仮引数に外部からの入力データを与えると脆弱性を生じる関数について、その関数名と特定の仮引数の位置を組にして登録した脆弱性ＤＢも予め備える。
【００１３】
まず、検査対象ソースコードの検査にあたり、構文解析手段は、検査対象ソースコードの記述に用いたプログラミング言語の構文解析ルールに従い、検査対象ソースコードから解析木を構築する。
【００１４】
続いて、脆弱性解析手段は、この解析木をルートノードから所定の順序でたどり、関数定義ノードに到達したらそのノードの表すユーザ定義関数を、まだ登録されていなければ動的仮引数遷移ＤＢに登録する。
【００１５】
次に、この関数定義ノードを頂点とする部分解析木を所定の順序でたどり、仮引数定義ノードに到達したら、この仮引数定義ノードの表す仮引数を変数テーブルに登録する。ここで現在処理中のユーザ定義関数について動的仮引数間遷移ＤＢを参照し、この仮引数が外部入力データを受け取ると登録されていれば、変数テーブルにもこの仮引数の値の種類に外部入力データを登録する。
【００１６】
また変数定義ノードに到達したら、この変数定義ノードの表す変数を変数テーブルに登録する。
【００１７】
また、関数呼出しノードに到達したら、仮引数間遷移ＤＢと動的仮引数間遷移ＤＢを参照してこの関数呼出しノードの表す関数の仮引数間のデータ遷移を取り出す。
【００１８】
このデータ遷移の遷移元仮引数の値の種類としてこの関数呼出しノードの表す関数の第１の仮引数が含まれていれば、解析木を所定の順序でたどって第１の仮引数の位置に当たる第１の実引数ノードに到達する。そして変数テーブルを参照し、第１の実引数ノードの表す第１の変数について登録されている変数の保持する値の種類を読み出し、これを新たな遷移先の値の種類とする。あるいは遷移元仮引数の値の種類に外部入力データが含まれていれば、これを新たな遷移先の値の種類とする。
【００１９】
次に、データ遷移の遷移先仮引数の値の種類として関数呼出しノードの表す関数の第２の仮引数が含まれていれば、解析木を所定の順序でたどって第２の仮引数の位置に当たる第２の実引数ノードに到達する。そして第２の実引数ノードの表す第２の変数について、先ほど求めた新たな遷移先の値の種類を第２の変数の保持する値として変数テーブルに登録する。
【００２０】
さらにここで、新たな遷移先の値の種類に外部入力データが含まれ、かつ関数呼出しノードの表す関数が動的仮引数間遷移ＤＢに登録されていれば、この関数の第１の仮引数が外部入力データを受け取ることを動的仮引数間遷移ＤＢに追記する。
【００２１】
部分解析木をたどり終えたら、仮引数ごとに、変数テーブルに記録された保持する値の種類を取得して遷移元仮引数の保持する値とし、仮引数自身を遷移先仮引数の保持する値とする、新たな仮引数間データ遷移を作成し、関数呼出しノードの表す関数の新たな仮引数間データ遷移として動的仮引数間遷移ＤＢに上書きする。
【００２２】
以上を検査対象ソースコードの各ユーザ定義関数について行いつつ、解析木全体をたどる。解析木全体をたどる間に一度でも動的仮引数間遷移ＤＢに更新があれば、再びルートノードから解析木をたどり上記の処理を行う。たどり終わったときに新たな更新がなくなったら、脆弱性解析手段は、再びルートノードから解析木を所定の順序でたどり、上記の処理を行いながら、仮引数間遷移ＤＢと動的仮引数間遷移ＤＢを参照して変数テーブルを作成、更新する。ただし、関数呼出しノードの処理において、その新たな遷移先の値の種類に外部入力データを含み、かつその関数呼出しノードの表す関数と前記第１の仮引数の位置との組が脆弱性ＤＢに登録されていれば、検査対象ソースコード内での前記第１の変数の記述位置を脆弱性の生じる可能性のある箇所として出力する。
【００２３】
本発明に係るソースコード脆弱性検査装置は、例えば検査対象のソースコードがＣ言語で記述されているときに、ポインタ変数自身とポインタ変数の間接参照先ごとにその値の種類を記録する。また変数のスコープに従い変数テーブルへの変数の登録・削除を行う。
【発明の効果】
【００２４】
本発明のソースコード脆弱性検査装置によれば、脆弱な箇所として検知する箇所を外部からの入力データを実引数として受け取る「危険な関数」の使用箇所に限定できる。そのため、検知された箇所が実際に脆弱性であるか、プログラマがインスペクションする必要のある箇所を、単純なパターンマッチングで「危険な関数」の使用箇所を見つける方法に比べて少なくできる。
【００２５】
すなわち本発明によれば、関数が扱うデータが、外部由来がどうか、および適切な脆弱性を回避する処理を受けているかどうかを判別するため、誤った脆弱性検出を防ぐことができる。また、あらかじめ登録した関数の呼び出し箇所だけでなく、プログラマが定義した関数の呼び出し箇所が脆弱であるかどうかも検査できる。これにより、プログラマが、脆弱性を回避する処理を行うべき場所を容易に特定できる。また、ソースコードにその内容と直接関係のない脆弱性検知を目的とした注釈を記述する必要がない。また、プログラマによるソースコード検査の作業負担が少ない。
【００２６】
本発明のソースコード脆弱性検査装置では、変数値の出所をポインタ変数自身やポインタ変数の間接参照先ごとに記録できるので、Ｃ言語のような間接参照をサポートするプログラミング言語で記述されたソースコードの検査も可能である。また、変数のスコープに従って変数テーブルへの変数の登録・削除を行うので、変数のスコープを考慮しない場合に比べて変数テーブルへの登録数を少なくして、ソースコード検査にかかる時間を減らすことができる。
【発明を実施するための最良の形態】
【００２７】
以下、図面を用いて本発明の実施の形態を説明する。まず、第１の実施形態を説明し、その後、第２の実施形態を説明する。
【００２８】
図１は、本発明の第１の実施形態であるソースコード脆弱性検査装置の構成図である。
【００２９】
１０１はソースコード脆弱性検査装置の本体（コンピュータ）で、ＣＰＵ１０２、記憶装置１０３、及びメモリ１０４を備える。ＣＰＵ１０２は、ソースコード検査を行うプログラムの実行や各種制御を行う。記憶装置１０３には、ソースコード検査を行うプログラム、検査対象のソースコード、及び、後述する仮引数間遷移ＤＢ２０４や脆弱性ＤＢ２０５などが保存される。メモリ１０４は、ＣＰＵ１０２で実行されるプログラムなどの扱う各種データを一時的に記憶する。
【００３０】
キーボード１０５はソースコード脆弱性検査装置に指示を送るための入力装置、ＣＲＴ１０６はソースコード脆弱性検査装置の表示装置である。外部記憶装置１０７は、ソースコード脆弱性検査装置に検査対象のソースコードを入力したり、検査結果を出力するための記憶装置である。バス１０８はこれら各部１０２〜１０７を相互に接続するバスであり、ＣＰＵ１０２の指示で移動されるデータの通り道である。
【００３１】
図２は、ソースコード脆弱性検査装置の機能の概要図である。ソースコード脆弱性検査装置は、構文解析手段２０１、及び脆弱性検出手段２０２を備える。これらの手段は、ＣＰＵ１０２がソースコード検査を行うプログラムを実行することにより実現されるものである。
【００３２】
構文解析手段２０１は、構文解析ルール２０３に従って検査対象ソースコード２０８を構文解析して解析木２１０を構築する。
【００３３】
脆弱性検出手段２０２は、解析木２１０をたどり、検査対象ソースコード２０８内で定義された関数（ユーザ定義関数）を列挙し、動的仮引数間遷移ＤＢ２０６を作成する。更に検査対象ソースコード２０８内で定義された変数を変数テーブル２０７に登録する。そして、検査対象ソースコード２０８の使用するライブラリで提供される関数（ライブラリ関数）について予め作成された仮引数間遷移ＤＢ２０４と、解析木２１０をたどりながら作成・更新する、動的仮引数間遷移ＤＢ２０６に従い、変数間のデータ遷移を追跡し、変数の保持する値の種類を変数テーブル２０７に逐次記録する。ここで、ファイルＩ／Ｏや通信などで外部から入力されたデータを参照する変数が、脆弱性ＤＢ２０５に予め登録された危険なライブラリ関数（「危険な関数」とされるライブラリ関数）の実引数として与えられる場合、検査対象ソースコード内の該当する箇所を脆弱な箇所として脆弱性検査結果２０９に出力する。
【００３４】
図３は、ソースコード脆弱性検査装置の構文解析手段２０１及び脆弱性検出手段２０２の詳細な処理手順である。手順３０１は構文解析手段２０１により実施され、それ以降の手順は脆弱性検出手段２０２により実施される。以下、各手順の詳細、及び図２の２０３〜２０７について説明する。
【００３５】
手順３０１において、構文解析手段２０１は、検査対象ソースコード２０８と構文解析ルール２０３を読込み、解析木２１０を構築する。
【００３６】
ここでは、図４に示すＣ言語で記述した検査対象ソースコード２０８を例にしてソースコード脆弱性検査装置の処理手順を説明する。図４の左端の行番号は、説明の便宜上、記したものである。なお、本処理手順は他のプログラミング言語で記述されたソースコードにも適用可能である。
【００３７】
構文解析ルール２０３は、検査対象ソースコード２０８の記述に用いられたプログラミング言語の文法を解釈するために予め定義されたルールである。本実施形態はルールの記述方法や内容、構文解析の手順を特定しないが、構文解析では少なくともソースコード内で使用されているグローバル変数、ローカル変数、仮引数、ユーザ定義関数、及びライブラリ関数を識別し、またソースコードを処理の最小単位である式に分解して解析木２１０を構築可能であることを前提とする。
【００３８】
図５は、図４のソースコードから構築された解析木２１０の例である。説明の便宜上、左端に行番号を記している。図中の囲み文字は、ソースコードの解析単位であるノードを表す。解析木２１０の各末端ノード（子ノードを持たないノード）のカッコ内の文字は、その末端ノードに対応するソースコードの断片である。図５では解析されたソースコードの主要なノードのみ記しており、括弧やセミコロンなどの区切り文字、演算子などは省略されている。
【００３９】
本実施形態では解析木２１０の構造を特に指定しないが、解析木２１０は、解析されたソースコードの全ノード（関数定義、式、変数など）の親子関係を、ルートノードを頂点とする木構造に表したものとする。また、所定の順序（図５の例ではルートノードを始点に上から下、左から右に向かって順に）に従うと末端ノードのソースコードの断片をソースコード内での出現順にたどれるものとする。
【００４０】
なお本実施形態の説明では、リスト構造のデータを'['、']'、集合を'('、')'で囲み、それぞれの各要素を','で区切って表記する。
【００４１】
また、検査対象ソースコード２０８をコンパイルして実行した際に検査対象ソースコード２０８内の各変数や仮引数が保持する値を、本実施形態の説明では抽象化して表記する。基本的な表記方法は、変数の値については変数テーブル２０７に登録された変数に割り当てられる識別番号に抽象化して表記するものとし、仮引数の値についてはライブラリ関数やユーザ定義関数の各仮引数を左から順に１、２、３と割り当てた仮引数番号に抽象化して表記するものとし、さらにその変数や仮引数で可能な間接参照の深さに応じた数の'*'を前置するものとする。例えば、識別番号（仮引数番号）として３を割り当てた変数（仮引数）の可能な間接参照の深さが０（ポインタではない）ならば、その値を'3'と表記する。可能な間接参照の深さが１（ポインタや１次元配列数）ならば、ポインタ変数（仮引数）自身の値を'3'、その間接参照先の値を'*3'と表記する。可能な間接参照の深さが２（ポインタのポインタや２次元配列）ならば、ポインタのポインタである変数（仮引数）自身の値を'3'、その間接参照先の値を'*3'、さらにその間接参照先の値を'**3'と表記する。ライブラリ関数やユーザ定義関数の戻り値を表す仮引数番号として０を用いる。また、可変長仮引数を表記する場合は可変長仮引数の仮引数番号に'...'を後置する。変数や仮引数がファイルＩ／Ｏや通信など外部入力を取得するライブラリ関数の呼出しで直接取得した外部入力データを保持する場合は'IN'と表記する。変数や仮引数の保持する値が外部へ出力される場合を示す場合は'OUT'と表記する。以上で説明した、変数や仮引数の保持する値を抽象的に表記したものを、本実施形態では参照データと呼ぶ。
【００４２】
手順３０１の後、手順３０２において、脆弱性検出手段２０２は、解析木２１０及び仮引数間遷移ＤＢ２０４を読込む。
【００４３】
図６は、仮引数間遷移ＤＢ２０４の例である。仮引数間遷移ＤＢ２０４は、内部での処理により仮引数の間でその保持する値のコピーや移動等のデータ遷移を伴うライブラリ関数を予め列挙したＤＢであり、検査対象ソースコード２０８のプログラミング言語や使用するライブラリ、コンパイラの処理系によって内容は異なる。ここではANSI C標準ライブラリの関数の例を示している。
【００４４】
図６の仮引数間遷移ＤＢ２０４の１列目は関数名である。２列目はどの仮引数の値がどの仮引数に遷移するか示すデータ遷移のリストである。このリストを仮引数間遷移リスト、リスト内の各要素を仮引数間遷移エレメントと、呼ぶ。各仮引数間遷移エレメントは、矢印'→'の左の参照データ（遷移元参照データ）で表記される仮引数の保持する値の全部または一部が、'→'の右の参照データ(遷移先参照データ)で表記される仮引数に複製されることを意味する。なお、仮引数間遷移リスト内の各エレメントは左から順に評価されるものとする。値渡しの仮引数は関数呼出しの前後でその値が必ず不変なので、このことを表す仮引数間遷移エレメント（例えば'1→1'）は仮引数間遷移リストに加えない。参照渡しの仮引数についてはその仮引数で可能な間接参照先が上書きされて残らない場合を除き、仮引数間遷移エレメント（例えば可能な間接参照の深さが２の仮引数なら'*1→*1'と'**1→**1'）を必ず仮引数間遷移リストに加えるものとする。
【００４５】
図６の例によると、関数getsは外部入力データが第１仮引数の間接参照先に遷移し、さらに第１仮引数のポインタが戻り値として返される。関数sprintfは第２仮引数と第３仮引数以降の可変長仮引数の間接参照先が不変で、これら間接参照先の値が第１仮引数の間接参照先に遷移する。関数putsは第１仮引数の間接参照先が不変で、かつ外部に出力される。
【００４６】
なお、仮引数間遷移ＤＢ２０４や動的仮引数間遷移ＤＢ２０６への登録対象は、特定のデータ型の仮引数を扱う関数に限定しても、データ型に関係なく全ての関数でもよい。本実施形態では、文字列の格納に使われるchar*型、const char*型を扱うものに限定している。
【００４７】
手順３０３において、脆弱性検出手段２０２は、解析木２１０をルートノードから所定の順序で全てたどり、見つかったユーザ定義関数を動的仮引数間遷移ＤＢ２０６に、グローバル変数を変数テーブル２０７に、それぞれ登録する。ここでの登録内容は暫定的なもので、手順３０５〜３１２において更新される。
【００４８】
図７は、図５の解析木２１０をたどって作成された動的仮引数間遷移ＤＢ２０６の例である。動的仮引数間遷移ＤＢ２０６の１列目と２列目は仮引数間遷移ＤＢ２０４と同じである。３列目は外部入力データを受け取ることのある仮引数の集合で、集合の各要素である外部入力仮引数を参照データとして表記する。手順３０３の時点では仮引数間のデータ遷移は不明なので、２列目の仮引数間遷移リストの初期値には参照渡しの仮引数だけについて参照先が不変であることを示す仮引数間遷移リストを与える。各仮引数が外部入力データを受け取るかどうかもこの時点では不明なため、３列目の外部入力仮引数集合の初期値を空集合とする。ただし、関数mainだけは第２引数（char型のポインタ配列）がプログラム実行パラメータを受け取るとＣ言語の仕様で定められているため、そのことを表す外部入力仮引数集合'(**2)'を初期値とする。
【００４９】
図５の解析木２１０にはグローバル変数が含まれていないので、ここでは変数テーブル２０７への登録はない。登録する場合の初期値は、手順３０８で説明するローカル変数のそれと同じである。
【００５０】
手順３０４において、脆弱性検出手段２０２は、初めて手順３０４を実施する場合、あるいは手順３０５〜３１２での解析木全探索を終了して手順３０４に戻ったときにその全探索の前後で動的仮引数間遷移ＤＢ２０６の内容が更新されている場合、次に手順３０５を実施する。それ以外の場合、手順３１３に進む。手順３０５において、脆弱性検出手段２０２は解析木２１０の探索をルートノードから始める。手順３０６において、脆弱性検出手段２０２は、解析木２１０の探索が終了していれば次に手順３０４を実施し、終了していなければ手順３０７に進む。
手順３０７において、脆弱性検出手段２０２は、これまでに探索済みのノードの次から解析木２１０を所定の順序でたどり、最初に到達した関数定義ノードを頂点とする部分解析木を手順３０８〜３１２の処理の対象とする。この部分解析木で表されるユーザ定義関数を以下では対象関数と呼ぶ。
【００５１】
図５の解析木２１０ではまず関数format_stringが対象関数となる。以降の説明では特に断らない限り、変数とは対象関数の仮引数とローカル変数、及びグローバル変数を意味する。
【００５２】
手順３０８において、脆弱性検出手段２０２は、対象関数の部分解析木を所定の順序でたどり、対象関数の仮引数や関数本体で定義されたローカル変数が見つかれば、それらを変数テーブル２０７に登録する。
【００５３】
図８は、図５に示す部分解析木の関数format_stringの仮引数（図５の５〜１１行目）について手順３０８を実施した後の変数テーブル２０７の内容である。変数（仮引数）毎に１行のデータが変数テーブル２０７に追加される。１列目は変数テーブル２０７に登録された変数の識別番号で、登録順に１から付けられる。２列目は変数の種別を表し、仮引数を登録する場合は'A'、ローカル変数なら'L'、グローバル変数なら'G'を格納する。３列目は変数の型、４列目は変数名、５列目は変数の保持する値を表す参照データ（変数参照データ）の集合（変数参照データ集合）から構成されるリスト（変数参照データ集合リスト）である。
【００５４】
図８の変数テーブル２０７の変数参照データ集合リストの要素（変数参照データ集合）の数は各変数で可能な間接参照の深さで決まる。変数が基本データ型（int型やchar型などポインタや配列でない単純なデータ型）なら要素数は１、ポインタまたは１次元配列なら２、ポインタのポインタまたは２次元配列なら３である。また、リスト内の各変数参照データ集合の位置はその変数の間接参照の繰り返し数に対応し、リストの先頭の変数参照データ集合はこの変数の値を表す変数参照データの集合、２つめの変数参照データ集合は変数の間接参照先の値を表す変数参照データの集合、３つめの変数参照データ集合は変数の間接参照先の間接参照先の値を表す変数参照データの集合である。変数の値やその間接参照先の値を変数参照データの集合とする理由は、例えば変数が複数の変数からコピーされた文字列を連結した文字列を保持する状態に対応するためである。なお、変数テーブル２０７における各変数参照データ内の数字は変数の識別番号である。
【００５５】
図８の変数テーブル２０７の変数参照データ集合リストの初期値は変数の種別により異なる。ローカル変数では、その初期化が行われていない場合、及び定数値による初期化の場合は、次のとおりである。まずローカル変数で可能な間接参照の深さごとに、そのローカル変数の変数テーブル２０７での識別番号に間接参照の深さに応じた'*'を前置した変数参照データを生成する。そして、各変数参照データを唯一つの要素とする変数参照データ集合を要素とするリストを初期値とする。なお、定数値で初期化される変数の場合、一番深い間接参照に対応する変数参照データ集合は、定数値を表す参照データ'C'を用いて'(C)'とする。例えば、ポインタのポインタであるローカル変数において、その可能な間接参照の深さは０、１、２なので、初期化されていない場合の変数参照データ集合リストの初期値は'[ (1), (*1), (**1) ]'、定数値で初期化されている場合の初期値は'[ (1), (*1), (C) ]'となる。ローカル変数の初期化に他の変数や関数呼び出しが含まれる場合、前記初期値に、初期化データを生成するための式に手順３０９の処理を加えたものとする。
【００５６】
グローバル変数の場合は、ローカル変数の場合と同じである。
【００５７】
仮引数の場合は、初期化されないローカル変数と同様の変数参照データ集合リストを初期値とする。ただし、外部入力データを渡される可能性のある仮引数については、該当する間接参照の深さの変数参照データ集合に擬似外部入力データ'PIN'を初期値に追加する。ここでの外部入力データの有無の判定は次のようにして行う。まず、変数テーブル２０７に登録しようとする仮引数の仮引数番号を取得する。この時点では解析木２１０の仮引数リストノードを頂点とする部分解析木をたどっている途中なので、登録しようとする仮引数が何番目の引数であるか、つまり仮引数番号が分かる。次に対象関数の名前をキーとして動的仮引数間遷移ＤＢ２０６を検索し、一致する行の外部入力仮引数集合を読み出す。この集合から前記仮引数番号を含む外部入力仮引数を全て取得する。そして、各外部入力仮引数について、間接参照の深さ（仮引数番号に前置された'*'の数）を求め、変数参照データ集合リスト内で左から前記深さに１を加えた位置の変数参照データ集合に'PIN'を追加する。例えば、対象関数の第２仮引数を変数テーブル２０７に登録する際、この第２引数の変数テーブル２０７内での変数識別番号が4、対象関数の名前をキーとして動的仮引数間遷移ＤＢ２０６を検索して読み出した外部入力仮引数集合が'(*1, **2)'だったとする。この集合内で、現在、処理対象の引数番号'2'を含む外部入力仮引数は'**2'であり、その間接参照の深さは２である。したがって、変数参照データ集合リストの初期値は、外部入力仮引数が無い時の初期値'[ (4), (*4), (**4) ]'の３番目の集合に'PIN'を加えた'[ (4), (*4), (**4, PIN) ]'となる。なお、関数mainの第２仮引数には必ず外部入力データが与えられるので、この第２仮引数について、変数テーブル２０７の変数参照データ集合リストの初期値は、仮にその変数識別番号が3とすると、'[ (3), (*3), (IN) ]'とする。
【００５８】
以上で説明した手順３０８を対象関数format_stringについて実施すると、図５の解析木からまずchar型へのポインタである仮引数stroutが見つかる（６〜８行目）。この時点での動的仮引数間遷移ＤＢ２０６（図７）の関数名の列内を対象関数の名前format_stringで検索すると、一致した行の外部入力仮引数集合は空である。仮引数stroutは変数テーブル２０７に登録する最初のデータなので識別番号は１となり、変数参照データ集合リストの初期値は'[ (1), (*1) ]'となる（図８の番号１の行）。続いて図５の解析木から仮引数strinが見つかって（９〜１１行目）変数テーブル２０７での識別番号が２となり、この仮引数に該当する外部入力仮引数は存在しないので、変数参照データ集合リストの初期値は'[ (2), (*2) ]'となる（図８の番号２の行）。
【００５９】
図４のソースコードの例には含まれていないが、戻り値を返す対象関数の場合、その戻り値の参照データを記録するための行も変数テーブル２０７に追加する。その種別はＡで仮引数扱い、変数型は戻り値の型、名前は'return'（Ｃ言語では予約語のため変数名に使えず、ユーザ定義変数と重複しない）、変数参照データ集合リストは戻り値の間接参照の深さに応じた空集合を並べたリスト（例えば深さが２なら、[ ( ), ( ), ( ) ]）として登録する。
【００６０】
なお、手順３０８においては、変数テーブル２０７に登録した仮引数の仮引数番号と、その仮引数を変数テーブル２０７に登録した際に割り当てられた変数識別番号の組も、仮引数ごとに記憶しておく。
【００６１】
手順３０９において、脆弱性検出手段２０２は、探索済みのノードの次から解析木２１０を所定の順序でたどり、変数の値が別の変数に移る可能性のあるノードに到達すると、そのノードを頂点とする部分解析木について、仮引数間遷移ＤＢ２０４及び動的仮引数間遷移ＤＢ２０６を参照してデータ遷移を追跡し、変数テーブル２０７を更新する。
【００６２】
変数の値が別の変数に遷移する可能性のあるノードには関数呼出しや代入文などがある。関数呼出しのノードにたどり着いたら、そのノードを頂点とする部分解析木を処理対象とする。例として図４に示すソースコードの関数format_stringについて手順３０９を実施すると、図５の解析木２１０の探索を再開後に最初に到達する、変数間での値の遷移が起きる可能性のあるノードは、関数呼出しノードである（図５の１５行目）。このノードを頂点とする部分解析木をここでの処理対象とする（同１５〜２６行目）。
【００６３】
以下、図９を用いて、関数呼出しの部分解析木を解析するときの変数テーブル更新処理（手順３０９）の詳細な手順を説明する。
【００６４】
手順９０１において、脆弱性検出手段２０２は、部分解析木内をたどって呼び出される関数の名前を取得する。図５の解析木２１０の例において、関数呼出しノードの次に到達する識別子ノード（同１６行目）のソースコード断片から、呼び出される関数の名前sprintfを得る。
【００６５】
手順９０２において、脆弱性検出手段２０２は、部分解析木をたどり、この関数呼出しの全実引数を取得して各実引数が変数であるか定数であるか調べる。図５の解析木２１０の例では、各実引数ノードから、第１実引数strout、第２実引数"input=%s"、第３実引数strinを得る。式ノードを直接の親ノードとする識別子ノードは変数を意味するので、第１実引数と第３実引数は変数であることが分かる。第２実引数に当たるノードは、文字列ノードであるので、定数値であることが分かる。
【００６６】
手順９０３において、脆弱性検出手段２０２は、先に取得した関数名をキーとして仮引数間遷移ＤＢ２０４及び動的仮引数間遷移ＤＢ２０６の関数名欄を検索し、一致する行から仮引数間遷移リストを得る。なお、各ＤＢを検索して一致行が見つからない場合（処理対象の関数呼出しに使われた関数が仮引数間遷移ＤＢ２０４に登録されてない場合）は図９の手順を終える。上記の例では、関数名sprintfをキーとして両ＤＢを検索すると、図６の仮引数間遷移ＤＢ２０４の３行目に一致する行が見つかる。そこで、この行から仮引数間遷移リスト'[*2→*1, *2→*2, *3...→*1, *3...→*3...]'を取得する。
【００６７】
手順９０４において、脆弱性検出手段２０２は、先に得た仮引数間遷移リストの左から順に仮引数間遷移エレメントを取り出して手順９０５から手順９０９の処理を行い、変数間のデータ遷移を評価する。全ての仮引数間遷移エレメントについて処理を終えたら、次に手順９１０を行う。
【００６８】
手順９０５において、脆弱性検出手段２０２は、評価対象の仮引数間遷移エレメントから遷移元参照データと遷移先参照データを取り出す。両者に仮引数番号が含まれている場合、及び遷移元参照データが'IN'で遷移先参照データが仮引数番号を含む場合、遷移先参照データに含まれる仮引数番号に該当する実引数が変数であれば、次の処理に移る。これら以外の場合、手順９０４に戻り、次の仮引数間遷移エレメントを評価対象とする。図５の例では、まず１つめの仮引数間遷移エレメント'*2→*1'について、遷移元、遷移先ともに仮引数番号が含まれるので手順９０６に移る。なお、３つめ、４つめの仮引数間遷移エレメントの場合も手順９０６に進めるが、２つめの仮引数間遷移エレメント'*2→*2'は遷移先参照データに含まれる仮引数番号に対応する実引数が定数であるので手順９０４に戻る。
【００６９】
手順９０６において、脆弱性検出手段２０２は、評価対象の仮引数間遷移エレメントについて、仮引数番号を含む遷移元参照データ及び遷移先参照データの間接参照の深さを調べる。これは仮引数番号に付加されたアスタリスク'*'を数えて求める。上記の例では、遷移元参照データ'*2'、遷移先参照データ'*1'から間接参照の深さは共に１である。
【００７０】
手順９０７において、脆弱性検出手段２０２は、遷移元参照データに仮引数番号が含まれていれば、部分解析木内の該当する実引数の参照データ集合を取得する。仮引数番号に対応する実引数が変数であれば、その変数の名前をキーとして変数テーブル２０７の名前欄を検索し、一致する行の変数参照データ集合リストを得る。このリスト内から、先に求めた遷移元の間接参照の深さに対応する変数参照データ集合（以下、遷移元変数参照データ集合と呼ぶ）を取り出す。仮引数番号に対応する実引数が定数であれば'(C)'を遷移元変数参照データ集合とする。遷移元参照データに可変長仮引数を表す'...'が含まれているため実引数に該当する変数や定数が複数ある場合、それら全てについて上記処理を行い、その結果の和集合（ただし要素の重複を許さない）を遷移元変数参照データ集合とする。遷移元参照データが'IN'であれば、'(IN)'を遷移元変数参照データ集合とする。上記の例では、遷移元参照データ'*2'から遷移元が第２引数と分かり、これは定数値であるので'(C)'を遷移元変数参照データ集合とする。
【００７１】
手順９０８において、脆弱性検出手段２０２は、呼び出される関数がユーザ定義関数であり、かつ遷移元変数参照データ集合に'IN'または'PIN'が含まれている場合、呼び出される関数に外部入力データが渡されることを記録するため、この関数について動的仮引数間遷移ＤＢ２０６の外部入力仮引数集合を更新する。先に取得した呼び出される関数の関数名をキーとして動的仮引数間遷移ＤＢ２０６を検索し、一致する行の外部入力仮引数集合に遷移元参照データが含まれていなければ、この遷移元参照データそのものを外部入力仮引数集合に追加する。上記の例では該当する場合がないので具体例の説明は省略する。
【００７２】
手順９０９において、脆弱性検出手段２０２は、遷移先参照データに含まれる仮引数番号に対応する実引数の変数の名前をキーとして変数テーブル２０７の名前欄を検索して一致する行を探し、その変数識別番号を得る。そして、この変数識別番号と手順９０６で得た遷移先参照データの間接参照の組に、手順９０７で得た遷移元変数参照データ集合をさらに組にして、暫定遷移先変数参照データ集合として一時的に記憶する。暫定遷移先変数参照データ集合は遷移先（変数識別番号と間接参照の深さの組）毎に作成する。なお、同一の遷移先（変数識別番号と間接参照の深さの組）に複数のデータ遷移が存在する場合には、新たな遷移元変数参照データ集合が得られる度に暫定遷移先変数参照データ集合内の遷移元変数参照データ集合に連結する。上記の例では、遷移先実引数の変数の名前stroutをキーとして図８の変数テーブル２０７の名前欄を検索し、一致した行の番号欄からその変数識別番号１を得る。また先に得た遷移先の間接参照の深さは１である。これらの組に先に得た遷移元変数参照データ集合'(C)'をさらに組にして一時的に記憶する。この暫定遷移先変数参照データ集合を、便宜的に、遷移先変数の変数識別番号、その関節参照の深さ、遷移元変数参照データ集合の順に'(1, 1, (C))'と記述する。上述の手順９０９の後、手順９０４に戻る。
【００７３】
ここまでの処理で、上記の例では、３つめの仮引数間遷移エレメントを処理する際に１つめと同じ変数識別番号と間接参照の深さの組からなる暫定遷移先変数参照データ集合を得るので、これらをマージした暫定遷移先変数参照データ集合は'(1, 1, (C, *2))'を得る。４つめの仮引数間遷移エレメントの処理から得られる暫定遷移先変数参照データ集合は'(2, 1, (*2))'である。
【００７４】
手順９１０において、脆弱性検出手段２０２は、暫定遷移先変数参照データ集合のそれぞれについて以下の処理を行い、変数テーブル２０７を更新する。暫定遷移先変数参照データ集合から遷移先変数の変数識別番号を取得し、これをキーとして変数テーブル２０７の番号欄を検索して一致した行から変数参照データ集合リストを得る。このリストについて、暫定遷移先変数参照データ集合から得られる間接参照の深さに対応する位置に、同じく暫定遷移先変数参照データ集合から得られる遷移元変数参照データ集合を上書きする。この結果として得られる新たな変数参照データ集合リストを変数テーブル２０７の元の場所に上書きして、次の暫定遷移先変数参照データ集合の処理に移る。全ての暫定遷移先変数参照データ集合について上記処理を終えたら、手順３０９における変数テーブル２０７の更新処理を終了する。例えば、上記の例において図８の変数テーブル２０７を更新すると、上記１つめの暫定遷移先変数参照データ集合'(1, 1, (C, *2))'について、遷移先変数の変数識別番号１を得る。これをキーとして図８の変数テーブル２０７の番号欄を検索し、一致した行の変数参照データ集合リスト'[ (1), (*1) ]'を得る。また上記１つめの暫定遷移先変数参照データ集合から遷移先変数の間接参照の深さ１を得る。これに対応する上記変数参照データ集合リストの２番目の位置に、さらに上記１つめの一時記憶データから得た遷移元変数参照データ集合'(C, *2)'を上書きし、'[ (1), (C, *2) ]'を得る。この結果を図８の変数テーブル２０７の元の位置に上書きする。同様に、上記２つめの暫定遷移先変数参照データ集合について処理を行うと、図８の変数テーブル２０７の番号２の行の変数参照データ集合リストの２番目の要素を遷移元変数参照データ集合'(*2)'で上書きし、さらに図８の変数テーブル２０７の元の位置に上書きする。以上で変数テーブル２０７の更新処理を終了する。更新後の変数テーブル２０７を図１０に示す。
【００７５】
以上で図９の説明を終える。
【００７６】
図９の処理手順は関数呼出しの場合であるが、代入文など演算子を介した変数の更新処理についても、その部分解析木が前記sprintf関数呼出しについての部分解析木（図５の１５〜２６行目）と同様に構築されるので、ほぼ同じ手順で処理できる。
【００７７】
例えばポインタの代入'p=q'の場合（変数p、qはchar*型とする）、左辺の仮引数番号を1、右辺の仮引数番号を2として、その仮引数間遷移リストは'[2→1, →*1, *2→*2]'である。代入後はポインタがコピーされ変数pの間接参照先は変数qと同じなので、前記リストではポインタ自身のコピー（'2→1'）と、変数pの間接参照先のクリア（'→*1'）を指示している。仮にchar*型のポインタ変数a、bについてポインタの代入'a=b'を処理する際、代入前の変数テーブル２０７が図１１の状態であれば、代入後は図１２のように更新され、変数aの間接参照先に当たる変数参照データ集合は空集合となる。なお、変数aがこの状態のときに変数aの間接参照先の参照データが関数呼出しや代入文の処理において必要とされた場合、空の変数参照データ集合より間接参照が一つ浅い（図１２においては変数参照データ集合リスト内の左隣の）集合内の変数識別番号を取り出す。そして、この番号で識別される変数の変数参照データ集合リスト内から元々必要とされた間接参照の深さの変数参照データ集合を読み出して使用する。これも空集合であれば、空集合でないものが見つかるまで上記処理を繰り返す。
【００７８】
また、関数呼出しの実引数や演算子の演算対象として別の関数呼出しや演算子による演算の結果が使われる場合、その結果を一時的なローカル変数の値とみなして変数テーブル２０７に登録し、この結果が返される位置に該当する部分解析木内のノードを上記一時ローカル変数のノードとみなすことで、手順３０９の処理手順を適用して変数テーブル２０７を更新できる。
【００７９】
return文で変数の値が返される場合、変数テーブル２０７に変数名returnとして登録した行の変数参照データ集合リストに、前記変数の変数参照データ集合リストをマージする。この際、同一の間接参照の深さごとに両者の変数参照データ集合の和集合を取り、その結果を変数名returnの新たな変数参照データ集合リストとする。return文で定数値が返される場合は'(C)'をマージする。
【００８０】
再び図３に戻って、手順３１０において、脆弱性検出手段２０２は、対象関数の部分解析木の探索が終了していれば手順３１１に、終了していなければ手順３０８に戻る。
【００８１】
手順３１１において、脆弱性検出手段２０２は、変数テーブル２０７の内容に基づき、対象関数について動的仮引数間遷移ＤＢ２０６の内容を更新する。対象関数の仮引数それぞれについて、その仮引数の変数参照データ集合リストを変数テーブル２０７から取得して仮引数間遷移エレメントを生成し、最後にそれらエレメントを連結して仮引数間遷移リストとする。
【００８２】
手順３１１での処理の詳細を説明する。まず、変数テーブル２０７の種別欄で種別が'A'（仮引数）となっている行を選び、その変数識別番号をすべて取得する。本実施形態では対象としているＣ言語では入れ子の関数定義が許されていないので、変数テーブル２０７に仮引数として登録されているものは対象関数の仮引数のみである。
【００８３】
取得した変数識別番号のそれぞれについて以下の処理を行う。まず、変数テーブル２０７から処理対象の変数識別番号の行の変数参照データ集合リストを取り出す。そして、リスト内の変数参照データ毎に仮引数間遷移エレメントを生成する。その遷移元参照データには、手順３０８の処理で記憶した仮引数番号と変数識別番号の組を参照して、処理対象の変数参照データに含まれる変数識別番号を仮引数番号に変換した参照データを用いる。遷移先参照データには、同様に仮引数番号と変数識別番号の組を参照して処理対象の変数識別番号を仮引数番号に変換したものに、処理対象の変数参照データが含まれる変数参照データ集合の表す間接参照の深さを組み合わせた、参照データを用いる。なお、変数参照データ集合が空集合の場合、仮引数間遷移エレメントの遷移元参照データは無しとする。また、処理対象の変数参照データにローカル変数の変数識別番号や擬似外部入力データを表す'PIN'や定数値を表す'C'が含まれる場合は無視し、グローバル変数が含まれる場合はその変数識別番号に'G'をつけて仮引数間遷移エレメントに含める。
【００８４】
以上のように生成した仮引数間遷移エレメントを全て連結して対象関数の新たな仮引数間遷移リストを構成する。対象関数の名前をキーとして動的仮引数間遷移ＤＢ２０６を検索し、一致する行の仮引数間遷移リストを更新する。なお、遷移元参照データ及び遷移先参照データに含まれる仮引数番号が同一で、かつ両者の間接参照の深さが0の仮引数間遷移エレメントは仮引数間遷移リストに連結しない。
【００８５】
上述の手順３１１の処理を図１０の変数テーブル２０７について行うと、種別欄が'A'である行は変数識別番号が1と2のものである。まず変数識別番号１の行について、変数参照データ集合リスト'[ (1), (C, *2) ]'を取り出す。最初の変数参照データ'1'に関して生成される仮引数間遷移エレメントは'1→1'、２つめの変数参照データ'*2'に関して生成される引数遷移エレメントは定数を表す'C'を無視して'*2→*1'となる。同様に、変数識別番号2の行について、生成される仮引数間遷移エレメントは順に'2→2'、'*2→*2'である。これらを連結して構成される新たな仮引数間遷移リストは、連結対象から除外する場合を考慮して、'[*2→*1, *2→*2]'となる。この結果、動的仮引数間遷移ＤＢ２０６は図１３のように更新される。
【００８６】
手順３１２において、脆弱性検出手段２０２は、対象関数に係わる仮引数とローカル変数についての登録データを変数テーブル２０７から削除する。
【００８７】
なお、グローバル変数について変数テーブル２０７に登録された変数参照データ集合リストに、ポインタの代入処理などのためローカル変数や仮引数の変数識別番号を含む参照データが含まれている場合、その変数識別番号について変数テーブル２０７を参照し、その参照データの間接参照の深さに対応する変数参照データ集合と置き換える。
【００８８】
なお、本実施形態の説明では簡略化のため変数のスコープを考慮していないが、ローカル変数と仮引数の変数テーブル２０７への登録はそのスコープに入ったとき、削除はスコープの外に出たときに行う。解析木２１０を所定の順序でたどり、変数定義または変数宣言のノードがあればその変数のスコープが始まる。解析木２１０内でのこのノードの深さを変数テーブル２０７に記録して解析木２１０の探索を続け、探索中のノードの深さが変数テーブル２０７に登録したものより浅くなれば前記変数はスコープから外れたと分かるので、変数テーブル２０７から該当データを削除すればよい。
【００８９】
以上で、１つの対象関数についての処理が終わり、手順３０６に戻る。
【００９０】
図４のソースコードについて引き続き手順３０６〜３１２を実施すると、動的仮引数間遷移ＤＢ２０６及び変数テーブル２０７は次のように更新される。
【００９１】
図４のソースコードの関数get_inputについて手順３０８終了時の変数テーブル２０７は、図１４である。
【００９２】
同関数について手順３０９終了時の変数テーブル２０７は図１５に更新され、動的仮引数間遷移ＤＢ２０６は図１３のままである。ここでは関数getsの呼出しについて、仮引数間遷移ＤＢ２０４を基に、図１４の変数テーブル２０７に登録された変数inの変数参照データ集合リストが更新されている。
【００９３】
同関数について手順３１１終了時の動的仮引数間遷移ＤＢ２０６は図１６に更新される。ここでは図１５の変数テーブル２０７を基に、図１３の動的仮引数間遷移ＤＢ２０６内の関数get_inputについての仮引数間遷移リストが更新されている。
【００９４】
図４のソースコードの関数put_inputについて手順３０８終了時の変数テーブル２０７は、図１７である。
【００９５】
同関数について手順３０９終了時の変数テーブル２０７は図１７のまま、動的仮引数間遷移ＤＢ２０６も図１６のままである。
【００９６】
同関数について手順３１１終了時の動的仮引数間遷移ＤＢ２０６は、図１６のままである。
【００９７】
図４のソースコードの関数mainの１８行目について手順３０８終了時の変数テーブル２０７は、図１８である。ここでは関数mainについて動的仮引数間遷移ＤＢ２０６に登録された外部入力仮引数集合を参照すると、第２仮引数に外部入力データが与えられている。したがって、第２仮引数argvについて変数テーブル２０７に登録される変数参照データ集合リストには、その参照の深さ２に対応する変数参照データ集合の初期値に'(IN)'が設定されている。
【００９８】
同関数の１９行目について手順３０９終了時の変数テーブル２０７は図１９に更新され、動的仮引数間遷移ＤＢ２０６は図１６のままである。ここでは図１８の変数テーブル２０７に登録されている変数inbufの変数参照データ集合リストが、ユーザ定義関数get_inputの呼出しについて図１６の動的仮引数間遷移ＤＢ２０６に従い更新されている。
【００９９】
同関数の２０行目について手順３０９終了時の変数テーブル２０７は図２０に更新され、動的仮引数間遷移ＤＢ２０６は図２１に更新される。ここでは、図１９の変数テーブル２０７に登録されている変数outbufの変数参照データ集合リストが、ユーザ定義関数format_stringの呼出しについて図１６の動的仮引数間遷移ＤＢ２０６に従い更新されている。また、同変数テーブル２０７に登録されている変数inbufの変数参照データ集合リストに'IN'が含まれているので、ユーザ定義関数format_stringについて図１６の動的仮引数間遷移ＤＢ２０６に登録された外部入力仮引数集合が図２１に更新されている。
【０１００】
同関数の２１行目について手順３０９終了時の変数テーブル２０７は図２０のままで、動的仮引数間遷移ＤＢ２０６は図２２に更新される。図２０の変数テーブル２０７に登録されている変数outbufの変数参照データ集合リストに'IN'が含まれているので、同関数について図２１の動的仮引数間遷移ＤＢ２０６に登録された外部入力仮引数集合が図２２に更新されている。
【０１０１】
手順３１１は、同関数が仮引数間遷移ＤＢ２０４に登録されているため、実施しない。
【０１０２】
以上で図５の解析木２１０の探索が終わるので手順３０４に戻る。現在の動的仮引数間遷移ＤＢ２０６（図２２）は前回の手順３０４の実施時のそれ（図７）と異なるので、手順３０５〜３１２を再び実施する。
【０１０３】
図４のソースコードの関数format_stringについて２回目の手順３０８終了時の変数テーブル２０７は、図２３である。ここでは同関数について図２２の動的仮引数間遷移ＤＢ２０６に登録された外部入力仮引数集合に基づき、変数テーブル２０７に登録される仮引数strinの変数参照データ集合リストの初期値に擬似外部入力データ'PIN'が含まれている。
【０１０４】
同関数について２回目の手順３０９終了時の変数テーブル２０７は図２４に更新され、動的仮引数間遷移ＤＢ２０６は図２２のままである。ここでは関数sprintfの呼出しについて仮引数間遷移ＤＢ２０４に基づき、図２３の変数テーブル２０７の変数stroutの変数参照データ集合リストが図２４に更新されている。
【０１０５】
同関数について２回目の手順３１１終了時の動的仮引数間遷移ＤＢ２０６は、図２２のままである。１回目の同手順実施時とは異なり変数参照データ集合リストに'PIN'が含まれているが、仮引数間遷移リストの生成には利用されないので、図２２の動的仮引数間遷移ＤＢ２０６は更新されない。
【０１０６】
図４のソースコードの関数get_inputについて２回目の手順３０６〜３１２を実施時の変数テーブル２０７の変化の様子は１回目のそれと同じである（図１４）。そのため、同関数について動的仮引数間遷移ＤＢ２０６に登録される仮引数間遷移リストも１回目のそれと変わらず、図２２の動的仮引数間遷移ＤＢ２０６がそのまま維持される。
【０１０７】
図４のソースコードの関数put_inputについて２回目の手順３０８終了時の変数テーブル２０７は、図２５である。ここでは、同関数について図２２の動的仮引数間遷移ＤＢ２０６に登録された外部入力仮引数集合に基づき、変数テーブル２０７に登録される仮引数outの変数参照データ集合リストの初期値に擬似外部入力データ'PIN'が含まれている。
【０１０８】
同関数について２回目の手順３０９終了時の変数テーブル２０７は図２５のまま、動的仮引数間遷移ＤＢ２０６も図２２のままである。
【０１０９】
同関数について２回目の手順３１１終了時の動的仮引数間遷移ＤＢ２０６は、図２２のままである。
【０１１０】
図４のソースコードの関数mainについて２回目の手順３０６〜３１２を実施時の変数テーブル２０７の変化の様子は１回目のそれと同じである（図１８〜２１）。そのため、同関数について動的仮引数間遷移ＤＢ２０６に登録される仮引数間遷移リストも１回目のそれと変わらず、図２２の動的仮引数間遷移ＤＢ２０６がそのまま維持される。
【０１１１】
以上で図５の解析木２１０の２回目の探索が終わるので手順３０４に戻る。現在の動的仮引数間遷移ＤＢ２０６（図２２）は前回の手順３０４の実施以降で更新されていないので、手順３１３に移る。
【０１１２】
手順３１３において、脆弱性検出手段２０２は、脆弱性ＤＢ２０５を読込む。
【０１１３】
脆弱性ＤＢ２０５の例を、図２６に示す。１列目は脆弱性を生じる可能性のある関数の名前である。２列目は外部入力データが与えられると脆弱性を生じる可能性のある仮引数を参照データ形式でリスト化した脆弱仮引数リストで、数字は仮引数番号である。
【０１１４】
手順３１４において、脆弱性検出手段２０２は、解析木２１０をルートノードから所定の順序でたどり、脆弱性ＤＢ２０５の脆弱性仮引数リストに登録された仮引数に'IN'または'PIN'を含む変数が与えられる箇所を脆弱性検査結果２０９として出力する。
【０１１５】
手順３１４では、これまでに構築された動的仮引数間遷移ＤＢ２０６と変数テーブル２０７に基づき、手順３０５〜３１２を実施する。ただし、動的仮引数間遷移ＤＢ２０６の更新に関する手順（手順３１１、及び手順３０９の処理を詳細化した図９の手順９０８）は省略する。また、手順９１０の処理の直前において、脆弱性ＤＢ２０５を参照して脆弱性検出ルールに合致する場合は脆弱性の恐れを指摘する、脆弱性検知手順を実施する。
【０１１６】
前記脆弱性検知手順の処理は次のようなものである。まず、手順９０１で取得した、呼び出される関数の名前をキーとして図２６の脆弱性ＤＢ２０５の関数名欄を検索する。一致する関数が見つからなければ脆弱性検知手順を終了する。見つかれば、その行の脆弱性仮引数リストを読込む。次に手順９０５〜９０７と同様の処理を行い、脆弱性仮引数リスト内の各仮引数参照データに対応する実引数について、その参照データを変数テーブル２０７から読込む。この参照データに外部入力データを表す'IN'、または擬似外部入力データを表す'PIN'が含まれていれば、脆弱性を生じる恐れがあるとして脆弱性検査結果２０９として出力する。
【０１１７】
図４のソースコードについて前記脆弱性検知手順を実施する場合を説明する。
【０１１８】
図４のソースコードの３行目の関数sprintfの関数呼出しについて前記脆弱性検知手順を実施する直前の変数テーブル２０７の状態は図２３、動的仮引数間遷移リスト２０６の状態は図２２である。まず、関数名sprintfで図２６の脆弱性ＤＢ２０５の関数名欄を検索し、その一致する行の脆弱仮引数リスト'[*2, *3...]'を読込む。同リスト内の仮引数参照データ'*2'に対応する実引数は"input=%s"なので、この参照データは存在しない。同リスト内の次の仮引数参照データ'*3...'に対応する実引数は変数strinで、前記仮引数参照データの間接参照の深さが1であることから、前記変数strinの変数参照データ集合を図２３の変数テーブル２０７から取得すると'(*2, PIN)'である。この変数参照データ集合には'PIN'が含まれているので、前記関数sprintfの関数呼出しは脆弱性を生じる可能性があり、この旨を脆弱性検査結果２０９として出力する。
【０１１９】
図４のソースコードの８行目の関数getsの関数呼び出しについて同様に前記脆弱性検知手順を実施する直前の変数テーブル２０７の状態は図１４、動的仮引数間遷移リスト２０６の状態は図２２である。関数getsについて脆弱性ＤＢ２０５に登録されている脆弱仮引数リストを読込むと'[ ]'を得る。同リストが空の場合、前記関数呼出しがいつでも脆弱であることを意味する。したがって、前記関数getの関数呼出しは脆弱性を生じる可能性があり、この旨を脆弱性検査結果２０９として出力する。
【０１２０】
図４のソースコードの１３行目の関数putsの関数呼び出しについて同様に前記脆弱性検知手順を実施する直前の変数テーブル２０７の状態は図２５、動的仮引数間遷移リスト２０６の状態は図２２である。関数putsについて脆弱性ＤＢ２０５に登録されている脆弱性仮引数リストを読込むと'[*1]'を得る。この参照データに対応する実引数は変数outで、前記参照データの間接参照の深さが1である。これらに該当する変数参照データ集合を図２５の変数テーブル２０７から読込むと'(*1, PIN)'を得る。この変数参照データ集合には'PIN'が含まれているので、前記関数putsの関数呼出しは脆弱性を生じる可能性があり、この旨を脆弱性検査結果２０９として出力する。
【０１２１】
以上で、本実施形態における基本的な手順の説明を全て終える。
【０１２２】
次に、検査対象ソースコード２０８に条件分岐やループが存在した場合の処理を以下で説明する。
【０１２３】
if文やswitch文による条件分岐では、条件式の評価結果により、分岐処理Ａ、分岐処理Ｂ、分岐処理Ｃ、…のいずれか１つが実行される。if文により条件分岐する検査対象ソースコード２０８の例を図２７に、このソースコードから構文解析手段２０１により生成された解析木２１０の例を図２８に示す。これらの図を用いてif文の場合の処理を説明する。
【０１２４】
脆弱性検出手段２０２は、手順３０９において図２７の検査対象ソースコード２０８から構築された図２８の解析木２１０を所定の順序でたどり条件分岐のノードに到達したら、この条件分岐ノードを頂点とする部分解析木について以下の処理を行う。まず前記部分解析木を所定の順序でたどり、１つめの式ノード(図２８の４行目)について手順３０９を適用する。続いて、この時点での動的仮引数間遷移ＤＢ２０６、変数テーブル２０７の複製を作成する。そして、図２８の解析木２１０を所定の順序でたどり、次に現れる２つめの式ノード（図２８の５行目）を頂点とする解析木２１０について、手順３０８〜３１０を適用して前記複製元の動的仮引数間遷移ＤＢ２０６、変数テーブル２０７を更新する。図２８の解析木２１０を所定の順序でたどりＥＬＳＥノードに到達したら、さらにその次に現れる３つめの式ノード(図２８の７行目)を頂点とする解析木２１０について、手順３０８〜３１０を適用して前記複製された動的仮引数間遷移ＤＢ２０６及び変数テーブル２０７を更新する。図２８の解析木２１０を所定の順序でたどり、前期３つめの式ノードを頂点とする解析木２１０をたどり終えたら、前記複製元の動的仮引数間遷移ＤＢ２０６及び変数テーブル２０７と、前記複製された動的仮引数間遷移ＤＢ２０６及び変数テーブル２０７とを、それぞれマージする。動的仮引数間遷移ＤＢ２０６のマージでは、同一の関数名を持つ行ごとに、仮引数間遷移リスト同士、外部入力仮引数集合同士を重複する要素を除いて連結する。変数テーブル２０７のマージでは、同一の変数識別番号を持つ行ごとに、変数参照データ集合リスト内の同一の間接参照の深さである変数参照データ集合同士を重複する要素を除いて連結する。
【０１２５】
switch文の場合、脆弱性検出手段２０２は、その条件式に対して手順３０９を適用した後、それぞれの分岐処理毎に動的仮引数間遷移ＤＢ２０６、変数テーブル２０７の複製を用意して手順３０９を適用して更新処理を行い、それらの結果をマージして新たな動的仮引数間遷移ＤＢ２０６、変数テーブル２０７とする。
【０１２６】
for文、while文、do-while文によるループの場合、脆弱性検出手段２０２はその条件式（for文の場合は初期化と更新の式も含む）及びループ本体に対し一度だけ手順３０９を適用し、動的仮引数間遷移ＤＢ２０６、変数テーブル２０７を更新する。
【０１２７】
上記第１の実施形態では脆弱性ＤＢ２０５に登録された関数を直接呼び出す箇所のみ脆弱性として検出しているが、そのような箇所を含むユーザ定義関数を呼び出す箇所も脆弱性として指摘することも上記第１の実施形態の手順を一部修正することで可能である。
【０１２８】
その一つの方法は、上記のようなユーザ定義関数と外部入力データを受け取ることのある仮引数を組にして記憶し、その使用箇所を手順３１４と同様の処理で検出するというものである。
【０１２９】
また別の方法は、ユーザ定義関数のそれぞれの仮引数について、そのユーザ定義関数の呼出し箇所における実引数の参照データの種類を、外部入力データ'IN'、擬似外部入力データ'PIN'、その他に分類して動的仮引数間遷移ＤＢ２０６に記憶しておく。手順３０４において同ＤＢの更新がなくなったときに、その他に分類された参照データを受け取ることのない仮引数を持ち、かつその仮引数で受け取った外部入力データの使用により脆弱性として検出される箇所を内部に持つユーザ定義関数について、その関数名と仮引数を組にして記憶し、その使用箇所を手順３１４と同様の処理で検出するというものである。
【０１３０】
以上で、第１の実施形態の説明を終える。
【０１３１】
次に第２の実施形態について説明する。第２の実施形態のソースコード脆弱性検査装置の構成は、第１の実施の形態で説明した図１と同じであるので、構成の説明は省略する。ただし、各変数や仮引数の保持する値の表記方法などは第１の実施形態とは異なる。
【０１３２】
図２９は、第２の実施形態のソースコード脆弱性検査装置の備える機能構成図である。本実施形態のソースコード脆弱性検査装置は、ソースコード検査手段２０１、固定関数遷移ＤＢ２９０２、脆弱遷移先ＤＢ２９０３、不定関数遷移ＤＢ２９０４、及び変数ＤＢ２９０５を備える。ソースコード検査手段２０１は、ソースコードの構文を解析する構文解析手段２９1１、及び脆弱な箇所を検出する脆弱性検出手段２９1２を備える。
【０１３３】
図３０は、あらかじめ登録された脆弱遷移先ＤＢ２９０３の例である。１列目は脆弱遷移先、２列目は脆弱回避値である。
【０１３４】
図３１は、固定関数遷移ＤＢ２９０２の例である。固定関数遷移ＤＢ２９０２は、標準ライブラリ関数などのデータ遷移をあらかじめ登録したデータベースである。１列目は関数名、２列目はどの値がどこに遷移するかを示すデータ遷移のリストである。データ遷移は、矢印'→'を用いて表記し、'→'の左を遷移元、'→'の右を遷移先とする。遷移元には、後述する変数ＤＢ２９０５に正の整数で登録される第何引数かを表す引数番号、外部から入力されたデータに由来するデータを表すIN、脆弱性を回避する処理を経たことを示す脆弱性回避値のいずれか、もしくはこれらの組み合わせが設定される。遷移先には、引数番号、グローバル変数の変数番号、戻り値を表すR、脆弱性を生じる可能性のある遷移先である脆弱遷移先のいずれかが設定される。
【０１３５】
図３２は、不定関数遷移ＤＢ２９０４の例である。不定関数遷移ＤＢ２９０４には、プログラマが定義した関数についてのデータ遷移情報を、ソースコード解析中に登録する。これは、固定関数遷移ＤＢ２９０２と同様の構造であるが、新たに解析を終了したかどうかを表すための解析済みフラグの項目を追加している。解析済みフラグは0か1の値をとり、解析済みフラグが0である関数は、後述の手順３４０６から３４１２までの解析が終了していないことを表し、一方１である関数は前記解析が終了していることを表す。初期値は0とする。以下、前記解析が終了していない関数の状態を未解析であると呼ぶ。不定関数遷移ＤＢ２９０４で遷移先に設定され得る値には、固定関数遷移ＤＢ２９０２の場合に設定され得る値に加え、後述する変数ＤＢ２９０５に負の整数で登録されるグローバル変数の変数番号がある。遷移値には、手順３４０１終了時、初期値DEFが与えられている。この値は、後述の手順３４０６または手順３４０８にて更新される。
【０１３６】
図３３は、変数ＤＢ２９０５の例である。１列目は変数ＤＢ２９０５に登録された変数の識別番号である。この変数番号は、グローバル変数の場合、負の整数値で−１、−２と降順に付ける。仮引数の場合、引数番号と一致する正の整数値を付ける。ローカル変数の場合、既に登録されている仮引数の変数番号に続くように昇順に付ける。正の整数値が一つも登録されていない場合、１から順に昇順に付ける。２列目は変数の種別を表し、仮引数を登録する場合は'A'、ローカル変数なら'L'、グローバル変数なら'G'を格納する。３列目は変数名である。４列目は変数の保持する値であり、初期値は変数番号と同一の値とする。値が定数の場合は、Cとする。
【０１３７】
図３４は、本実施形態のソースコード脆弱性検査装置の処理手順である。以下の処理で、関数定義、代入、及び関数呼び出しなどのソースコード中の構文の解析は、構文解析手段２９１１が行う。
【０１３８】
ソースコード検査プログラムが起動されると、与えられたソースコードを全てたどり、見つかったプログラマ定義関数を不定関数遷移ＤＢ２９０４に、グローバル変数を変数ＤＢ２９０５に、それぞれ登録する。グローバル変数の変数番号は、負の整数値で−１から降順に付ける（手順３４０１）。
【０１３９】
次に、ソースコードの先頭を探索開始位置にする（手順３４０２）。複数のファイルで構成されるソースコードを検査する場合、検査するファイルの順序を決めておき、その先頭を探索開始位置にする。次に、ソースコード中から、未解析である関数定義を探索する（手順３４０３）。未解析の関数が無い場合は後述する手順３４１３に移る（手順３４０３）。該当関数が見つかれば、次に、該当関数の定義の中で、未解析の関数呼び出しが行われていないかを探索する（手順３４０４）。未解析の関数呼び出しが行われている場合、探索開始位置をソースコード中の次の関数定義位置に移し（手順３４０５）、手順３４０３に戻る。未解析の関数呼び出しが行われていない場合、本関数を処理対象関数とし、解析を開始する（手順３４０６）。
【０１４０】
まず、対象関数の仮引数があればそれを変数ＤＢ２９０５に登録する（手順３４０７）。このとき、仮引数の変数番号は、その引数番号と一致するように登録する。対象関数内で定義されたローカル変数が見つかれば、それらを変数ＤＢ２９０５に登録する（手順３４０８）。変数番号は、正の整数で昇順に付ける。
【０１４１】
さらに、関数呼び出し箇所があれば、関数名で固定関数遷移ＤＢ２９０２および不定関数遷移ＤＢ２９０４を探索し、該当関数の遷移値を取得する。遷移値がＤＥＦである場合、手順３４１０へ進む。そうでない場合、次に記す処理を行う。呼び出された関数が引数を持つ関数である場合、実引数の値を取得する。関数呼び出しに伴う遷移の遷移元が正の整数（引数番号）である場合、その遷移元を引数番号に相当する実引数値に修正後、以下の処理を行う。遷移元が負の整数（グローバル変数の変数番号）である場合、変数ＤＢ２９０５から該当する変数値を参照し、その値に修正した後、以下の処理を行う。それ以外の場合、何もせず以下の処理を行う。
【０１４２】
データ遷移の遷移先の値に応じて次の処理を行う（手順３４０９）。まず、遷移先が変数番号のデータ遷移の箇所があれば、変数ＤＢ２９０５の該当する変数値を更新する。遷移先が脆弱遷移先ＤＢ２９０３の脆弱遷移先のいずれかに合致し、遷移元が変数種別'A'または'G'の変数番号のデータ遷移があれば、不定関数遷移ＤＢ２９０４に追加する。遷移先が脆弱遷移先ＤＢ２９０３の脆弱遷移先のいずれかに合致し、遷移元にINを含み、脆弱遷移先に対応する脆弱性回避値を含まないデータ遷移があれば、不定関数遷移ＤＢ２９０４に追加すると共に、ソース中の該当箇所への警告を検査結果として出力する。
【０１４３】
なお、代入文についても、右辺→左辺のデータ遷移として、関数呼び出しと同様に処理する。
【０１４４】
対象関数の処理を終えるまで、手順３４０８、３４０９を繰り返す。対象関数の処理を終えたら、解析済みフラグを１に設定し、手順３４１１に移る（手順３４１０）。
【０１４５】
変数ＤＢ２９０５の種別欄で種別が'A'（仮引数）または'G'(グローバル変数)となっている行を選び、その値を取得する。値がINまたは、それ自身以外の変数番号でかつ種別が'A'または'G'である場合、それぞれINまたは変数番号を遷移元とし、該当行の変数番号を遷移先とする遷移を不定関数遷移ＤＢ２９０４に登録する（手順３４１１）。
【０１４６】
変数ＤＢ２９０５から仮引数とローカル変数についての登録データを削除する。グローバル変数の値を初期化する（手順３４１２）。対象関数についての処理を終え、手順３４０３に戻る。
【０１４７】
手順３４１３では不定関数遷移ＤＢ２９０４に、前回解析時と比較して、グローバル変数を遷移先とする新たな遷移値の登録があるかどうかを調べる。該当する遷移値の登録がある場合、不定関数遷移ＤＢ２９０４の解析済みフラグの値をすべて０に初期化し、手順３４０３へ戻る。一方、無い場合は処理を終了する。
【０１４８】
後述する検査対象ソースコードにポインタ変数の遷移がないため、記述していないが、変数ＤＢ２９０５に参照の深さと参照値を加えることと、固定関数遷移ＤＢ２９０２および不定関数遷移ＤＢ２９０４の遷移値に設定できるものの一つにこの参照値を加えることと、手順３４０９で遷移元がポインタ変数の変数番号である場合、変数リストから、その値を取得し、遷移元を修正すること、を行うことでポインタ変数の遷移に対応できる。
【０１４９】
以上で図３４の説明を終える。
【０１５０】
図４６は、本実施形態のソースコード脆弱性検査装置を説明するための検査対象ソースコードである。Ｃ言語で記述されており、説明の便宜上一番左に行番号を記述している。sanitizeOs関数の定義を省いているが、含めても以下の結果は変わらない。
【０１５１】
まず、従来のパターンマッチング法を、図４６のソースコードに適用した場合について説明する。パターンマッチング法による検査では、関数に渡されるデータが外部由来かどうかを判断することなく、あらかじめ登録された脆弱性を生じる可能性のあるライブラリ関数使用箇所のすべてを検出するため、２２行目のOSコマンドインジェクションを生じる可能性のあるライブラリ関数であるsystem関数に対し、警告が出力される。しかし、system関数は直接main関数から呼ばれることはなく、call_do_system関数を通して呼ばれており、system関数が実行される５行目、８行目、１２行目の３箇所のうち、８行目の一箇所だけが実際に脆弱である。５行目は、扱うデータが外部由来ではない。また、１２行目は、扱うデータが事前に適切な脆弱性回避処理がなされたデータである。プログラマは、パターンマッチング法を用いた脆弱性検査を行った後、このように警告箇所が実際に脆弱であるかを、自ら目視で判断する必要がある。
【０１５２】
また、プログラマが脆弱性の警告への対処として行う脆弱性回避処理は、目視で実際に脆弱であると判断された箇所で行う必要がある。もし、警告された22行目の直前でその扱うデータに対し脆弱性回避処理を施すと、８行目で脆弱性回避処理を行う必要のないデータに対し脆弱性回避処理が行われ、１２行目で二重に脆弱性回避処理が行われることになり、この２箇所で想定外の動作が生じる可能性がある。
【０１５３】
次に図４６のソースコードに対して、３４の処理を適用した場合の処理を説明する。図３２は、手順３４０１終了時の不定関数遷移ＤＢ２９０４の例を示し、検査対象ソースコードに定義されている関数が登録されている。この検査対象ソースコードにはグローバル変数は定義されていない。
【０１５４】
手順３４０１，３４０２の後、ソースコードの先頭から未解析の関数を探索し、main関数が検出される（手順３４０３）。main関数の定義内で、未解析の関数呼び出しの有無の検査を行う（手順３４０４）。５行目でcall_do_system関数が呼ばれており、不定関数遷移ＤＢ２９０４より解析済みフラグが0であることが分かる（手順３４０４）。すなわち未解決の関数呼び出しが行われているので、探索開始位置を次の関数定義に移す（手順３４０５）。
【０１５５】
次に、do_gets関数が、未解析で、定義内で未解析の関数呼び出しが行われていないことが分かる（手順３４０３および３４０４）。よってdo_getsを解析対象の関数（対象関数）とする（手順３４０６）。以降、手順３４０６にて対象関数とされる関数の順番は、do_gets、do_system、call_do_system、mainである。
【０１５６】
まず対象関数do_getsに対し、仮引数とローカル変数を変数ＤＢ２９０５に登録する（手順３４０７、３４０８）。do_getsについて手順３４０８終了時の変数ＤＢ２９０５が、図３３である。１７行目の関数getsの呼び出しによるデータ遷移の処理を行う（手順３４０９）。getsの遷移値を、固定関数遷移ＤＢ２９０２および不定関数遷移ＤＢ２９０４より検索し取り出す。すると、IN→1の遷移が取得される。この遷移先は、変数番号であるので、変数ＤＢ２９０５の該当変数の変数値を更新する。以上で対象関数do_getsの処理を終える（手順３４１０）。手順３４１０終了時の変数ＤＢ２９０５が、図３５である。
【０１５７】
変数ＤＢ２９０５のうち、種別が'A'の変数値がINであるので、これに相当する遷移IN→1を、不定関数遷移ＤＢ２９０４に登録する（手順３４１１）。手順３４１１終了時の不定関数遷移ＤＢ２９０４が、図３６である。
【０１５８】
次にdo_systemを対象関数とした処理を説明する。上記と同様にして、仮引数とローカル変数を変数ＤＢ２９０５に登録する（手順３４０７、３４０８）。手順３４０８終了時の変数ＤＢ２９０５が、図３７である。２２行目の関数systemの呼び出しによるデータ遷移の処理を行う（手順３４０９）。systemの遷移値を、固定関数遷移ＤＢ２９０２および不定関数遷移ＤＢ２９０４より検索し取り出す。すると、1→OSCOMMの遷移が取得される。第一引数の実引数値は１であり、遷移元をこの値に修正する。遷移先OSCOMMは、脆弱遷移先ＤＢ２９０３の脆弱遷移先に登録されている。遷移元は変数種別'A'の変数番号であるので、不定関数遷移ＤＢ２９０４に遷移を登録する（手順３４０９）。以上で対象関数do_systemの処理を終える（手順３４１０）。手順３４１０終了時の不定関数遷移ＤＢ２９０４が、図３８である。
【０１５９】
次にcall_do_systemを対象関数とした処理を説明する。上記と同様にして、仮引数とローカル変数を変数ＤＢ２９０５に登録する（手順３４０７、３４０８）。手順３４０８終了時の変数ＤＢ２９０５が、図３９である。２７行目の関数do_systemの呼び出しによるデータ遷移の処理を行う（手順３４０９）。do_systemの遷移値を、固定関数遷移ＤＢ２９０２および不定関数遷移ＤＢ２９０４より検索し取り出す。すると、1→OSCOMMの遷移が取得される。第一引数の実引数値は１であり、遷移元をこの値に修正する。この遷移先OSCOMMは、脆弱遷移先ＤＢ２９０３の脆弱遷移先に登録されている。遷移元は変数種別'A'の変数番号であるので、不定関数遷移ＤＢ２９０４に遷移を登録する（手順３４０９）。以上で対象関数call_do_systemの処理を終える（手順３４１０）。手順３４１０終了時の不定関数遷移ＤＢ２９０４が、図４０である。
【０１６０】
次にmainを対象関数とした処理を説明する。上記と同様にして、仮引数とローカル変数を変数ＤＢ２９０５に登録する（手順３４０７、３４０８）。手順３４０８終了時の変数ＤＢ２９０５が、図４１である。５行目の関数call_do_systemの呼び出しによるデータ遷移の処理を行う（手順３４０９）。すなわち、まずdo_systemの遷移値を、固定関数遷移ＤＢ２９０２および不定関数遷移ＤＢ２９０４より検索し取り出す。すると、1→OSCOMMの遷移が取得される。第一引数の実引数値は定数を表すＣであり、遷移元をこの値に修正する。この遷移先OSCOMMは、脆弱遷移先ＤＢ２９０３の脆弱遷移先に登録されている。しかし、遷移元が定数値Cであるので、何も行わない（手順３４０９）。
【０１６１】
次に７行目の関数get_inputの呼び出しによるデータ遷移の処理を行う（手順３４０９）。１７行目と同様に処理する。手順３４０９終了時の変数ＤＢ２９０５が、図４２である。
【０１６２】
次に８行目の関数call_do_systemの呼び出しによるデータ遷移の処理を行う（手順３４０９）。同様に1→OSCOMMの遷移が取得される。第一引数の実引数値はINであり、遷移元をこの値に修正する。この遷移先OSCOMMは、脆弱遷移先ＤＢ２９０３の脆弱遷移先に登録されている。遷移元がINであるので、不定関数遷移ＤＢ２９０４に登録するとともに、この箇所が脆弱であるという警告を検査結果として出力する。
【０１６３】
次に１０行目の関数strlcpyの呼び出しによるデータ遷移の処理を行う（手順３４０９）。同様に2→1の遷移が取得される。第二引数の実引数値はINであり、遷移元をこの値に修正する。この遷移先は、変数番号であるので、変数ＤＢ２９０５の該当変数の変数値を更新する。手順３４０９終了時の変数ＤＢ２９０５が、図４３である。
【０１６４】
次に１１行目の関数sanitizeOsの呼び出しによるデータ遷移の処理を行う（手順３４０９）。同様に1,SAFE_OS→1の遷移が取得される。第一引数の実引数値はINであり、遷移元の１をこの値に修正する。この遷移先は、変数番号であるので、変数ＤＢ２９０５の該当変数の変数値を更新する。手順３４０９終了時の変数ＤＢ２９０５が、図４４である。
【０１６５】
次に１２行目の関数call_do_systemの呼び出しによるデータ遷移の処理を行う（手順３４０９）。同様に1→OSCOMMの遷移が取得される。第一引数の実引数値はIN, SAFE_OSであり、遷移元をこの値に修正する。この遷移先OSCOMMは、脆弱遷移先ＤＢ２９０３の脆弱遷移先に登録されている。遷移元にINを含むが、脆弱遷移先ＤＢ２９０３の脆弱回避値SAFE_OSも同時に含むので、何も行わない。
【０１６６】
以上で対象関数mainの処理を終える（手順３４１０）。手順３４１０終了時の不定関数遷移ＤＢ２９０４が、図４５である。
【０１６７】
未解析の関数探索（手順３４０３）にて該当関数が見つからないので手順３４１３に移る。不定関数遷移ＤＢ２９０４に登録されている遷移値で、グローバル変数の変数番号を遷移先とする遷移の登録はないため、検査を終了する。
【０１６８】
以上のように、本ソースコード脆弱性検査装置を、図４６のソースコードに適用した場合、正確に８行目が脆弱であるという警告を出す。よってプログラマは、８行目の直前でその扱うデータに対し脆弱性回避処理を施せばいいことが分かる。このように従来のパターンマッチング法に比べ、誤った検出がなされず、プログラマが脆弱性回避処理を行うべき箇所を容易に特定できる。また、ソースコードに検査のための注釈を書き込む必要がない。
【０１６９】
また本実施形態では記述していないが、変数に対し二重に脆弱性回避処理を行ってしまう場合に、警告を出すこともできる。手順３４０９にて変数ＤＢ２９０５の変数値を更新する際に、新しく更新された値に、脆弱遷移先ＤＢ２９０３の脆弱回避値の同一の値が二つ以上含まれる場合、その箇所に警告を出すようにすればよい。
【０１７０】
また、遷移先が変数ＤＢ２９０５の種別'A'もしくは'G'の変数の変数番号である場合、図３４の手順３４０９で一度変数ＤＢ２９０５にその遷移を反映した後、手順３４１１にて遷移を読み取り不定関数遷移ＤＢに登録するのではなく、手順３４１１を無くし、直接不定関数遷移ＤＢに遷移を登録してもよい。
【０１７１】
以上で第２の実施形態の説明を終える。
【図面の簡単な説明】
【０１７２】
【図１】第１実施形態のソースコード脆弱性検査装置の構成の概要図
【図２】第１実施形態のソースコード脆弱性検査装置の機能の概要図
【図３】構文解析手段と脆弱性検出手段での処理手順を示す図
【図４】検査対象ソースコードの例を示す図
【図５】解析木の例を示す図
【図６】仮引数間遷移ＤＢの例を示す図
【図７】動的仮引数間遷移ＤＢの例（手順３０３終了時）を示す図
【図８】変数テーブルの例（関数format_stringについて手順３０８終了時）を示す図
【図９】関数呼出し箇所を解析時の変数テーブル更新処理手順を示す図
【図１０】変数テーブルの例（関数format_stringについて手順３０９終了時）を示す図
【図１１】変数テーブルの例（ポインタの代入'a=b'の処理前）を示す図
【図１２】変数テーブルの例（ポインタの代入'a=b'の処理後）を示す図
【図１３】動的仮引数間遷移ＤＢの例（関数format_stringについて手順３１１終了時）を示す図
【図１４】変数テーブルの例（関数get_inputについて手順３０８終了時）を示す図
【図１５】変数テーブルの例（関数get_inputについて手順３０９終了時）を示す図
【図１６】動的仮引数間遷移ＤＢの例（関数get_inputについて手順３１１終了時）を示す図
【図１７】変数テーブルの例（関数put_inputについて手順３０８終了時）を示す図
【図１８】変数テーブルの例（関数mainの１８行目について手順３０８終了時）を示す図
【図１９】変数テーブルの例（関数mainの１９行目について手順３０９終了時）を示す図
【図２０】変数テーブルの例（関数mainの２０行目について手順３０９終了時）を示す図
【図２１】動的仮引数間遷移ＤＢの例（関数mainの２０行目について手順３０９終了時）を示す図
【図２２】動的仮引数間遷移ＤＢの例（関数mainの２１行目について手順３０９終了時）を示す図
【図２３】変数テーブルの例（関数format_stringについて２回目の手順３０８終了時）を示す図
【図２４】変数テーブルの例（関数format_stringについて２回目の手順３０９終了時）を示す図
【図２５】変数テーブルの例（関数put_inputについて２回目の手順３０８終了時）を示す図
【図２６】脆弱性ＤＢの例を示す図
【図２７】if文を含む検査対象ソースコードの例を示す図
【図２８】解析木の例を示す図
【図２９】第２実施形態のソースコード脆弱性検査装置の機能の概要図
【図３０】脆弱遷移先ＤＢの例を示す図
【図３１】固定関数遷移ＤＢの例を示す図
【図３２】不定関数遷移ＤＢの例（手順３４０１終了時）を示す図
【図３３】変数ＤＢの例（関数do_getsについて手順３４０８終了時）を示す図
【図３４】本実施形態のソースコード脆弱性検査の動作を示すフローチャート図
【図３５】変数ＤＢの例（関数do_getsについて手順３４１０終了時）を示す図
【図３６】不定関数遷移ＤＢの例（関数do_getsについて手順３４１１終了時）を示す図
【図３７】変数ＤＢの例（関数do_systemについて手順３４０８終了時）を示す図
【図３８】不定関数遷移ＤＢの例（関数do_systemについて手順３４１０終了時）を示す図
【図３９】変数ＤＢの例（関数call_do_systemについて手順３４０８終了時）を示す図
【図４０】不定関数遷移ＤＢの例（関数call_do_systemについて手順３４１１終了時）を示す図
【図４１】変数ＤＢの例（関数mainについて手順３４０８終了時）を示す図
【図４２】変数ＤＢの例（関数mainの７行目について手順３４０９終了時）を示す図
【図４３】変数ＤＢの例（関数mainの１０行目について手順３４０９終了時）を示す図
【図４４】変数ＤＢの例（関数mainの１１行目について手順３４０９終了時）を示す図
【図４５】不定関数遷移ＤＢの例（関数mainについて手順３４１１終了時）を示す図
【図４６】検査対象ソースコードの具体例を表す図
【符号の説明】
【０１７３】
１０１…ソースコード脆弱性検査装置の本体（コンピュータ）、１０２…ＣＰＵ、１０３…記憶装置、１０４…メモリ、１０５…キーボード、１０６…ＣＲＴ、１０７…外部記憶装置、１０８…バス。
【図１】
0004693044.tif 000002
【図２】
0004693044.tif 000003
【図３】
0004693044.tif 000004
【図４】
0004693044.tif 000005
【図５】
0004693044.tif 000006
【図６】
0004693044.tif 000007
【図７】
0004693044.tif 000008
【図８】
0004693044.tif 000009
【図９】
0004693044.tif 000010
【図１０】
0004693044.tif 000011
【図１１】
0004693044.tif 000012
【図１２】
0004693044.tif 000013
【図１３】
0004693044.tif 000014
【図１４】
0004693044.tif 000015
【図１５】
0004693044.tif 000016
【図１６】
0004693044.tif 000017
【図１７】
0004693044.tif 000018
【図１８】
0004693044.tif 000019
【図１９】
0004693044.tif 000020
【図２０】
0004693044.tif 000021
【図２１】
0004693044.tif 000022
【図２２】
0004693044.tif 000023
【図２３】
0004693044.tif 000024
【図２４】
0004693044.tif 000025
【図２５】
0004693044.tif 000026
【図２６】
0004693044.tif 000027
【図２７】
0004693044.tif 000028
【図２８】
0004693044.tif 000029
【図２９】
0004693044.tif 000030
【図３０】
0004693044.tif 000031
【図３１】
0004693044.tif 000032
【図３２】
0004693044.tif 000033
【図３３】
0004693044.tif 000034
【図３４】
0004693044.tif 000035
【図３５】
0004693044.tif 000036
【図３６】
0004693044.tif 000037
【図３７】
0004693044.tif 000038
【図３８】
0004693044.tif 000039
【図３９】
0004693044.tif 000040
【図４０】
0004693044.tif 000041
【図４１】
0004693044.tif 000042
【図４２】
0004693044.tif 000043
【図４３】
0004693044.tif 000044
【図４４】
0004693044.tif 000045
【図４５】
0004693044.tif 000046
【図４６】
0004693044.tif 000047