第10章 著名な脆弱性対策
C11:2011年以降のC言語仕様

2011年に発行された C言語仕様には対策が含まれている。

ISO/IEC 9899: 2011
Information technology -- Programming languages -- C

この「Annex K」に「Bounds-checking interfaces」が規範的(normative)な付録として規定されている。

あふれ対策

バッファオーバーフロー(あふれ)対策が施された strcpy_s 関数をはじめとする 37の関数が導入された。

strcpy_s (to, maxsize, from);

これらの関数は、いずれも領域長の引数(上記の例においては maxsize)をもち、データが入りきるか否かについて転記前にチェックされる。領域にデータが入りきらなければエラー(Runtime-constraint violation)として扱われ、転記は行われない。

厳密には、上記以外の振る舞いをする関数がいくつかある。37の関数の内訳は次のとおりである。

例として、文字列をコピーする典型的な関数 strcpy と、その後継の strcpy_s 関数について説明する。

従来の strcpy 関数においては、受け取り領域の大きさが一切、考慮されていなかった。領域が足りなくても、かまわずメモリへの書き込みが実行されて、あふれが起こっていた。

図

図10-13: 従来の strcpy

後継の strcpy_s 関数には、受け取り領域長の引数がある。この引数が参照されて、文字列を収容しきれるかについてのチェックが行われる。収容しきれないとき、受け取り領域には空列が置かれてエラーハンドラ関数が呼ばれる。

図

図10-14: 対策された strcpy_s

(言語規格においては「Runtime-sonstraint handler」と呼ばれる)エラーハンドラ関数としては、プログラマがあらかじめ割り当てておいたものが使われる。プログラマ自らがエラーハンドラ関数を記述することもできるし、ライブラリにあらかじめ用意されたものを利用することもできる。用意されているのは、プログラムを異常終了させる abort_handler_s 関数と、プログラムを続行させる ignore_handler_s 関数のふたつである。

参考:

フォーマット文字列注入攻撃対策

%n が廃止された。

追加され関数は28件にも及ぶ。それは、問題に該当する従来の C言語ライブラリ関数が多く存在することによる。従来の C言語ライブラリ関数が可変個引数に対応していいたため、それぞれについて対策関数を用意する必要があったのである。

その他の対策

細かな論点について、まとめて書く。

(1) 静的バッファの廃止

下記の関数において、結果を返す際に静的バッファを使用しないように改められた。

これらの関数の原型となった従来の関数(_s が付かない名前の関数)は、 あらかじめ用意されている特定の静的なバッファに値を書き込み、その領域へのポインタを戻り値として返している。そのため異なる 2箇所から呼び出されると、後から呼ばれたときの結果によって先の処理結果を上書きしてしまうのでプログラムが正しくない振る舞いをする懸念がある。

(2) ファイルオープンの排他モード "x"

fopen_s と freopen_s においては、オープンモード文字に、これまでの r、w、a 等に加えて x が仕様とされた。

FILE* f = fopen_s ("brand-new-file", "wx");

"x" は、オープン対象のファイルが事前に存在しないことを求めるものである。ファイルが既に存在していると、オープンは失敗する。これは、低レベル入出力関数 open のオープンフラグ引数値 O_EXCL に相当する。

"x"を用いると、新規生成ファイルに関するものに限定されるが、シンボリックリンク攻撃への対策としても使える。