-control_flow_integrity【Professional版のみ】【V1.06以降】
|
不正な間接関数呼び出しを検出するコードを生成します。
[指定形式]
不正な間接関数呼び出しを検出するコードを生成しません。
[詳細説明]
- | 不正な間接関数呼び出しを検出するコードを生成します。 |
本オプションを指定すると,Cソース・ファイル内に次の処理を行うコードを生成します。
(1) 関数の間接呼び出しが行われる直前に,間接呼び出し先のアドレスを引数に持つチェック関数__control_flow_integrityを呼び出します。
(2) チェック関数内で,引数のアドレスが,間接呼び出しされる可能性のある関数アドレスのリスト(以降,関数リストと呼びます)の中に含まれるかをチェックし,含まれていない場合は,不正な関数呼び出しとみなして,__control_flow_chk_fail関数を呼び出します。
このように,関数呼び出しをはじめとして,プログラムの流れ(制御フロー)を変える処理の整合性をチェックすることを,Control Flow Integrity(CFI)と呼びます。
- | チェック関数は下記のように定義され,ライブラリ関数として提供しています。 |
void __far __control_flow_integrity(void __far *addr);
チェック関数を通常の関数のように呼び出すことは禁止します。
- | コンパイラは,間接呼び出しされる可能性のある関数の情報をCソース・ファイルから自動で抽出します。リンカがその情報を統合して関数リストを作成します。リンカで関数リストを作成するにはリンク・オプション-CFIの指定が必要です。 |
詳細は「2.5.3 リンク・オプション」を参照してください。
- | __control_flow_chk_fail関数には不正な間接関数呼び出しの検出時に実行する処理を記述します。 |
この関数はユーザが定義する必要があります。
__control_flow_chk_fail関数を定義する際には,次の項目に注意してください。
- | 戻り値および引数の型をvoid型とし,far領域に配置してください。 |
- | __control_flow_chk_fail関数は,不正な間接関数呼び出しを検出するコードの生成の対象になりません。 |
- | __control_flow_chk_fail関数内ではabort()を呼び出してプログラムを終了するなど,チェック関数に戻らないように注意してください。 |
[例]
#include <stdlib.h>
int glb;
void __control_flow_chk_fail(void)
{
abort();
}
void func1(void) // 関数リストに追加される
{
++glb;
}
void func2(void) // 関数リストに追加されない
{
--glb;
}
void (*pf)(void) = func1;
void main(void)
{
pf(); // func1 関数の間接呼び出し
func2();
}
|
-cpu=S2 -S -control_flow_integrity を指定してコンパイルした場合
___control_flow_chk_fail:
.STACK ___control_flow_chk_fail = 4
br !!_abort
_func1:
.STACK _func1 = 4
incw !LOWW(_glb)
ret
_func2:
.STACK _func2 = 4
decw !LOWW(_glb)
ret
_main:
.STACK _main = 8
subw sp, #0x04
movw de, !LOWW(_pf)
movw ax, de
movw [sp+0x02], ax
mov a, !LOWW(_pf+0x00002)
mov [sp+0x00], a
call !!___control_flow_integrity ; チェック関数の呼び出し
mov a, [sp+0x00]
mov cs, a
movw ax, [sp+0x02]
movw hl, ax
call hl ; func1関数の間接呼び出し
call $!_func2 ; func2関数の直接呼び出し
addw sp, #0x04
ret
.SECTION .bss,BSS
.ALIGN 2
_glb:
.DS (2)
.SECTION .data,DATA
.ALIGN 2
_pf:
.DB2 LOWW(_func1)
.DB LOW(HIGHW(_func1))
.DB 0x00
|