-control_flow_integrity 【Professional版のみ】 【V1.07.00以降】


不正な間接関数呼び出しを検出するコードを生成します。

[指定形式]

-control_flow_integrity

 

-

省略時解釈

不正な間接関数呼び出しを検出するコードを生成しません。

[詳細説明]

-

不正な間接関数呼び出しを検出するコードを生成します。

本オプションを指定すると,Cソース・プログラム内に次の処理を行うコードを生成します。

(1)

関数の間接呼び出しが行われる直前に,間接呼び出し先のアドレスを引数に持つチェック関数 __control_flow_integrityを呼び出します。

(2)

チェック関数内で,引数のアドレスが,間接呼び出しされる可能性のある関数アドレスのリスト(以降,関数リストと呼びます)の中に含まれるかをチェックし,含まれていない場合は,不正な間接呼び出しとみなして__control_flow_chk_fail関数を呼び出します。

このように,間接関数呼び出しなどプログラムの流れを変える処理について,その正しさを検証することを,Control Flow Integrity(CFI)と呼びます。

-

チェック関数は下記のように定義され,ライブラリ関数として提供しています。

void __control_flow_integrity(void *addr);

チェック関数を通常の関数のように呼び出すことは禁止します。

-

コンパイラは,間接呼び出しされる可能性のある関数の情報をCソース・プログラムから自動で抽出します。リンカがその情報を統合して関数リストを作成します。リンカで関数リストを作成するにはリンク・オプション-CFIの指定が必要です。

詳細は「2.5.3 リンク・オプション」を参照してください。

-

__control_flow_chk_fail関数には不正な間接関数呼び出しの検出時に実行する処理を記述します。

この関数はユーザが定義する必要があります。

__control_flow_chk_fail関数を定義する際には,次の項目に注意してください。

-

戻り値および引数の型をvoid型としてください。

-

static関数にしないでください。

-

通常の関数のように呼び出すことは禁止します。

-

__control_flow_chk_fail関数は,不正な間接関数呼び出しを検出するコードの生成の対象になりません。

-

__control_flow_chk_fail関数内ではabort()を呼び出してプログラムを終了するなど,チェック関数に戻らないように注意してください。

-

-picオプションを同時に指定した場合,エラーとなります。

[例]

-

<Cソース>

#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();
}

 

-

<出力コード>

-S -control_flow_integrityを指定してコンパイルした場合

___control_flow_chk_fail:
    .stack ___control_flow_chk_fail = 4
    prepare 0x00000001, 0x00000000
    jarl _abort, r31
    dispose 0x00000000, 0x00000001, [r31]
_func1:
    .stack _func1 = 0
    movhi HIGHW1(#_glb), r0, r2
    ld.w LOWW(#_glb)[r2], r5
    add 0x00000001, r5
    st.w r5, LOWW(#_glb)[r2]
    jmp [r31]
_func2:
    .stack _func2 = 0
    movhi HIGHW1(#_glb), r0, r2
    ld.w LOWW(#_glb)[r2], r5
    add 0xFFFFFFFF, r5
    st.w r5, LOWW(#_glb)[r2]
    jmp [r31] 
_main:
    .stack _main = 8
    prepare 0x00000041, 0x00000000
    movhi HIGHW1(#_pf), r0, r20
    ld.w LOWW(#_pf)[r20], r20
    mov r20, r6
    jarl ___control_flow_integrity, r31 ; チェック関数の呼び出し
    jarl [r20], r31 ; func1関数の間接呼び出し
    jarl _func2, r31 ; func2関数の直接呼出し
    dispose 0x00000000, 0x00000041, [r31] 
    .section .bss, bss
    .align 4
_glb:
    .ds (4)
    .section .data, data
    .align 4
_pf:
    .dw #_func1
    .section .const, const