C11 (ISO/IEC 9899:2011) 仕様は2011年に規格化された C言語仕様であるが,C11 の改訂項目の特徴の1つとして脆弱性対策が挙げられる.
ここでは,C11仕様の Annex K で定められている関数 (実装はオプション扱い) の内,脆弱性対策用の主な関数を紹介する.
なお,C11 の仕様書は,Committee draft であれば www.open-std.org で閲覧可能である.
errno_t tmpfile_s(FILE * restrict * restrict streamptr);一時ファイルをモード "wb+"(更新用バイナリファイル)で作成して,引数で指定された場所にFILEポインタを格納する.作成されたファイルは,プログラムの終了時に自動的に削除される.
errno_t tmpnam_s(char *s, rsize_t maxsize);tmpnam関数は,生成された一時ファイルの名前を引数で渡した位置に格納するが,用意した領域のサイズを指定する方法がないため,常に領域あふれの危険が伴う.また,引数に nullポインタを指定した場合は,領域が自動的に確保されるが,マルチスレッドでの利用に問題がある (利用は推奨されない).
errno_t fopen_s(FILE *restrict *restrict streamptr, const char *restrict filename, const char *restrict mode);戻り値が errno_t になり,errno からエラーの原因を調べなくても良くなっている. fopen_s でファイルを開くと他のアプリケーションから開けなくなる.また,ファイルが既に存在するか生成できない場合にエラーになる排他モード("x")が追加されている.
char *gets_s(char *s, rsize_t n);gets 関数は,標準入力から1行分の文字列を読みメモリに格納する関数であるが,格納先メモリの長さを指定できないため,潜在的なバッファオーバーラン脆弱性がある.C11ではこの関数は削除され,fgets 関数か gets_s関数を用いることが推奨されている.
errno_t memcpy_s(void * restrict s1, rsize_t s1max, const void * restrict s2, rsize_t n);s2 で示されるオブジェクト位置から s1 で示されるオブジェクト位置に n 文字分コピーする.
errno_t memmove_s(void *s1, rsize_t s1max, const void *s2, rsize_t n);s2 で示されるオブジェクト位置から s1 で示されるオブジェクト位置に n 文字分コピーする.s1 と s2 がオーバラップしていてもよい.
errno_t strcpy_s(char * restrict s1, rsize_t s1max, const char * restrict s2);s2 で示される文字列 (終端のNULL文字を含む)を s1 で示される配列にコピーする.
errno_t strcat_s(char * restrict s1, rsize_t s1max, const char * restrict s2);s2 で示される文字列 (終端のNULL文字を含む)を s1 で示される文字列の後ろに追加する.
size_t strnlen_s(const char *s, size_t maxsize);s で示される文字列の長さを返す.s が NULLポインタの場合は,0 を返す.
errno_t memset_s(void *s, rsize_t smax, int c, rsize_t n);memset関数により後処理用に書き込んだメモリ内容(ダミーデータなど)にアクセスしないと,コンパイラが最適化のため実行を不要と判断し,memset関数の処理そのものを削除してしまう可能性がある.これに対して,memset_s関数ではメモリへの書き込みが行われることが保証される.
errno_t getenv_s(size_t * restrict len, char * restrict value, rsize_t maxsize, const char * restrict name);getenv関数は,指定された名前を持つ環境変数の値を指すポインタを返す.マルチスレッド環境では,あるスレッドがgetenv関数を呼んで環境変数へのポインタを取得した直後に別のスレッドが環境変数を変更し,競合状態(ポインタ値が無効)となる可能性がある.また,環境変数の最大長はプラットフォーム依存であり,ここで得られたポインタを使ってstrcpy関数などで内容をコピーするのは危険である.getenv_s関数は,環境変数の値をコピーするようになっており,また最大コピー長も指定できるようになっている.