-control_flow_integrity 【Professional版のみ】 【V2.08.00以降】


コンパイル・オプション / オブジェクトオプション

[指定形式]

-control_flow_integrity

 

-

省略時解釈

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

[詳細説明]

-

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

本オプションを指定すると、C/C++ソース・ファイル内に次の処理を行うコードを生成します。

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

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

このように、関数呼び出しをはじめとして、プログラムの流れ(制御フロー)を変える処理の整合性をチェックすることを,Control Flow Integrity(CFI)と呼びます。

-

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

void __control_flow_integrity(void *addr);

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

-

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

詳細は2.5.3 最適化リンケージエディタ(rlink)・オプションを参照してください。

-

__control_flow_chk_fail関数には不正な間接関数呼び出しの検出時に実行する処理を記述します。この関数はユーザが定義する必要があります。

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

-

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

-

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

-

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

-

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

-

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

-

C++プログラム内で__control_flow_chk_fail関数を定義する場合は「extern "C"」を付加してください。

-

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

 

-

<出力コード>

-isa=rxv2 -output=src -control_flow_integrityを指定してコンパイルした場合

___control_flow_chk_fail:
  .STACK ___control_flow_chk_fail=4
  BRA _abort
_func1:
  .STACK _func1=4
  MOV.L #_glb, R14
  MOV.L [R14], R15
  ADD #01H, R15
  MOV.L R15, [R14]
  RTS
_func2:
  .STACK _func2=4
  MOV.L #_glb, R14
  MOV.L [R14], R15
  SUB #01H, R15
  MOV.L R15, [R14]
  RTS
_main:
  .STACK _main=8
  PUSH.L R6
  MOV.L #_pf, R6
  MOV.L [R6], R1
  BSR ___control_flow_integrity ; チェック関数の呼び出し
  MOV.L [R6], R14
  JSR R14 ; func1関数の間接呼び出し
  BSR _func2 ; func2関数の直接呼び出し
  RTSD #04H, R6-R6
  .SECTION D,ROMDATA,ALIGN=4
_pf:
  .lword _func1
  .SECTION B,DATA,ALIGN=4
_glb:
  .blkl 1
  .END