MSC16-C. 関数ポインタの暗号化を検討する
メモリ内の関数の位置はコンパイル時に計算され、プログラムで後で使用するために格納される。攻撃者が特定の関数ポインタを上書きすると、任意のコードの実行が可能になることがある。このような攻撃の影響を緩和するには、関数へのポインタを、プロセスの特性に基づき実行時に暗号化し、実行中のプロセスだけが関数ポインタを復号できるようにするとよい。
違反コード
以下のコード例は printf() のアドレスを関数ポインタ log_fn に代入しているが、この関数ポインタはスタック内またはデータセグメント内に割り当てられる可能性がある。
int (*log_fn)(const char *, ...) = printf; /* ... */ log_fn("foo");
関数ポインタ log_fn の上書きを攻撃者に許すような脆弱性がこのプログラムに存在する場合(バッファオーバーフローや任意のメモリ書き込みなど)、攻撃者は printf の値を任意の関数のアドレスで上書きすることができる。
適合コード (Windows)
Microsoft Windows は、プロセスに固有の秘密鍵を使用してポインタの暗号化と復号を行う、EncodePointer() 関数と DecodePointer() 関数を提供している。
int (*log_fn)(const char *, ...) = EncodePointer(printf); /* ... */ DecodePointer(log_fn)("foo");
適合コード (C1X)
これら2つの関数に似た関数を、C言語規格の C1X に含めることが検討されている。
C1X は encode_pointer() が以下の動作を行うことを定義している。
encode_pointer 関数は pf 引数に対して変換を実行し、decode_pointer 関数はその逆変換を行う。それゆえ関数 pfun へのポインタは、pfun 型に変換されると pfun に等しくなる。decode_pointer(encode_pointer( (void(*)()) pfun )
int (*log_fn)(const char *, ...) = encode_pointer(printf); /* ... */ decode_pointer(log_fn)("foo");
リスク評価
レコメンデーション | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
MSC16-C | 高 | 低 | 低 | P9 | L2 |
参考情報
- [MSDN] EncodePointer(), DecodePointer()
- [MITRE 07] CWE-311, "Missing Encryption of Sensitive Data"
翻訳元
これは以下のページを翻訳したものです。