メインコンテンツ

チェック時と使用時 (TOCTOU) の間のファイル アクセス

アクセス競合によりファイルやフォルダーの状態が変化する可能性がある

説明

この欠陥は、ファイルまたはフォルダーの存在をチェックして使用するまでの間に競合状態が生じた場合に発生します。

リスク

攻撃者は、ファイルのチェックとファイルの使用の間に、そのファイルにアクセスして操作できます。攻撃者はシンボリック リンクが指す場所を変更できるため、シンボリック リンクは特にリスクが大きくなります。

修正方法

ファイルを使用する前は、そのステータスをチェックしないようにします。代わりに、ファイルを使用してから、その結果をチェックします。

すべて展開する

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

extern void print_tofile(FILE* f);

void writeToFile(char * log_path) {
    if (access(log_path, W_OK)==0) {
        FILE* f = fopen(log_path, "w");
        if (f == NULL) {
            print_tofile(f);
            fclose(f);
        }
    }
}

この例では、ファイルを開いて使用する前に、ファイルが存在するかどうかを関数 writeToFile() でチェックしています。しかし攻撃者は、関数の 1 行目と 2 行目の間でファイルを変更できます。

修正 — 排他モードでファイルを開く (POSIX)

POSIX® では、フラグ O_CREAT および O_EXCL を設定した open() 関数を使用すると、対象のファイルが既に存在する場合、ファイルを開く操作が失敗する可能性があります。ファイルに対してさらにアクションを実行する前に、エラーの有無を確認できます。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

extern void print_tofile(FILE* f);

void writeToFile(char * log_path) {
    int fd = open(log_path, O_CREAT | O_EXCL | O_WRONLY);
    if (fd!=-1) {
        FILE *f = fdopen(fd, "w");
        if (f) {
            print_tofile(f);
            fclose(f);
        }
    }
}
修正 — 排他モードでファイルを開く (C11)

C11 以降、関数 fopen() または fopen_s() を使用してファイルを開く際は、アクセス モード指定子に文字 x を含めることができます。対象のファイルが既に存在する場合、このアクセス モード指定子により、ファイルを開く操作が失敗します。ファイルに対してさらにアクションを実行する前に、エラーの有無を確認できます。

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

extern void print_tofile(FILE* f);

void writeToFile(char * log_path) {
        FILE* f = fopen(log_path, "wx");
        if (f == NULL) {
            print_tofile(f);
            fclose(f);
        }
}

結果情報

グループ: セキュリティ
言語: C | C++
既定値: オフ
コマンド ライン構文: TOCTOU
影響度: Medium

バージョン履歴

R2015b で導入