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)