# Bugs Rust Won't Catch——uutils审计揭示44个安全漏洞

2026年4月，Canonical披露了**uutils**（GNU coreutils的纯Rust重新实现）的外部安全审计结果：共计**44个CVE**被修复。令人深思的是，**这些漏洞中没有一个是**被Rust的borrow checker、Clippy或cargo audit发现的。

## 八大漏洞类型与防御建议

### 1. TOCTOU（检查时间与使用时间之间的竞态）
当程序先检查文件路径再操作同一路径时，攻击者可在两个系统调用之间将路径替换为符号链接。Rust的`std::fs` API每次都会重新解析路径。建议使用`OpenOptions::create_new(true)`或基于文件描述符而非路径进行操作。

### 2. 创建时设置权限，而非之后
`fs::create_dir`后再`set_permissions`存在权限窗口期。建议在创建时通过`OpenOptions::mode()`或`DirBuilderExt::mode()`直接设置权限。

### 3. 路径字符串相等≠文件系统身份
`file == Path::new("/")`的检查可以被`/../`、`/./`或符号链接绕过。应使用`fs::canonicalize`标准化后再比较。经典漏洞：`rm ./`成功删除了当前工作目录。

### 4. 在Unix边界使用字节，而非UTF-8字符串
Unix路径、环境变量、流数据是原始字节。使用`from_utf8_lossy`会导致静默数据损坏，`from_utf8`在非UTF-8输入下会崩溃。应使用`OsStr`、`&[u8]`、`Path`等类型。

### 5. 每个`panic!`都是拒绝服务攻击
在CLI工具中，`unwrap`、`expect`、索引操作等若被攻击者控制的输入触发，可导致进程中止。在cron/CI/脚本场景中会造成崩溃循环。

### 6. 传播错误，不要丢弃
`chmod -R`只返回最后一个文件的退出码而非最严重错误，可能导致脚本认为一切正常。`dd`对普通文件调用了`.ok()`静默丢弃错误，全盘写入时可能导致数据静默丢失。

### 7. 精确匹配原工具行为
`kill -1`被错误解析为"向PID -1发送默认信号"，导致系统级kill（向所有可见进程发送信号）。Rust重写需要Hyrum法则级别的bug-for-bug兼容性。

### 8. 跨越信任边界前解析输入
`chroot`漏洞：在新根文件系统内部再解析用户名，导致攻击者可以控制`/etc/passwd`来分配任意UID，实现本地提权。

## 核心教训

Rust的内存安全保证是强大工具，但它并不能解决所有安全问题。系统编程中**逻辑错误**、**竞态条件**和**API误用**仍然会产生严重漏洞。开发者在用Rust重写系统工具时，需要结合安全审计、模糊测试和防御性编程来弥补语言无法覆盖的安全盲区。

---

## 参考链接
- [corrode.dev: Bugs Rust Won't Catch](https://corrode.dev/blog/bugs-rust-wont-catch/)
