JPCERT コーディネーションセンター

安全・安心なIT社会のための、国内・国際連携を支援する

お問い合わせ サイトマップ English

Home > ラーニング > セキュアコーディング > C セキュアコーディングスタンダード > 07. 文字と文字列 (STR)

最終更新: 2011-01-06

STR38-C. ナロー文字列に対するワイド文字関数の使用、およびその逆を避ける


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 を使用)

以下の例では、wcsncpy を使用してワイド文字を 10 文字コピーしている。ほとんどの処理系では、ワイド文字 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);
処理系固有の詳細

C99 では、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 を使用する)機能を実装することも可能だ。

関連ガイドライン
  • ISO/IEC 9899:1999 Section 7.21.2.4, "The strncpy function"
  • ISO/IEC 9899:1999 Section 7.24.4.2.2, "The wcsncpy function"
翻訳元

これは以下のページを翻訳したものです。

STR38-C. Do not use wide-char functions on narrow-char strings and vice versa (revision 13)

Top へ