POS30-C. readlink() 関数を適切に使用する
readlink() 関数は、第1引数に渡されたシンボリックリンクのリンク先を読み取り、第2引数が指すバッファに格納する。格納される文字列はナル終端されない。バッファに書き込んだ文字数が関数の返り値となる。
違反コード
このコード例では、len が sizeof(buf) と等しい場合、buf の終端を 1 バイト越えた場所にナル文字が書き込まれてしまう。
char buf[1024];
ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf));
buf[len] = '\0';
次の修正例では、buf を十分大きくし、結果を常に保持できるようにしようとしている。
long symlink_max;
size_t bufsize;
char *buf;
ssize_t len;
errno = 0;
symlink_max = pathconf("/usr/bin/", _PC_SYMLINK_MAX);
if (symlink_max == -1) {
if (errno != 0) {
/* エラー処理 */
}
bufsize = 10000;
}
else {
bufsize = symlink_max+1;
}
buf = (char *)malloc(bufsize);
if (buf == NULL) {
/* エラー処理 */
}
len = readlink("/usr/bin/perl", buf, bufsize);
buf[len] = '\0';
この修正では、シンボリックリンクのリンク先の長さは、pathconf() が返す SYMLINK_MAX の値を超えることはないと想定している。しかし、これは誤りである。pathconf() が返した値は readlink() が呼び出された時点で無効になっている可能性があり、オフバイワンバッファオーバーフローのリスクは依然として存在する。その理由は、これら2つの関数の呼出しの間に /usr/bin/perl の置かれている領域が、より大きな SYMLINK_MAX 値を持つファイルシステムに移動される可能性があるからである。また、SYMLINK_MAX が不定の場合(つまり pathconf() が -1 を返し errno も設定しない場合)、任意のバッファサイズ(このコード例では10,000)を十分なサイズであることを期待して使用しているが、readlink() が丁度このサイズを返す可能性がないとは言えないだろう。
また、readlink() は失敗した場合に -1 を返すので、その場合オフバイワンアンダーフローが発生する可能性がある。
適合コード
次の適合コードでは、バッファに書き込むのは sizeof(buf)-1 文字のみであるため、オーバーフローは発生しない。またエラーの発生を適切に確認している。
enum { BUFFERSIZE = 1024 };
char buf[BUFFERSIZE];
ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf)-1);
if (len != -1) {
buf[len] = '\0';
}
else {
/* エラー処理 */
}
リスク評価
readlink() の結果を適切にナル終端しないと、プログラムの異常終了やバッファオーバーフローにつながる可能性がある。
|
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
|---|---|---|---|---|---|
|
POS30-C |
高 |
中 |
中 |
P12 |
L1 |
自動検出(最新の情報はこちら)
|
ツール |
バージョン |
チェッカー |
説明 |
|---|---|---|---|
|
Compass/ROSE |
|
|
|
| Coverity | 6.5 | READLINK | 実装済み |
関連するガイドライン
| MITRE CWE | CWE-170, Improper null termination |
参考文献
| [Ilja 2006] |
| [Open Group 1997a] |
| [Open Group 2004] |
翻訳元
これは以下のページを翻訳したものです。
POS30-C. Use the readlink() function properly (revision 60)
