STR38-C. ナロー文字列に対するワイド文字関数の使用、およびその逆を避ける
ASCII 文字集合のワイド文字を操作している場合、文字列の中に null バイトが含まれている可能性が高い。そのため、null バイト終端を想定しているナロー文字関数の使用は、正しくない動作を引き起こす可能性がある。同様に、適切に null 終端されたナロー文字列は、ワイド文字関数においてそのように見なされないこともあり得る。ナロー文字列とワイド文字列を適切に使用しないと、バッファオーバーフローを引き起こす可能性がある。
違反コード (wcsncpy
の代わりに strncpy
を使用)
以下のコード例は strncpy
を使用している。この関数は最大 10 バイトコピーするが、null バイトに達するとコピーを中止する。ワイド文字は null バイトを含んでいることが考えられるため、コードは途中でコピーを中止する可能性がある。ナロー文字列関数の多くはバイト単位で文字列を処理する関数であるため、途中で終了する可能性があることを認識しておくことが重要である。
wchar_t wide_str1[] = L"0123456789"; wchar_t wide_str2[] = L"0000000000"; strncpy(wide_str2, wide_str1, 10);
違反コード (strncpy
の代わりに wcsncpy
を使用)
ほとんどの処理系では、ワイド文字 1 文字はナロー文字複数文字分のサイズがある。wcsncpy
関数は、ワイド文字を最大 10 文字分コピーするが、その長さは narrow_str1
よりも長い。そのため、narrow_str1
の最初の 10 バイトを narrow_str2
に書き込み、その後ワイド文字 10 文字分が書き込まれるまで、null ワイド文字 L'\0'
による埋め込みを続ける。
コピー元の文字列にコピー先の文字列よりも多くのワイド文字が含まれていた場合、wcsncpy
は null 終端を行わない点に注意する。それゆえ、攻撃者は故意に細工した文字列を wcsncpy
に渡すことによって、この脆弱性を悪用する可能性がある。wcsncpy
はバイト単位ではなくワイド文字単位でコピーを行う手段であるため、一定のバイト数だけコピーすることを意図している場合、マルチバイトの書き込みによってバッファがあふれる可能性がある。
char narrow_str1[] = "0123456789"; char narrow_str2[] = "0000000000"; wcsncpy(narrow_str2, narrow_str1, 10);
処理系固有の詳細
C 標準では、wchar_t[]
と char[]
を異なる型として区別している。そのため、適切な関数が使用されていないと、多くのコンパイラは警告を発する。たとえば、上記の 2 つ目の違反コードを Linux i686 上の GCC でフラグなしでコンパイルすると、次の警告が表示された。
warning: passing arg 1 of `wcsncpy' from incompatible pointer type warning: passing arg 2 of `wcsncpy' from incompatible pointer type
1 つ目の違反コードに対しては、strncpy
関数の引数に関して同様の警告がコンパイラから出された。
これらは単なる警告であるため、コンパイル済みのコードは実行可能である。i686 Linux プラットフォーム上で実行すると、どちらの違反コードも、引数の範囲外の情報をコピーし始めた。この動作は、バッファオーバーフローの脆弱性の可能性を示している。
適合コード
以下の適合コードでは、ワイド文字とナロー文字に対して適切な関数を使用している。ワイド文字列に対して wcsncpy
を、ナロー文字列に対して strncpy
を使用することで、データの切り捨てや必要以上のメモリの上書きが行われないことが保証される。
wchar_t wide_str1[] = L"0123456789"; wchar_t wide_str2[] = L"0000000000"; wcsncpy(wide_str2, wide_str1, 10); /* 適切な幅の関数を使用 */ char narrow_str1[] = "0123456789"; char narrow_str2[] = "0000000000"; strncpy(narrow_str2, narrow_str1, 10); /* 適切な幅の関数を使用 */
リスク評価
ワイド文字とナロー文字に対して適切な文字列関数を使用しないと、バッファオーバーフローや、攻撃者による任意のコードの実行が引き起こされる可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
STR38-C |
高 |
高 |
低 |
P27 |
L1 |
自動検出(最新の情報はこちら)
最近のコンパイラは、char*
ポインタと wchar_t*
ポインタの違いを認識する。それゆえ、このルールに違反するコードをコンパイルすると警告が発せられる。不適切な幅の関数を認識して適切な幅の関数に置き換える機能(つまり、引数の型を wchar_t*
型と認識したら wcsncpy
を使用する機能)を実装することも可能だ。
翻訳元
これは以下のページを翻訳したものです。
STR38-C. Do not use wide-char functions on narrow-char strings and vice versa (revision 21)