标题说明了一切:是否可以在{em> stat()
之后使用fopen()
来避免“检查时间到使用时间(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错误以及错误的权限错误?
答案 0 :(得分:6)
编辑(2018-10-25):Toby Speight's answer更好。
一个例子:
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;
}
我在问这个问题之前检查了我的所有基础时发现了这一点。
答案 1 :(得分:2)
否,问题中显示的代码不能避免参加TOCTOU比赛。
使用后的测试容易产生与使用前的测试完全相同的错误。在这两种情况下,名称都在两个不同的时间解析,结果可能不同。这是比赛的原因,无论哪种访问先发生都可能发生。
唯一避免这种情况的方法是打开文件一次,然后将获得的文件描述符用于所需的任何其他检查。现代操作系统为此提供了fstat()
之类的接口。
如果您想使用C的缓冲I / O,则可以使用FILE*
从fileno()
获取文件描述符-或者可以使用{ {1}}。
这需要对您的代码进行很小的更改:
FILE*
答案 2 :(得分:0)
Toby Speight 您能否让我知道您为什么使用:if(S_ISDIR(pstat.st_mode))。我们为什么要检查目录? 与缓解种族状况有关吗?