SC Workbook
科目 A-2 · セキュリティ

access() と open() の競合

setuid root で動作するプログラムに次のコードがある。このプログラムは,実行した利用者に書込み権限があるファイルにだけ書き込むことを意図しており,path は利用者が指定したファイル名である。

if (access(path, W_OK) == 0) {
    fd = open(path, O_WRONLY);
    write(fd, buf, len);
}

このコードに関する記述として,適切なものはどれか。

  1. アaccess() は実効ユーザ ID で権限を検査するので,setuid root で動作するこのプログラムでは検査が常に成功し,利用者は任意のファイルに書き込める。
  2. イaccess() と open() の間には他の処理がなく,その間の時間が極めて短いので,競合状態が生じる余地はなく,コードを変更する必要はない。
  3. ウaccess() による検査の後,open() までの間に,path が指すファイルを書込み権限のないファイルへのシンボリックリンクに置き換えられると,root 権限で書き込まされる。
  4. エaccess() の前に lstat() で path がシンボリックリンクでないことを確認しておけば,その後にファイルを置き換えられても,root 権限で書き込まされることはない。
正解と解説を見る

正解 ウ

この問題の基礎知識

  • TOCTOU(Time Of Check To Time Of Use)は,資源を検査した時点と利用する時点との間に資源の状態が変わり得ることによって生じる競合状態の脆弱性である。
  • setuid root のプログラムは,実行した利用者ではなくファイルの所有者である root の権限(実効ユーザ ID)で動作する。access() は実行した利用者(実ユーザ ID)の権限で検査する関数である。
  • ファイル名で対象を指定する処理は,検査の後にファイルをシンボリックリンクなどに置き換えられると別のファイルを操作し得る。検査を増やしても競合は解消しないので,実行者の権限に切り替えてから操作するなど,検査と利用を分けない対策をとる。
アaccess() は実効ユーザ ID で権限を検査するので,setuid root で動作するこのプログラムでは検査が常に成功し,利用者は任意のファイルに書き込める。

access() は,プログラムを実行した利用者が必要な権限をもつかどうかを検査し,権限がなければ失敗を返す。検査自体は意図どおりに機能するが,検査と利用との間でファイルが変わり得ることが問題である。

イaccess() と open() の間には他の処理がなく,その間の時間が極めて短いので,競合状態が生じる余地はなく,コードを変更する必要はない。

検査と利用の間隔を短くしても攻撃を難しくするだけで,問題は解消しない(CWE-367)。攻撃者はファイルの置換えを繰り返し試み,その間隔に割り込むことができる。

ウaccess() による検査の後,open() までの間に,path が指すファイルを書込み権限のないファイルへのシンボリックリンクに置き換えられると,root 権限で書き込まされる。正解

access() と open() はファイル名で対象を指定するので,検査時と利用時に同じファイルを指す保証がない。検査後にシンボリックリンクへ置き換えられると,root 権限で本来書き込めないファイルを操作してしまう(TOCTOU,CWE-367)。

エaccess() の前に lstat() で path がシンボリックリンクでないことを確認しておけば,その後にファイルを置き換えられても,root 権限で書き込まされることはない。

lstat() による確認も検査の一つにすぎず,確認の後にファイルをシンボリックリンクへ置き換えられれば同じ問題が起きる。検査を増やしても検査と利用の間の競合は解消しないので,実行者の権限に切り替えてから open() するなどの対策が必要である。

検証用の出典出典照合済み
CWE-367 Time-of-check Time-of-use (TOCTOU) Race Condition
照合の根拠(6 件)
  • ア(誤り): access() はプログラムを実行した利用者の権限を検査し,権限がなければ失敗を返す
    The call to access() behaves as expected, and returns 0 if the user running the program has the necessary permissions to write to the file, and -1 otherwise.
    CWE-367 · Demonstrative Examples (Example 2)(新しいタブで開きます)
  • ウ(正解): 検査と利用がファイル名で対象を指定するので,同じファイルを指す保証がない
    However, because both access() and fopen() operate on filenames rather than on file handles, there is no guarantee that the file variable still refers to the same file on disk when it is passed to fopen() that it did when it was passed to access().
    CWE-367 · Demonstrative Examples (Example 2)(新しいタブで開きます)
  • ウ(正解): 検査後にシンボリックリンクへ置き換えられると root 権限で本来書き込めないファイルを操作する
    If an attacker replaces file after the call to access() with a symbolic link to a different file, the program will use its root privileges to operate on the file even if it is a file that the attacker would otherwise be unable to modify.
    CWE-367 · Demonstrative Examples (Example 2)(新しいタブで開きます)
  • イ(誤り): 検査と利用の間隔を短くしても問題は解消しない
    then try to limit the amount of time (CPU cycles) between the check and use of the resource. This will not fix the problem, but it could make it more difficult for an attack to succeed.
    CWE-367 · Potential Mitigations(新しいタブで開きます)
  • エ(誤り): シンボリックリンクかどうかの確認の後に置き換えられれば同じ問題が起きる
    However, an attacker may be able to change the file from a real file to a symbolic link between the calls to is_link() and file_get_contents(), allowing the reading of arbitrary files.
    CWE-367 · Demonstrative Examples (Example 3)(新しいタブで開きます)
  • エ(誤り)の解説で示す対策: 実行者の権限に切り替えてから操作する
    When the file being altered is owned by the current user and group, set the effective gid and uid to that of the current user and group when executing this statement.
    CWE-367 · Potential Mitigations(新しいタブで開きます)

問題のコードは CWE-367 の例と同じく access() で検査した後にファイル名で open() するので,その間にファイルを置き換えられる(open() と fopen() の違いは論点に影響しない)。

問題 ID A2-SEC-0530 · AI 作成のオリジナル問題 · 正解と各選択肢の根拠を出典の原文で確認しています。 照合日 2026-11-08

非公式の学習用アプリです(IPA とは関係ありません)。問題はすべて AI が作成したオリジナルで、誤りを含む場合があります。