CodeQL 文档

Time-of-check time-of-use 文件系统竞争条件

ID: cpp/toctou-race-condition
Kind: problem
Security severity: 7.7
Severity: warning
Precision: high
Tags:
   - security
   - external/cwe/cwe-367
Query suites:
   - cpp-code-scanning.qls
   - cpp-security-extended.qls
   - cpp-security-and-quality.qls

点击查看 CodeQL 存储库中的查询

通常,在使用文件之前需要检查文件的状态。这些检查通常需要文件名作为检查对象,如果检查返回肯定结果,则打开文件或对其进行其他操作。

但是,在检查和操作之间的时间段内,攻击者可能会更改文件名所引用的基础文件,从而导致意外行为。

建议

尽可能使用对文件描述符而不是文件名进行操作的函数(例如,使用 fchmod 而不是 chmod)。

对于访问检查,您可以临时将 UID 和 GID 更改为要检查其权限的用户的 UID 和 GID,然后执行操作。这样做可以“原子地”将权限检查与操作结合起来。

如果您的平台上提供了文件系统锁定工具,则在检查之前锁定文件可以防止意外更新。但是,请注意,在某些平台(例如 Unix)上,文件系统锁通常是*建议性*的,因此攻击者可以忽略它们。

示例

以下示例显示了一个案例,其中打开了一个文件,然后,如果打开成功,则使用 chmod 更改其权限。但是,攻击者可能会在初始打开和权限更改之间更改文件名的目标,从而可能会更改其他文件的权限。

char *file_name;
FILE *f_ptr;
 
/* Initialize file_name */
 
f_ptr = fopen(file_name, "w");
if (f_ptr == NULL)  {
  /* Handle error */
}
 
/* ... */
 
if (chmod(file_name, S_IRUSR) == -1) {
  /* Handle error */
}

可以通过将 fchmod 与从打开文件接收到的文件描述符一起使用来避免这种情况。这可以确保将权限更改应用于与打开的文件完全相同的文件。

char *file_name;
int fd;
 
/* Initialize file_name */
 
fd = open(
  file_name,
  O_WRONLY | O_CREAT | O_EXCL,
  S_IRWXU
);
if (fd == -1) {
  /* Handle error */
}
 
/* ... */
 
if (fchmod(fd, S_IRUSR) == -1) {
  /* Handle error */
}

参考

  • ©GitHub 公司
  • 条款
  • 隐私