POS33-C. vfork() を使用しない
vfork
関数を使用すると可搬性やセキュリティに関する多くの問題が生じることになる。未定義の動作や処理系固有の動作が発生しうるケースが多数存在し、サービス運用妨害の脆弱性につながる可能性がある。
vfork
のマニュアルには次のように記載されている。
vfork()
関数はfork()
と同じ働きをするが、vfork()
が作成したプロセスが、vfork()
の戻り値を格納するためのpid_t
型変数以外のデータを変更した場合、vfork()
が呼び出された関数からリターンする場合、および_exit()
やexec
系の関数を正常に呼び出す前に他の関数を呼び出した場合、その動作は未定義である。
また、旧バージョンの Linux では、特権プロセスが vfork()
を呼び出し、次に、子プロセスが権限を降格して execve()
を呼び出す場合、競合状態が発生する可能性がある。子プロセスは、execve()
を呼び出す直前は、特権のないユーザの UID で実行されている。
vfork()
関数の実装では、子プロセスの実行中、親プロセスは停止する。ユーザが子プロセスにシグナルを送ってその実行を遅らせた場合、(特権を持つ)親プロセスもまたブロックされる。これは、特権を持たないプロセスが特権プロセスを停止させることができる、つまり権限の逆転を意味し、サービス運用妨害につながる可能性がある。
次のコード例は、未定義の動作を引き起こさずに vfork()
を使うことがいかに困難であるかを示している。権限を降格するには setuid()
を呼び出す必要があるが、呼出しが vfork()
と execve()
の間で行われるため、動作は未定義となる。
pid_t pid = vfork();
if (pid == 0) /* 子プロセス */ {
setuid(unprivileged_user); /* 未定義の動作 */
/*
* 旧バージョンの Linux では、権限回避の
* 競合ウィンドウがここにある
*/
if (execve(filename, NULL, NULL) == -1) {
/* エラー処理 */
}
/*
* 通常の動作では、execve() が失敗するかもしれない;
* 失敗した場合、vfork() の動作は未定義。
*/
_exit(1); /* execve() が失敗した場合 */
}
いかなる場合も vfork()
ではなく fork()
を使用すること。
違反コード
次の違反コードでは、vfork()
を呼び出してから execve()
を呼び出している。前述のとおり、vfork()
と execve()
を組み合わせて使用すると、処理系によっては競合ウィンドウの発生を避けられない。
char *filename = /* 適当なファイル名 */; pid_t pid = vfork(); if (pid == 0 ) /* 子 */ { if (execve(filename, NULL, NULL) == -1) { /* エラー処理 */ } _exit(1); /* execve() が失敗した場合 */ }
適合コード
次の適合コードでは、vfork()
を fork()
と置き換えることで競合状態を取り除き、サービス運用妨害の脆弱性を排除している。
char *filename = /* 適当なファイル名 */; pid_t pid = fork(); if (pid == 0) /* 子 */ { if (execve(filename, NULL, NULL) == -1) { /* エラー処理 */ } _exit(1); /* execve() が失敗した場合 */ }
リスク評価
vfork
関数を使用すると、サービス運用妨害の脆弱性を引き起こす可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
POS33-C |
低 |
中 |
低 |
P6 |
L2 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
CodeSonar | 4.0 | BADFUNC.VFORK | vfork の使用 |
8.5.4 |
|
|
|
Compass/ROSE |
|
|
|
Fortify SCA |
V. 5.0 |
|
|
9.1 |
SV.USAGERULES.PROCESS_VARIANTS |
|
|
PRQA QA-C | v8.2 | Warncall -wc vfork | 実装ずみ |
関連するガイドライン
MITRE CWE | CWE-242, Use of inherently dangerous function |
参考資料
[Wheeler 2003] | Section 8.6 |
翻訳元
これは以下のページを翻訳したものです。
POS33-C. Do not use vfork() (revision 72)