1

如何避免 stat 和 rename for LOGFILE 之间的竞争条件的 TOCTOU(time-of-check, ti​​me-of-use) 竞争条件?

需要在其大小值超过最大大小后移动日志文件。

result = stat(LOGFILE, & data);
if (result != 0) {
  // stat failed
  // file probably does not exist
} else if (data.st_size > MAX_LOGSIZE) {
  unlink(PREV_LOGFILE);
  (void) rename(LOGFILE, PREV_LOGFILE);
}
4

1 回答 1

2

避免对文件操作进行 TOCTTOU 的标准方法是对open文件执行一次,然后通过文件描述符而不是文件名执行您需要的所有操作。

但是,重命名和取消链接文件都需要它的路径(因为他们需要知道要重命名或删除哪个链接),因此您不能在此处使用该方法。另一种方法可能是将文件的内容复制到其他地方,然后将其截断为零字节,尽管您的日志文件方案可能要求操作是原子的,这可能难以实现。另一种方法是要求对目录进行严格的访问控制:如果攻击者无法写入目录,那么它就无法与您的进程玩 TOCTTOU 游戏。您可以使用unlinkatandrenameat将路径限制为特定目录的文件描述符,这样您就不必担心目录本身会发生变化。

假设一个类似 POSIX 的平台,像这样未经测试的代码可能会完成这项工作:

dirfd = open(LOGDIR, O_DIRECTORY);
// check for failure
res = fstatat(dirfd, LOGFILE, statbuf, AT_SYMLINK_NOFOLLOW);
if ((0 == res) && (S_ISREG(statbuf) && (data.st_size > MAX_LOGSIZE)) {
    unlinkat(dirfd, PREV_LOGFILE, 0);
    renameat(dirfd, LOGFILE, dirfd, PREV_LOGFILE);
}
close(dirfd);
于 2019-06-27T06:00:48.047 回答