説明

ソフトウェア検査装置及びプログラム

【課題】時間的・空間的オーバーヘッドを抑制しつつ、ドメイン間の実行制限を考慮して、非信頼ドメインからの関数コール時と関数リターン時のアドレスチェックを効率よく行う。
【解決手段】ソフトウェア検査装置は、ソフトウェアに対して、第1レイヤから第2レイヤへの関数のコール先がコードセグメント内であるか否か、関数のコール先アドレスの所定バイト前のコールポイントIDに基づいて関数のコール許可があるか否か、を判定するためのチェックコードを、第1のレイヤの関数をコールする前の箇所に挿入し、各レイヤから第2レイヤへ関数をコールすることができるか否かを示すビット列を含むコールポイントIDを決定し、このコールポイントIDを第2レイヤの関数開始の所定バイト前に挿入する演算処理部12を備えている。

【発明の詳細な説明】
【技術分野】
【0001】
本発明は、ソフトウェア検査装置及びプログラムに関する。
【背景技術】
【0002】
宇宙機器、航空システム、車載システムなどの様々な制御ソフトウェアは、近年、高度の信頼性が要求され、ソフトウェアの大規模化・複雑化が顕著に進んでいる。そして、ソフトウェアの大規模化・複雑化に伴って、バグが残留する可能性が高まっている。
【0003】
これに対して、実行時にセキュリティチェックを行うように、言語処理によってチェック処理を追加する方法が提案されている(特許文献1参照)。特許文献1の技術は、入力プログラム中の関数ポインタ変数を検出し、関数ポインタが指すことが可能な関数のリストを作成し、関数ポインタ変数を用いた関数呼出しの直前に、当該関数リストを使用して、関数ポインタ変数の値が不正な値でないか調べる。
【先行技術文献】
【特許文献】
【0004】
【特許文献1】特開2007−41777号公報
【発明の概要】
【発明が解決しようとする課題】
【0005】
しかし、特許文献1の技術は、実行時に関数リストと比較するために、呼び出す可能性のある関数の個数が多くなると、比較のためのオーバーヘッドが顕著になる問題が生じてしまう(時間的オーバーヘッドの増加)。また、呼び出す可能性のある関数の個数が多くなると、関数リストを保存しておくための領域も大きくなる問題もある(空間的オーバーヘッドの増加)。
【0006】
さらに、残留するバグの1つとして、ソフトウェア内部に存在する、間接アドレッシング(関数ポインタ)を用いた非信頼ドメインからの不適切な関数コール、又は、非信頼ドメインからの不適切な関数リターンによって、設計者の意図しない命令列を実行してしまうことが挙げられる一方で、特許文献1の技術はこれを実行時に防止できない。
【0007】
本発明は、上述した課題を解決するために提案されたものであり、時間的・空間的オーバーヘッドを抑制しつつ、ドメイン間の実行制限を考慮して、非信頼ドメインからの関数コール時と関数リターン時のアドレスチェックを効率よく行うことができるソフトウェア検査装置及びプログラムを提供することを目的とする。
【課題を解決するための手段】
【0008】
本発明に係るソフトウェア検査装置は、非信頼ドメインである第1レイヤ及び信頼ドメインである第2レイヤを含むソフトウェアに対して、前記第1レイヤから第2レイヤへの関数のコール先がコードセグメント内であるか否か、前記関数のコール先アドレスの所定バイト前のコールポイントIDに基づいて前記関数のコール許可があるか否か、を判定するためのチェックコードを、前記第1のレイヤの前記関数をコールする前の箇所に挿入するチェックコード挿入手段と、前記ソフトウェアを構成するレイヤ間で関数をコールすることができるか否かを示すデータに基づいて、前記ソフトウェアを構成する各レイヤから前記第2レイヤへ関数をコールすることができるか否かを示すビット列を含むコールポイントIDを決定するコールポイントID決定手段と、前記コールポイントID決定手段により決定されたコールポイントIDを前記第2レイヤの前記関数開始の所定バイト前に挿入するコールポイントID挿入手段と、前記チェックコード挿入手段により前記チェックコードが挿入された前記第1レイヤと、前記コールポイントID挿入手段により前記コールポイントIDが挿入された前記第2レイヤと、を含む前記ソフトウェアをコンパイルするコンパイル手段と、を備えている。
【0009】
本発明に係るソフトウェア検査装置は、非信頼ドメインである第1レイヤ及び信頼ドメインである第2レイヤを含むソフトウェアに対して、前記第1レイヤから第2レイヤへの関数のリターン先がコードセグメント内であるか否か、前記関数のリターン先アドレスの所定バイト後のリターンポイントIDに基づいて前記関数のリターン許可があるか否か、を判定するためのチェックコードを、前記第1のレイヤの前記関数をリターンする前の箇所に挿入するチェックコード挿入手段と、前記ソフトウェアを構成するレイヤ間で関数をリターンすることができるか否かを示すデータに基づいて、前記第2レイヤから前記ソフトウェアを構成する各レイヤへ関数をリターンすることができるか否かを示すビット列を含むリターンポイントIDを決定するリターンポイントID決定手段と、前記リターンポイントID決定手段により決定されたリターンポイントIDを前記第1レイヤの前記関数コールの所定バイト後に挿入するリターンポイントID挿入手段と、前記チェックコード挿入手段により前記チェックコードが挿入された前記第1レイヤと、前記リターンポイントID挿入手段により前記リターンポイントIDが挿入された前記第2レイヤと、を含む前記ソフトウェアをコンパイルするコンパイル手段と、を備えている。
【発明の効果】
【0010】
本発明に係るソフトウェア検査装置及びプログラムは、ドメイン間の実行制限を考慮しつつ、非信頼ドメインからの関数コール時と関数リターン時のアドレスチェックを効率よく行うことができる。
【図面の簡単な説明】
【0011】
【図1】本発明の実施形態に係るソフトウェア検査装置の構成を示すブロック図である。
【図2】検査対象であるソフトウェアの各レイヤの一例を示す図である。
【図3】ソフトウェア検査装置による検査内容の概要を示す図である。
【図4】本実施形態に係るコールリターン許可表を示す図である。
【図5】本実施形態のラベルの構成を示す図である。
【図6】コール部分のコンパイル実行ルーチンを示すフローチャートである。
【図7】コール部分のコンパイル実行ルーチンを示すフローチャートである。
【図8】コール部分のコンパイル実行ルーチンを示すフローチャートである。
【図9】コンパイル実行ルーチンによって変換されるSW−Cを示す図である。
【図10】コンパイル実行ルーチンによって変換されるLibを示す図である。
【図11】リターン部分のコンパイル実行ルーチンを示すフローチャートである。
【図12】リターン部分のコンパイル実行ルーチンを示すフローチャートである。
【図13】リターン部分のコンパイル実行ルーチンを示すフローチャートである。
【図14】コンパイル実行ルーチンによって変換されるSW−Cを示す図である。
【図15】コンパイル実行ルーチンによって変換されるRTOSを示す図である。
【図16】ソフトウェアのコール部分のソフトウェア実行ルーチンを示すフローチャートである。
【図17】ソフトウェアのリターン部分のソフトウェア実行ルーチンを示すフローチャートである。
【発明を実施するための形態】
【0012】
以下、本発明の好ましい実施の形態について図面を参照しながら詳細に説明する。
【0013】
[ソフトウェア検査装置の構成]
図1は、本発明の実施形態に係るソフトウェア検査装置10の構成を示すブロック図である。ソフトウェア検査装置10は、検査対象であるソフトウェア(オリジナルソースコード)をコンパイルし、コンパイルされたコードを検査しながら実行する。
【0014】
ソフトウェア検査装置10は、データが入力又は出力されるデータ入出力部11と、ソフトウェアを検査するための演算処理を行う演算処理部12と、入力されたデータを記憶するデータ記憶部13と、データのワークエリアであるランダムアクセスメモリ(RAM)14と、演算処理部12の制御プログラムが記憶されたリードオンリーメモリ(ROM)15と、ソフトウェアの検査結果を出力する検査結果出力部16と、を備えている。
【0015】
なお、データ記憶部13には、データ入出力部11を介して入力された、オリジナルソースコード、コールリターン許可表のデータが記憶される。また、検査結果出力部16は、ソフトウェアを検査した結果、エラー(セグメント違反、不正なリターンなど)が見つけられた場合に、そのエラー内容を画像または音声により出力する。
【0016】
図2は、検査対象であるソフトウェアの各レイヤの一例を示す図である。このソフトウェアは、信頼ドメインである複数のレイヤ(例えばオペレーティング・システム(OS))と、非信頼ドメインであるレイヤと、で構成されている。
【0017】
信頼ドメインのレイヤとしては、RTOS(リアルタイム・オペレーティング・システム)、COM、Lib(ライブラリ)が該当する。非信頼ドメインのレイヤとしては、SW−C(ソフトウェア・コンポーネント)が該当する。
【0018】
本実施形態では、コール/リターンについて次のようなレイヤ間実行ポリシー(レイヤ間の実行制限)が存在する。
【0019】
1.SW−Cは、SW−C又はLibへのみコール可能である。
(SW−Cは、SW−C又はLibからのみリターン可能である。)
【0020】
2.SW−Cは、SW−C又はRTOSからのみコール可能である。
(SW−Cは、SW−C又はRTOSへのみリターン可能である。)
【0021】
3.上記以外の組合せは、すべてコール/リターン可能である。
【0022】
図3は、ソフトウェア検査装置10による検査内容の概要を示す図である。予め、オペレータは、ソフトウェアの各レイヤが信頼ドメインであるか非信頼ドメインであるかを示すソフトウェアレイヤ表と、レイヤ間のコール/リターンが可能か否かを示すレイヤ間実行ポリシーと、に基づいて、コールリターン許可表を作成する。
【0023】
ここで、ソフトウェアレイヤ表は、検査対象のソフトウェアを構成する全レイヤについて、例えば、レイヤ1は信頼ドメイン、レイヤ2は非信頼ドメイン、・・・、レイヤkは信頼ドメイン、であることを示している。レイヤ間実行ポリシーは、検査対象のソフトウェアを構成する各レイヤについて、例えば、レイヤ1はレイヤ1またはレイヤ2へのみコール可能(レイヤ1はレイヤ1またはレイヤ2からのみリターン可能)、レイヤ2は・・・、であることを示している。
【0024】
このように、コールリターン許可表は、レイヤ間のコール/リターンの実行制限を記述したものであり、1行目のCallerはコールする側であり、一番左側の列のCalleeはコールされる(リターンさせる)側である。
【0025】
次に、ソフトウェア検査装置10は、このコールリターン許可表のデータを用いてオリジナルソースコードのコンパイルを実行し、制御フロー保護コードであるオブジェクトを生成する。コンパイルの実行中では、ソフトウェア検査装置10は、コール部分とリターン部分のそれぞれに所定の条件をチェックするためのコードを挿入し、ラベルを決定し、決定したラベルをバイナリへ埋め込む。
【0026】
なお、ラベルとは、コールポイントID及びリターンポイントIDの総称である。コールポイントIDは、コール許可ビット(xビット)、コールポイントビット(yビット)で構成されている。リターンポイントIDは、リターン許可ビット(aビット)、リターンポイントビット(bビット)で構成されている。
【0027】
最後に、ソフトウェア検査装置10は、コール/リターンの実行制限をチェックしながら制御フロー保護コードに基づいてソフトウェアを実行する。なお、本実施形態では、次のようなコールリターン許可表が使用される。
【0028】
図4は、本実施形態に係るコールリターン許可表を示す図である。コールリターン許可表は、どのレイヤからどのレイヤへのコール/リターンが可能か不可能かを示している。
【0029】
例えば、左から3列目の「Lib/0/1/1/1」によると、CallerがLibの場合、Libは、SW−Cへのコール(及びSW−Cからのリターン)が不可能であるが、Lib、COM、RTOSへのコール(及びLib、COM、RTOSからのリターン)が可能である。また、上から3行目の「Lib/1/1/1/1」によると、CalleeがLibの場合、Libはすべてのレイヤからのリターンが可能(及びすべてのレイヤはLibへコールが可能)である。
【0030】
そして、コールリターン許可表のデータは、ソフトウェア検査装置10に入力され、コンパイル実行時に使用される。また、コンパイル実行時では、図4に示すコールリターン許可表に基づいて次のように構成されたラベルが決定される。
【0031】
図5は、本実施形態のラベルの構成を示す図である。ラベルの1つであるコールポイントID(32ビット)は、コール許可ビット(x=4ビット)、コールポイントビット(y=28ビット)で構成されている。ラベルの残りの1つであるリターンポイントID(32ビット)は、リターン許可ビット(a=4ビット)、リターンポイントビット(b=28ビット)で構成されている。
【0032】
コール許可ビット及びリターン許可ビットは、コールリターン許可表に基づいて決定される。コールポイントビット及びリターンポイントビットは、ROM15のコード領域で使用されていないビット列であり、コンパイル時に静的に決定される。
【0033】
以上のように構成されたソフトウェア検査装置10では、次に示すコンパイル実行ルーチンが実行される。
【0034】
[ソフトウェアのコール部分のコンパイル]
図6から図8は、コール部分のコンパイル実行ルーチンを示すフローチャートである。以下の各ルーチンでは、図4に示すコールリターン許可表、図5に示すラベルが使用される。また、コードセグメントは、ROM15の領域にあり、プログラム自身で書き換えできないものとする。よって、本ルーチン実行時に埋め込まれたコールポイントID及びリターンポイントIDは不変である。
【0035】
また、本ルーチンでは、SW−C(非信頼ドメイン)からLib(信頼ドメイン)のコールを例に挙げて説明する。なお、図9は、コンパイル実行ルーチンによって変換されるSW−Cを示す図である。図10は、コンパイル実行ルーチンによって変換されるLibを示す図である。
【0036】
図6に示すステップS1では、演算処理部12は、コールリターン許可表の行のビット数を“n”に設定する。本実施形態ではn=4に設定する。
【0037】
ステップS2では、演算処理部12は、コードセグメントで使用されていないビット列を用いて、命令ビット数からnを除いたビット数でコールポイントビットをランダムに決定し、この決定したものを“CPB”に設定する。本実施形態では、命令ビット数は図5に示すように32であるので、命令ビット数32からn(=4)を除いた28ビットのCPBが設定される。
【0038】
ステップS3では、演算処理部12は、ランタイムチェック(チェックコード)を挿入しようとしている非信頼ドメインのレイヤを“L”に設定する。本実施形態では、非信頼ドメインであるSW−Cが“L”に設定される。
【0039】
ステップS4では、演算処理部12は、図4に示すコールリターン許可表より“L”がMSB(最上位ビット)から何行目を示すかを“b”に設定する。
【0040】
ステップS5では、演算処理部12は、命令ビット数32のうちbビット目のみを1にして残りを0としたビット列を“maskBit1”に設定する。本実施形態では、“maskBit1”に、例えば0x80000000が設定される。
【0041】
ステップS6では、演算処理部12は、上位nビットを0にしてその他を1にしたビット列を“maskBit2”に設定する。本実施形態では、“maskBit2”に、例えば0x0fffffffが設定される。
【0042】
ステップS7では、演算処理部12は、コードセグメントの開始アドレスをST_CODESEGに設定し、続くステップS8では、コードセグメントの終了アドレスをED_CODESEGに設定する。
【0043】
図7に示すステップS9では、演算処理部12は、Lに属するコードの構文解析を行い、構文の全体集合をGに設定する。本実施形態では、非信頼ドメインのレイヤであるSW−Cに属するコードの構文解析が行われる。
【0044】
ステップS10では、演算処理部12は、構文の全体集合Gが存在する(Gが空集合φではない)かを判定する。そして、Gが存在する場合はステップS11へ進み、Gが存在しない場合はステップS15へ進む。
【0045】
ステップS11では、演算処理部12は、Gから構文を1つ取り出してgに設定し、続くステップS12では、gが関数ポインタを使用しているかを判定する。例えば、データ記憶部13には多くの関数ポインタが記憶され、演算処理部12は、これらの関数ポインタを参照して、gが関数ポインタを使用しているかを判定すればよい。gが関数ポインタを使用している場合はステップS13へ進み、使用していない場合はステップS10へ戻る。
【0046】
ステップS13では、演算処理部12は、gで使用している関数ポインタの変数名をfptrNameに設定し、図9(A)の(*fptrName)()の部分を以下のものに置換する(ステップS14)。
【0047】
【数1】

【0048】
すなわち、演算処理部12は、関数をコールする前(図9(A)の下から2行目の“(*fptrName)();”の前)の部分に、2つのif文を含むチェックコードを挿入している。
【0049】
一方、図7に示すステップS15では、演算処理部12は、検査対象のソフトウェアのすべての非信頼ドメインのレイヤに対してステップS10〜S14を実行したかを判定する。肯定判定の場合は図8に示すステップS16へ進み、否定判定の場合は図6に示すステップS3へ戻る。
【0050】
図8に示すステップS16では、演算処理部12は、非信頼ドメインのレイヤに対して、コードをコンパイルしバイナリを生成する。
【0051】
ステップS17では、演算処理部12は、図4に示すコールリターン許可表のb行目を上位n(=4)ビットとしたコール許可ビットと、残りの28ビットをCPBとしたビット列とを用いて、図5に示すように、コールポイントIDを決定する。
【0052】
ステップS18では、演算処理部12は、信頼ドメインのレイヤに対して、コードをコンパイルしバイナリを生成する。ここで、バイナリ生成時には、演算処理部12は、信頼ドメインの関数の先頭に、ステップS17で決定されたコールポイントIDを挿入する。
【0053】
ステップS19では、演算処理部12は、コードセグメント全体で関数の先頭以外にCPBのビット列が使われていないかを判定する。CPBのビット列が使われていない場合は本ルーチンを終了し、使われている場合はステップS20へ進む。
【0054】
ステップS20では、演算処理部12は、コードセグメント全体で使われていないビット列をCPBに設定して、図6に示すステップS3に戻る。
【0055】
この結果、図9(A)に示すSW−Cは、ステップS13において、図9(B)に示すように、#1及び#2のコードが挿入される。ここで、#1は、関数ポインタがコードセグメント内にあるかを判定し、ない場合はセグメント違反に対するルーチン(segViolation())へ移行することを示している。また、#2は、コール許可ビットがコール許可を示し、かつ、コールポイントビットと等しいか、を判定し、これらの条件を満たさない場合は、不正なリターンに対処するエラールーチン(errorHook())へ移行することを示している。#3は、#1及び#2を満たす場合は、間接コールが実行されることを示している。そして、図9(B)がコンパイルされると、図9(C)に示す制御フロー保護コードが生成される。
【0056】
また、図10(A)に示すLibがコンパイルされると、図10(B)に示すように、libFunc1、libFunc2のそれぞれの関数の先頭にコールポイントID“f1 fb 3a 2c”が挿入される。
【0057】
ここで、図10(A)及び(B)に示すLibはコールされる側であるので、ステップS17において、図4に示すコールリターン許可表の3行目(Calleeがlibの場合)の“1111”がコールポイントIDの上位4ビットとして選択される。“1111”は16進数で“f”であるので、図10(B)に示すコールポイントIDの先頭は“f”となる。コールポイントIDの残りの“1 fb 3a 2c”はコールポイントビットである。
【0058】
[ソフトウェアのリターン部分のコンパイル]
図11〜図13は、リターン部分のコンパイル実行ルーチンを示すフローチャートである。
【0059】
本ルーチンでは、SW−C(非信頼ドメイン)からRTOS(信頼ドメイン)へのリターンを例に挙げて説明する。なお、図14は、コンパイル実行ルーチンによって変換されるSW−Cを示す図である。図15は、コンパイル実行ルーチンによって変換されるRTOSを示す図である。
【0060】
図11に示すステップS31では、演算処理部12は、コールリターン許可表の行のビット数を“n”に設定する。本実施形態ではn=4に設定する。
【0061】
ステップS32では、演算処理部12は、コードセグメントで使用されていないビット列を用いて、命令ビット数からnを除いたビット数でリターンポイントビットをランダムに決定し、この決定したものを“RPB”に設定する。本実施形態では、命令ビット数32からn(=4)を除いた28ビットのRPBが設定される。そして、ステップS33〜S39は、ステップS3〜S9と同様に実行され、図12に示すステップS40へ進む。
【0062】
ステップS40では、演算処理部12は、構文の全体集合Gが存在する(Gが空集合φではない)かを判定する。そして、Gが存在する場合はステップS41へ進み、Gが存在しない場合はステップS47へ進む。
【0063】
ステップS41では、演算処理部12は、Gから構文を1つ取り出してgに設定し、続くステップS42では、gが関数の先頭を表しているかを判定する。gが関数の先頭を表している場合はステップS43へ進み、それを表していない場合はステップS40へ戻る。
【0064】
ステップS43では、演算処理部12は、関数の先頭で、変数int dummyNumの宣言を挿入し、ステップS44では、構文の全体集合Gから構文を1つ取り出してgに設定する。
【0065】
ステップS45では、演算処理部12は、gが関数の最後を表しているかを判定する。gが関数の最後を表している場合はステップS46へ進み、それを表していない場合はステップS44へ戻る。
【0066】
ステップS46では、演算処理部12は、関数の最後に以下のコードを挿入する。
【0067】
【数2】

【0068】
すなわち、演算処理部12は、関数をリターンする前(図14(A)の“}”の直前)の部分に、2つのif文を含むチェックコードを挿入している。
【0069】
ステップS47では、演算処理部12は、すべての非信頼ドメインのレイヤに対してステップS40〜S46を実行したかを判定する。肯定判定の場合は図13に示すステップS48へ進み、否定判定の場合は図11に示すステップS33へ戻る。
【0070】
ステップS48では、演算処理部12は、非信頼ドメインのレイヤに対して、コードをコンパイルしバイナリを生成する。
【0071】
ステップS49では、演算処理部12は、図4に示すコールリターン許可表のb行目を上位n(=4)ビットとしたリターン許可ビットと、残りの28ビットをRPBとしたビット列とを用いて、リターンポイントIDを決定する。
【0072】
ステップS50では、演算処理部12は、信頼ドメインのレイヤに対して、コードをコンパイルしバイナリを生成する。ここで、バイナリ生成時には、演算処理部12は、信頼ドメインの関数コールの直後にリターンポイントIDを挿入する。
【0073】
ステップS51では、演算処理部12は、コードセグメント全体で関数の先頭以外にRPBのビット列が使われていないかを判定する。RPBのビット列が使われていない場合は本ルーチンを終了し、それが使われている場合はステップS52へ進む。
【0074】
ステップS52では、演算処理部12は、コードセグメント全体で使われていないビット列をRPBに設定して、図11に示すステップS33に戻る。
【0075】
この結果、図14(A)に示すSW−Cは、ステップS46において、図14(B)に示すように、#4及び#5のコードが挿入される。ここで、#4は、リターンアドレス(ステップS43で最初に挿入したダミー変数を使用)がコードセグメント内にあるかを判定し、ない場合はセグメント違反に対するルーチンへ移行することを示している。また、#5は、リターン許可ビットがリターン許可を示し、かつ、リターンポイントビットと等しいか、を判定し、これらの条件を満たさない場合は、不正なリターンに対処するエラールーチンへ移行することを示している。#6は、リターンアドレスをインクリメントしてコードを指すようにすることを示している。そして、図14(B)がコンパイルされると、図14(C)に示す制御フロー保護コードが生成される。
【0076】
また、図15(A)に示すRTOSがコンパイルされると、図15(B)に示すように、関数コール(CALL SW_C)の直後に、リターンポイントID“f2 fa 3c bd”が挿入される。
【0077】
ここで、図15(A)及び(B)に示すRTOSはコールする側であるので、ステップS49において、図4に示すコールリターン許可表の4列目(CallerがRTOSの場合)の“1111”がリターンポイントIDの上位4ビットとして選択される。“1111”は16進数で“f”であるので、図15(B)に示すリターンポイントIDの先頭は“f”となる。リターンポイントIDの残りの“2 fa 3c bd”はリターンポイントビットである。そして、SW−Cのコール直後のスタック内容は図15(C)に示すようになる。
【0078】
[ソフトウェアのコール部分の実行]
図16は、ソフトウェアのコール部分のソフトウェア実行ルーチンを示すフローチャートである。本ルーチンでは、ステップS1〜S20の処理によってコンパイルされたソフトウェア(図9及び図10)を例に挙げて説明する。
【0079】
ステップS61では、演算処理部12は、コンパイルされたソフトウェアのチェックコードに基づいて、関数ポインタ(fptr)がコードセグメント内(セグメント開始アドレスからセグメント終了アドレスの間)を指しているかを判定する。
【0080】
ここでは、例えば、図9(B)の#1のチェックコードに基づいて、[fptr<コードセグメント開始アドレス]を満たすか否か、[fptr>コードセグメント終了アドレス]を満たすか否かが判定される。いずれも満たさない場合に、関数ポインタがコードセグメント内を指していると判定される。
【0081】
そして、関数ポインタがコードセグメント内を指している場合はステップS62へ進み、それを指していない場合はステップS68へ進む。
【0082】
ステップS62では、演算処理部12は、関数ポインタから1を引いた値(fptr−1)について間接参照した値をコールポイントID(callPointId)に設定する(callPointId←fptr−1)。そして、ステップS63へ進む。
【0083】
ステップS63では、演算処理部12は、コールポイントIDの上位xビットをコール許可ビット(callAllowingBit)に設定する。なお、本実施形態ではx=4とし、(callAllowingBit←callPointIdの上位4ビット)となる。そして、ステップS64へ進む。
【0084】
ステップS64では、演算処理部12は、コール許可ビットに基づいて当該ドメインのレイヤについてコール許可があるかを判定する。
【0085】
ここでは、例えばコール許可ビット(callAllowingBit)の最上位ビットを取り出してビットが立っていないかが判定される。その最上位ビットが立っている場合、当該ドメインのコール許可があることを示すので、ステップS65へ進む。SW−Cからのコール許可の有無はコールリターン許可表から分かるので、コールリターン許可表から求められたcallAllowingBitの最上位ビットをみればコール許可の有無が分かる。一方、その最上位ビットが立っていない場合、当該ドメインのコール許可がないことを示すので、ステップS69へ進む。
【0086】
ステップS65では、演算処理部12は、コールポイントIDの下位yビットをコールポイントビットに設定する。なお、本実施形態ではy=28であり、(callPointBit←callPointIdの下位28ビット)となる。そして、ステップS66へ進む。
【0087】
ステップS66では、演算処理部12は、コールポイントビットとコンパイラ(コンパイル実行ルーチン)が定めたビット列であるCPBが等しい(callPointBit=CPB)かを判定する。そして、それらが等しい場合はステップS67へ進み、等しくない場合はステップS69へ進む。
【0088】
ステップS67では、演算処理部12は、関数ポインタの値を正当であるとみなし、間接コール(*fptr)()を実行する。そして、本ルーチンが終了する。
【0089】
なお、ステップS61の否定判定の場合はステップS68へ進み、演算処理部12は、セグメント違反に対処するエラールーチンsegViolation()へ移行する。このエラールーチンは特に限定されるものではないが、例えば、検査結果出力部16が、セグメント違反であることを示すエラーメッセージを音声または画像で出力する。そして、本ルーチンが終了する。
【0090】
また、ステップS64の否定判定の場合又はステップS66の否定判定の場合はステップS69へ進み、演算処理部12は、不正なコールに対処するエラールーチンerrorHook()へ移行する(ステップS69)。このエラールーチンは特に限定されるものではないが、例えば、検査結果出力部16が、不正なコールであることを示すエラーメッセージを音声または画像で出力する。そして、本ルーチンが終了する。
【0091】
以上のように、ソフトウェア検査装置10は、関数のコール先がコードセグメントで、コール許可があり、かつ関数のコールポイント(本実施形態では関数の先頭)であれば、正当なコールとみなして当該関数をコールする。また、ソフトウェア検査装置10は、上記のいずれか1つの条件を満たさない場合は、不正なコールとみなしてエラーを発行する。
【0092】
[ソフトウェアのリターン部分の実行]
図17は、ソフトウェアのリターン部分のソフトウェア実行ルーチンを示すフローチャートである。ここでは、ステップS31〜S52の処理によってコンパイルされたソフトウェア(図14及び図15)が実行される。
【0093】
ステップS71では、演算処理部12は、コンパイルされたソフトウェアのチェックコードに基づいて、リターンアドレス(retAdr)がコードセグメント内を指しているかを判定する。
【0094】
ここでは、最初に、コード変換(コンパイル)時において関数の最初に挿入したダミー変数(dummyNum)が使用されて、リターンアドレス(retAdr)が求められる。具体的には、ダミー変数のアドレスに1を加えて間接参照した値がリターンアドレスに設定される(retAdr←dummyNumのアドレス+1を間接参照した値)。
【0095】
次に、図14(B)の#4のチェックコードに基づいて、[retAdr<コードセグメント開始アドレス]を満たすか否か、[retAdr>コードセグメント終了アドレス]を満たすか否か、が判定される。いずれも満たさない場合に、関数ポインタがコードセグメント内を指していると判定される。
【0096】
そして、リターンアドレスがコードセグメント内を指している場合はステップS72へ進み、それを指していない場合はステップS79へ進む。
【0097】
ステップS72では、演算処理部12は、リターンアドレスの間接参照した値をリターンポイントID(retPointId)に設定する(retPointId←retAdrの間接参照)。そして、ステップS73へ進む。
【0098】
ステップS73では、演算処理部12は、リターンポイントIDの上位aビットをリターン許可ビット(retAllowingBit)に設定する。なお、本実施形態ではa=4とし、(retAllowingBit←retPointIdの上位4ビット)となる。そして、ステップS74へ進む。
【0099】
ステップS74では、演算処理部12は、リターン許可ビットに当該ドメインのリターン許可があるかを判定する。
【0100】
ここでは例えば、retAllowingBitの最上位ビットを取り出してビットが立っていないかが判定される。その最上位ビットが立っている場合、当該ドメインのリターン許可があることを示すので、ステップS75へ進む。SW−CからRTOSへのリターン許可の有無はコールリターン許可表から分かるので、コールリターン許可表から求められたretAllowingBitの最上位ビットをみればリターン許可の有無が分かる。一方、その最上位ビットが立っていない場合、当該ドメインのリターン許可がないことを示すので、ステップS80へ進む。
【0101】
ステップS75では、演算処理部12は、リターンポイントIDの下位bビットをリターンポイントビットに設定する。なお、本実施形態ではb=28であり、(retPointBit←retPointIdの下位28ビット)となる。そして、ステップS76へ進む。
【0102】
ステップS76では、演算処理部12は、リターンポイントビットとコンパイラ(コンパイル実行ルーチン)が定めたビット列が等しい(retPointBit=RPB)かを判定する。そして、それらが等しい場合はステップS77へ進み、等しくない場合はステップS80へ進む。
【0103】
ステップS77では、演算処理部12は、ステップS71で説明したリターンアドレス(retAdr)をインクリメントして、リターン先のコードを指すように修正する。そして、ステップS78に進む。
【0104】
なお、ステップS77の実行前では、リターンアドレスがリターンポイントIDの領域を指している。そこで、ステップS77において、スタックに格納されているリターンアドレスをインクリメントすることで、リターンアドレスが、リターンした後に実行すべきコードを指すようにしている。
【0105】
ステップS78では、演算処理部12は、リターンを実行する(ステップS78)。そして、本ルーチンが終了する。
【0106】
なお、ステップS71の否定判定の場合はステップS79に進み、演算処理部12は、セグメント違反に対処するエラールーチンsegViolation()へ移行する。そして、このエラールーチンが実行されて、本ルーチンが終了する。
【0107】
また、ステップS74の否定判定の場合又はステップS76の否定判定の場合はステップS80へ進み、演算処理部12は、不正なリターンに対処するエラールーチンerrorHook()へ移行する。そして、このエラールーチンが実行されて、本ルーチンが終了する。
【0108】
以上のように、ソフトウェア検査装置10は、関数のリターン先がコードセグメントで、リターン許可があり、かつ関数のリターンポイント(本実施形態ではコールの直後)であれば、正当なリターンとみなし、リターン先のアドレスをインクリメントしてコードを指すようにした後にリターンする。また、ソフトウェア検査装置10は、上記のいずれか1つの条件を満たさない場合は、不正なリターンとみなしてエラーを発行する。
【0109】
この結果、ソフトウェア検査装置10は、コール時/リターン時におけるソフトウェアのレイヤ間の実行制限を考慮して、設計者の意図する範囲内で、コール/リターンを実行することができる。
【0110】
また、ソフトウェア検査装置10は、リターンアドレスの待避領域に意図しない書き込みができて破壊されるのを防止することで、アドレスチェックの妥当性を保証することができる。
【0111】
さらに、ソフトウェア検査装置10は、コール可能な関数の個数が増加し、またはコールのネストが深くなっても、コール時及びリターン時のアドレスチェックにおける時間的・空間的オーバーヘッドを抑制することができる。
【0112】
なお、本発明は、上述した実施の形態に限定されるものではなく、特許請求の範囲に記載された範囲内で設計上の変更をされたものにも適用可能であるのは勿論である。
【符号の説明】
【0113】
11 構文解析部
12 演算処理部
13 データ記憶部
14 RAM
15 ROM
16 検査結果出力部

【特許請求の範囲】
【請求項1】
非信頼ドメインである第1レイヤ及び信頼ドメインである第2レイヤを含むソフトウェアに対して、前記第1レイヤから第2レイヤへの関数のコール先がコードセグメント内であるか否か、前記関数のコール先アドレスの所定バイト前のコールポイントIDに基づいて前記関数のコール許可があるか否か、を判定するためのチェックコードを、前記第1のレイヤの前記関数をコールする前の箇所に挿入するチェックコード挿入手段と、
前記ソフトウェアを構成するレイヤ間で関数をコールすることができるか否かを示すデータに基づいて、前記ソフトウェアを構成する各レイヤから前記第2レイヤへ関数をコールすることができるか否かを示すビット列を含むコールポイントIDを決定するコールポイントID決定手段と、
前記コールポイントID決定手段により決定されたコールポイントIDを前記第2レイヤの前記関数開始の所定バイト前に挿入するコールポイントID挿入手段と、
前記チェックコード挿入手段により前記チェックコードが挿入された前記第1レイヤと、前記コールポイントID挿入手段により前記コールポイントIDが挿入された前記第2レイヤと、を含む前記ソフトウェアをコンパイルするコンパイル手段と、
を備えたソフトウェア検査装置。
【請求項2】
前記コールポイントID決定手段は、コードセグメントで使用されていないビット列であるコールポイントビットを更に含んだ前記コールポイントIDを決定する
請求項1に記載のソフトウェア検査装置。
【請求項3】
前記コンパイル手段によりコンパイルされたソフトウェアに含まれる前記チェックコードに基づいて、前記第1レイヤから第2レイヤへの関数のコール先がコードセグメント内であり、かつ、前記関数のコール許可がある場合に、前記ソフトウェアを実行するソフトウェア実行手段を更に備えた
請求項1に記載のソフトウェア検査装置。
【請求項4】
前記ソフトウェア実行手段は、更に、前記コンパイルされたソフトウェアに含まれる前記チェックコードのコールビットポイントが、前記コールポイントID決定手段により決定されたコールポイントIDのコールビットポイントと同じである場合に、前記ソフトウェアを実行する
請求項3に記載のソフトウェア検査装置。
【請求項5】
非信頼ドメインである第1レイヤ及び信頼ドメインである第2レイヤを含むソフトウェアに対して、前記第1レイヤから第2レイヤへの関数のリターン先がコードセグメント内であるか否か、前記関数のリターン先アドレスの所定バイト後のリターンポイントIDに基づいて前記関数のリターン許可があるか否か、を判定するためのチェックコードを、前記第1のレイヤの前記関数をリターンする前の箇所に挿入するチェックコード挿入手段と、
前記ソフトウェアを構成するレイヤ間で関数をリターンすることができるか否かを示すデータに基づいて、前記第2レイヤから前記ソフトウェアを構成する各レイヤへ関数をリターンすることができるか否かを示すビット列を含むリターンポイントIDを決定するリターンポイントID決定手段と、
前記リターンポイントID決定手段により決定されたリターンポイントIDを前記第1レイヤの前記関数コールの所定バイト後に挿入するリターンポイントID挿入手段と、
前記チェックコード挿入手段により前記チェックコードが挿入された前記第1レイヤと、前記リターンポイントID挿入手段により前記リターンポイントIDが挿入された前記第2レイヤと、を含む前記ソフトウェアをコンパイルするコンパイル手段と、
を備えたソフトウェア検査装置。
【請求項6】
前記リターンポイントID決定手段は、コードセグメントで使用されていないビット列であるリターンポイントビットを更に含んだ前記リターンポイントIDを決定する
請求項5に記載のソフトウェア検査装置。
【請求項7】
前記コンパイル手段によりコンパイルされたソフトウェアに含まれる前記チェックコードに基づいて、前記第1レイヤから第2レイヤへの関数のリターン先がコードセグメント内であり、かつ、前記関数のリターン許可がある場合に、前記ソフトウェアを実行するソフトウェア実行手段を更に備えた
請求項5に記載のソフトウェア検査装置。
【請求項8】
前記ソフトウェア実行手段は、更に、前記コンパイルされたソフトウェアに含まれる前記チェックコードのリターンビットポイントが、前記リターンポイントID決定手段により決定されたリターンポイントIDのリターンビットポイントと同じである場合に、前記ソフトウェアを実行する
請求項7に記載のソフトウェア検査装置。
【請求項9】
コンピュータを請求項1から請求項8のいずれか1項に記載のソフトウェア検査装置の各手段として機能させるためのソフトウェア検査プログラム。

【図1】
image rotate

【図2】
image rotate

【図3】
image rotate

【図4】
image rotate

【図5】
image rotate

【図6】
image rotate

【図7】
image rotate

【図8】
image rotate

【図9】
image rotate

【図10】
image rotate

【図11】
image rotate

【図12】
image rotate

【図13】
image rotate

【図14】
image rotate

【図15】
image rotate

【図16】
image rotate

【図17】
image rotate