You need to enable JavaScript to run this app. 如何解决stat校验目录后执行mkdir的TOCTOU类Coverity问题
优惠活动
大模型
产品
解决方案
定价
更多

如何解决stat校验目录后执行mkdir的TOCTOU类Coverity问题

Coverity检出的目录操作TOCTOU缺陷修复方案

缺陷产生的根因

现有实现是典型的TOCTOU(时间检查-使用时间不匹配)竞态:先通过stat做路径状态预判,再根据预判结果跨逻辑分支延迟执行mkdir、opendir操作,两次独立系统调用之间存在不受控的时间窗口——线程被调度挂起、其他进程介入篡改路径(比如把目标路径替换为指向系统敏感目录的恶意符号链接),都会让后续操作读写非预期路径,这也是Coverity检出该缺陷的核心判定依据。

核心修复逻辑

从根源上消除“预检查-延迟操作”的分离设计,把预判动作从流程最前端移到系统调用返回后即时执行,压缩所有可能的竞态窗口:

  • 取消最前面的stat预检查,直接发起mkdir(dir, S_IRWXU)调用。内核的mkdir是原子操作,不存在外部插入篡改的窗口
  • 完全基于mkdir的返回值和errno走分支,不依赖之前的预检查结果:
    • mkdir返回0:说明目录由当前调用成功创建,直接进入后续流程即可
    • mkdir返回-1时,仅对errno == EEXIST(目标路径已存在)的场景做即时校验,其他错误(无权限、上级目录缺失、磁盘满等)直接按失败处理
  • 即时校验环节的安全加固:
    • 用lstat替代原有的stat做路径属性检查:lstat不会跟随符号链接,只要目标路径本身是恶意符号链接,就会直接识别并拒绝,避免被诱骗访问非预期目录
    • 修正原代码的逻辑错配:原实现中stat校验的是dir变量,opendir却传入硬编码的fabcSsrDbStorageDir,两个路径不一致,校验逻辑完全失效,修复时要统一使用同一个路径变量
    • 拿到opendir返回的有效目录句柄后,后续涉及该目录的文件操作,优先使用基于目录句柄的相对路径调用(如openat系列接口),彻底避免后续操作被路径篡改影响

修复示例代码

#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
int ensure_storage_dir_valid(const char* dir) {
    struct stat stat_res;
    DIR* dir_fd = NULL;
    // 直接发起mkdir,不提前做状态预检查
    int mk_ret = mkdir(dir, S_IRWXU);
    if (mk_ret == 0) {
        return 0;
    }
    // 非“路径已存在”类错误直接返回
    if (errno != EEXIST) {
        return -1;
    }
    // 路径已存在,即时校验路径属性
    if (lstat(dir, &stat_res) == -1) {
        return -1;
    }
    // 拒绝非目录类型的路径(包括符号链接)
    if (!S_ISDIR(stat_res.st_mode)) {
        return -1;
    }
    // 统一用同一个dir变量打开目录
    dir_fd = opendir(dir);
    if (dir_fd == NULL) {
        return -1;
    }
    closedir(dir_fd);
    return 0;
}

适配Coverity规则的注意点

  • 整个流程中不存在跨分支的预检查逻辑,mkdir和后续的路径校验是连续执行的系统调用,无开放时间窗口,不会被Coverity判定为TOCTOU缺陷
  • 保留原有的目录权限设置(S_IRWXU),仅给运行进程的当前用户开放读写执行权限,避免目录权限过松带来的其他安全问题
  • 如果进程的umask会导致创建的目录权限偏离预期,可在创建成功后通过fchmod校准权限,不要依赖默认的umask值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 04:45:09