FIO37-C. fgets() や fgetws() が読み取り成功時に空でない文字列を返すと想定しない
読み取るデータの種類について間違った想定をしていると、エラーが発生する可能性がある。たとえば、ユーザの端末からテキストデータが読み取られる、あるいはプロセスの出力が stdin
にパイプされるはずが、実際にはファイルからバイナリデータが読み取られている場合には、こうした想定がくつがえされる可能性がある (「FIO14-C. ファイルストリームにおけるテキストモードとバイナリモードの違いを理解する」を参照)。システムによっては、キーボードから null バイト(や他のバイナリデータ)を入力できる場合もある。
C 言語規格 [ISO/IEC 9899:2011] 7.21.7.2 節には、次のように記載されている。
fgets
関数は、成功するとs
を返す。ファイルの終わりを検出し、かつ配列に1文字も読み取っていなかった場合、配列の内容を変化させずに残し、空ポインタを返す。
ワイド文字を読み取る fgetws()
関数も同様の動作をする。したがって、fgets()
あるいは fgetws()
が null でないポインタを返すならば、配列には実際にデータが格納されていると仮定しても安全であろう。しかし、配列に空でない文字列が含まれていると仮定するのは間違いである。なぜなら、データにはナル文字が含まれているかもしれないからだ。
違反コード
次の違反コード例では、入力行から末尾の改行 (\n
) を削除しようとしている。fgets()
関数は、通常、改行で終わる行を入力ストリームから読み込むために使用される。fgets()
は、サイズ引数をとり、ストリームから文字配列へ、最大で size - 1
文字までコピーする。
#include <stdio.h> #include <string.h> enum { BUFFER_SIZE = 1024 }; void func(void) { char buf[BUFFER_SIZE]; if (fgets(buf, sizeof(buf), stdin) == NULL) { /* エラー処理 */ } buf[strlen(buf) - 1] = '\0'; }
strlen()
関数は、終端ナル文字より前にある文字数を数えることで、文字列長を計算する。fgets()
が入力から読み取る最初の文字が偶然ナル文字である場合、問題が発生する。問題が発生するのは、たとえば fgets()
がバイナリデータファイルを読み取る場合などである [Lai 2006]。buf
の最初の文字がナル文字の場合、strlen(buf)
は 0 を返すので、式 strlen(buf) - 1
はラップアラウンドして大きな正の値になり、境界外書込みエラーが発生する。
適合コード
次の適合コードでは、strchr()
を使い、文字列中に改行文字が存在する場合にそれを置き換えるという操作を行っている。
#include <stdio.h> #include <string.h> enum { BUFFER_SIZE = 1024 }; void func(void) { char buf[BUFFER_SIZE]; char *p; if (fgets(buf, sizeof(buf), stdin)) { p = strchr(buf, '\n'); if (p) { *p = '\0'; } } else { /* エラー処理 */ } }
リスク評価
文字データが読み取られていると間違って想定すると、配列境界外書き込みやその他の欠陥を作り込むことにつながる。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
FIO37-C |
高 |
中 |
中 |
P12 |
L1 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Compass/ROSE |
|
|
このルールの違反を一部検出できる。たとえば、先に挙げた違反コード例の場合であれば、 |
Fortify SCA |
5.0 |
|
|
関連するガイドライン
CERT C Secure Coding Standard | FIO14-C. ファイルストリームにおけるテキストモードとバイナリモードの違いを理解する FIO20-C. Avoid unintentional truncation when using fgets() or fgetws() |
CERT C++ Secure Coding Standard | FIO37-CPP. Do not assume character data has been read |
MITRE CWE | CWE-119, Failure to constrain operations within the bounds of an allocated memory buffer CWE-241, Failure to handle wrong data type |
参考資料
[ISO/IEC 9899:2011] | 7.21.7.2, "The fgets Function"7.29.3.2, "The fgetws Function" |
[Lai 2006] | |
[Seacord 2013] | Chapter 2, "Strings" |
翻訳元
これは以下のページを翻訳したものです。
FIO37-C. Do not assume that fgets() or fgetws() returns a nonempty string when successful (revision 73)