C语言 在 fopen() 之后使用 stat() 来避免 TOCTOU 问题?



>Title说明了一切:是否可以在fopen()使用stat()来避免检查时间到使用时间(TOCTOU(竞争条件?

一些细节:

我正在编写一个读取文件的 C 程序,但在被要求读取目录时需要正确错误。截至目前,它使用open()(带O_RDWR(生成错误,然后检查errno是否有EISDIR,如下所示:

int fd = open(path, O_RDWR);
if (fd == -1) {
if (errno == EISDIR) return PATH_IS_DIR;
else return FILE_ERR;
}

上述解决方案的问题在于该程序只需要读取文件,因此通过打开带有O_RDWR的文件,如果用户具有读取权限,但没有写入权限,我可能会错误地收到权限错误。

是否可以执行以下操作来避免TOCTOU竞争条件?

struct stat pstat;
FILE *f = fopen(path, "r");
if (!f) return FILE_ERR;
if (stat(path, &pstat) == -1) {
fclose(f);
return FILE_ERR;
}
if (S_ISDIR(pstat.st_mode)) {
fclose(f);
return PATH_IS_DIR;
}

如果不可能,是否有其他解决方案可以防止TOCTOU错误和错误的权限错误?

不,问题中提供的代码并不能避免 TOCTOU 比赛

使用后测试容易出现与使用前测试完全相同的错误。 在这两种情况下,名称在两个不同的时间解析,结果可能不同。 这是比赛的原因,无论先发生什么访问,它都可能发生。

避免这种情况的唯一方法是打开文件一次,并使用由此获得的文件描述符进行所需的任何其他检查。 现代操作系统正是为此目的提供了诸如fstat()之类的接口。

如果要使用 C 的缓冲 I/O,可以使用fileno()FILE*获取文件描述符 - 也可以使用fdopen()从文件描述符创建FILE*

它需要对代码进行非常小的更改:

# Untested
struct stat pstat;
FILE *f = fopen(path, "r");
if (!f) return FILE_ERR;
if (fstat(fileno(f), &pstat) == -1) {
//  ^^^^^^^^^^^^^^^                         <-- CHANGED HERE
fclose(f);
return FILE_ERR;
}
if (S_ISDIR(pstat.st_mode)) {
fclose(f);
return PATH_IS_DIR;
}

编辑(2018-10-25(:托比·斯佩特的答案更好。

有一个解决方案:使用open(),然后fstat().

举个例子:

struct stat pstat;
int fd = open(path, O_RDONLY);
if (fd == -1) return FILE_ERR;
if (fstat(fd, &pstat) == -1) {
close(fd);
return FILE_ERR;
}
if (S_ISDIR(pstat.st_mode)) {
close(fd);
return PATH_IS_DIR;
}

在问这个问题之前,我在检查我是否已经涵盖了我所有的基地时发现了这一点。

相关内容

  • 没有找到相关文章

最新更新