【问题标题】:Using stat() after fopen() to Avoid TOCTOU Problems?在 fopen() 之后使用 stat() 来避免 TOCTOU 问题?
【发布时间】:2019-03-27 21:47:19
【问题描述】:

标题说明了一切:可以使用stat() after 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 错误和错误权限错误?

【问题讨论】:

    标签: c posix fopen stat fstat


    【解决方案1】:

    编辑(2018-10-25):Toby Speight's answer 更好。

    一个解决方案:使用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;
    }
    

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

    【讨论】:

      【解决方案2】:

      不,问题中提供的代码不能避免 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;
      }
      

      【讨论】:

      • 我更喜欢这个。谢谢你。接受。
      猜你喜欢
      • 1970-01-01
      • 2011-09-25
      • 1970-01-01
      • 2014-05-23
      • 2016-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-14
      相关资源
      最近更新 更多