我在 RHEL 8.x / 9.x 中运行 gcc 'C' 代码,该代码已被标记为具有 'TOCTOU 竞争条件'。
它先执行 mkdir(),然后执行 chmod(),SonarQube 指向 chmod()。
我认为它是在抱怨有人可能在 mkdir() 和 chmod() 之间做坏事,导致替换文件或符号链接被“chmod()”编辑,而不是我创建的新目录。
我执行后续 chmod() 的原因是因为 umask 值将更改我在 mkdir() 上指定的权限,因此 chmod() 可以将文件权限“修复”为我最初要求的内容。
由于我的代码是更大系统的一部分,并且被各种程序作为共享对象中的条目调用,因此我无法修改 umask,因为它会更改整个进程和任何其他线程的 umask同时运行可能会改变其文件创建行为。 (我无法控制可能从同一进程运行的任何其他线程,或用于启动给定进程的 umask)。
我的印象是我无法使用 open() 创建目录(这将允许我在打开的句柄上使用 fchmod() 并可能避免竞争条件)。
是否有一些“标准”方法可以避免这场 TOCTOU 比赛?
仅当尝试在所述子目录中创建文件失败并显示“ENOENT”时,才会真正调用“创建子目录”代码(假设失败原因是子目录不存在)。
(我试图在“/tmp”类型目录中创建这个子目录,该目录在每次系统重新启动时都会被删除。我想要创建的文件将进入我的新子目录,并且该子目录预计在重新启动后第一次调用我的代码时需要创建)。
类似:
strcpy(temp_dir_path, "/tmp/new-dir");
strcpy(f_name, "/tmp/new-dir/xyzzy");
fd = open( f_name,
O_CREAT | O_RDWR | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1)
{
if (errno == ENOENT)
{ /***************************************************************/
/* Presume this is because the sub-directory under /tmp */
/* doesn't yet exist. Try to create it. */
/***************************************************************/
rc = create_subdir(temp_dir_path);
...
我执行后续 chmod() 的原因是因为 umask 值将更改我在 mkdir() 上指定的权限,因此 chmod() 可以将文件权限“修复”为我最初要求的内容。
如果您使用
0000
作为 mkdir
的权限参数,那么在新目录创建到 chmod
发生之间,每个人都将完全无法访问该目录(root 可能除外,但 root 无论如何都是受信任的) ,因此您无需担心任何人利用不正确的权限在新创建的目录上。 据我所知,这里没有系统调用(甚至在
*at
系列中也没有)创建目录并返回该目录的打开
O_PATH
/
O_SEARCH
fd。因此,如果您使用
0000
,那么 仍然是一场竞赛:有人可能会突然介入并修改
mkdir
和 chmod
之间的parent
目录,导致您
chmod
做错事。我认为没有任何办法可以避免这场比赛。然而,有两种应该无懈可击的解决方法:
root
拥有和写入,则让
root
创建您需要的目录并将其
chown
授予适当的用户。