POS34-C. putenv()の引数として自動変数へのポインタを渡さない
POSIX 関数 putenv()
を使い環境変数の値を設定することができる。putenv()
関数は、引数として渡された文字列のコピーを作成しない。文字列へのポインタを環境配列に挿入する。自動記憶域期間を持つバッファを指すポインタが putenv()
に引数として渡された場合、バッファに割り当てられたメモリは、呼び出し側の関数がリターンしてスタックメモリが再利用されるとき、上書きされるかもしれない。この動作は、Open Group Base Specifications Issue 6 [Open Group 2004] に次のように記されている。
エラーが発生する可能性があるのは、自動変数を引数として
putenv()
を呼び出し、string
がまだその環境の一部であるうちに、呼び出し側の関数から戻る場合である。
実際に問題が発生するのは、自動変数へのポインタを putenv()
に渡す場合である。静的バッファへの自動ポインタであれば意図した通りに動作する。
違反コード
次の違反コードでは、自動記憶域期間のバッファへのポインタを putenv()
への引数として使用している [Dowd 2006]。func()
が呼出し元にリターンし、env
を含むスタックフレームが再利用されたあとで TEST
環境変数がアクセスされた場合、環境変数の TEST
は意図せぬ値を取るかもしれない。
このコードは「DCL30-C. 適切な記憶域期間をもつオブジェクトを宣言する」にも違反していることに注意。
int func(const char *var) {
char env[1024];
int retval = snprintf(env, sizeof(env),"TEST=%s", var);
if (retval < 0 || (size_t)retval >= sizeof(env)) {
/* エラー処理 */
}
return putenv(env);
}
適合コード (static
)
次の適合コードでは、putenv()
の引数に静的配列を使用している。
int func(const char *var) { static char env[1024]; int retval = snprintf(env, sizeof(env),"TEST=%s", var); if (retval < 0 || (size_t)retval >= sizeof(env)) { /* エラー処理 */ } return putenv(env); }
適合コード (ヒープメモリ)
次の適合コードでは、putenv()
の引数のために動的にメモリを割り当てている。
int func(const char *var) { static char *oldenv; const char *env_format = "TEST=%s"; const size_t len = strlen(var) + strlen(env_format); char *env = (char *) malloc(len); if (env == NULL) { return -1; } int retval = snprintf(env, len, env_format, var); if (retval < 0 || (size_t)retval >= len) { /* エラー処理 */ } if (putenv(env) != 0) { free(env); return -1; } if (oldenv != NULL) { free(oldenv); /* メモリリークを回避する */ } oldenv = env; return 0; }
putenv()
関数よりも POSIX の setenv()
関数を使う方がよい[Open Group 2004]。
適合コード (setenv()
)
setenv()
関数は環境変数用のヒープメモリを割り当てる。こうすることで、値が容易に変更されるスタックメモリがアクセスされる可能性を排除している。
int func(const char *var) { return setenv("TEST", var, 1); }
putenv()
を使用するよりも setenv()
を使う方が簡単で間違いを作り込みにくい。
リスク評価
putenv
の引数として、自動記憶域期間のバッファへのポインタを使用した場合、バッファは想定外の値をとる可能性がある。バッファがいつどのように使用されるかにもよるが、プログラムが予期せぬ動作を引き起こしたり、攻撃者に任意のコードを実行される可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
POS34-C |
高 |
低 |
中 |
P6 |
L2 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
CodeSonar | 4.0 | (customization) | putenv() の使用を全て検出する独自のチェックを追加することができる |
Fortify SCA |
V. 5.0 |
|
CERT C Rule Packを使ってこのルールの違反を検出できる |
Compass/ROSE |
|
|
|
PRQA QA-C | v8.2 | warncall for putenv | 部分的に実装済み |
関連するガイドライン
MITRE CWE | CWE-686, Function call with incorrect argument type CWE-562, Return of stack variable address |
参考資料
[Dowd 2006] | Chapter 10, "UNIX Processes" |
[ISO/IEC 9899:2011] | Section 6.2.4, "Storage Durations of Objects" Section 7.22.3, "Memory Management Functions" |
[Open Group 2004] | putenv() setenv() |
翻訳元
これは以下のページを翻訳したものです。
POS34-C. Do not call putenv() with a pointer to an automatic variable as the argument (revision 104)