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
通常,在使用文件之前需要检查文件的状态。这些检查通常需要文件名作为检查对象,如果检查返回肯定结果,则打开文件或对其进行其他操作。
但是,在检查和操作之间的时间段内,攻击者可能会更改文件名所引用的基础文件,从而导致意外行为。
建议¶
尽可能使用对文件描述符而不是文件名进行操作的函数(例如,使用 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 */
}
参考¶
CERT Oracle C 安全编码标准: FIO01-C. 使用使用文件名进行标识的函数时要小心 。
常见弱点枚举:CWE-367。