You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RHEL 8/9下gcc C代码mkdir()/chmod()的TOCTOU竞争条件解决咨询

解决mkdir() + chmod()的TOCTOU竞争问题(RHEL 8.x/9.x)

问题背景

你的代码在RHEL 8.x/9.x环境下运行,SonarQube检测到mkdir()后调用chmod()存在TOCTOU(时间检查-时间使用)竞争:mkdir()创建目录后到chmod()修改权限的间隙中,恶意进程可能将该路径替换为其他文件或符号链接,导致chmod()错误地修改无关对象的权限。

由于代码是共享库,无法修改进程umask(会影响整个进程及其他线程),且open()无法创建目录,因此无法通过fchmod()规避竞争。你的场景中,子目录位于重启即清空的/tmp类目录下,仅在创建子目录内文件返回ENOENT时才触发创建逻辑。

可行的标准解决方案

1. 父目录粘滞位 + 0权限mkdir(推荐)

/tmp类目录默认带有粘滞位(sticky bit),该权限确保只有目录所有者、文件所有者或root用户才能删除/重命名目录内的对象。利用这一特性,你可以:

  • 以0权限调用mkdir():umask不会对权限产生影响(0与任何umask按位与结果仍是0)
  • 立即调用chmod()设置目标权限

由于粘滞位的保护,恶意用户无法在mkdir()和chmod()的间隙中替换你刚创建的目录(当前进程是目录所有者,其他用户无权限修改该路径),彻底消除TOCTOU风险。

修改后的create_subdir函数示例:

int create_subdir(char *temp_dir_path)
{
    int rc = 0;

    // 以0权限创建目录,umask不影响最终初始权限
    rc = mkdir(temp_dir_path, 0);
    if (rc == 0) {
        // 立即设置目标权限
        rc = chmod(temp_dir_path, S_IRWXU | S_IRWXG | S_IRWXO);
    }

    return rc;
}

2. 额外验证目录属性(增强防护)

如果需要额外安全保障,可以在chmod()前添加lstat()检查,确认路径确实是当前进程创建的目录:

#include <unistd.h>

int create_subdir(char *temp_dir_path)
{
    int rc = 0;
    struct stat st;

    rc = mkdir(temp_dir_path, 0);
    if (rc == 0) {
        // 验证路径是目录,且所有者为当前进程
        if (lstat(temp_dir_path, &st) == 0 && S_ISDIR(st.st_mode) && st.st_uid == getuid()) {
            rc = chmod(temp_dir_path, S_IRWXU | S_IRWXG | S_IRWXO);
        } else {
            // 验证失败,清理目录并返回错误
            rmdir(temp_dir_path);
            rc = -1;
        }
    }

    return rc;
}

3. 使用mkdirat()(可选)

如果已打开父目录的文件描述符,可以使用mkdirat()替代mkdir(),确保创建的目录确实位于预期的父目录下,避免路径遍历攻击。结合粘滞位和0权限创建逻辑,同样能消除TOCTOU风险:

#include <fcntl.h>

int create_subdir(char *parent_dir, char *subdir_name)
{
    int rc = 0;
    int parent_fd = open(parent_dir, O_RDONLY | O_DIRECTORY);
    if (parent_fd == -1) {
        return -1;
    }

    // 以0权限在父目录下创建子目录
    rc = mkdirat(parent_fd, subdir_name, 0);
    if (rc == 0) {
        // 拼接路径后设置权限
        char full_path[256];
        snprintf(full_path, sizeof(full_path), "%s/%s", parent_dir, subdir_name);
        rc = chmod(full_path, S_IRWXU | S_IRWXG | S_IRWXO);
    }

    close(parent_fd);
    return rc;
}

关键前提

确保父目录(如/tmp)已正确设置粘滞位,可通过以下命令检查:

ls -ld /tmp

输出权限位包含t(如drwxrwxrwt)即表示粘滞位已启用。

内容的提问来源于stack exchange,提问作者MysteryGuy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 00:22:43