这是一个概念验证程序,用于触发并证明 rb_per_cpu_empty 中的逻辑错误。触发该错误的程序将会在内核空间的 tracing_read_pipe 中陷入忙等待死循环,并且无法通过任何 UNIX 信号(包括 SIGKILL)挂起或终止。
尽管该程序的行为(死循环和 CPU 燃烧)与 linux 4.5 中修复 的 seq_buf_used 计算错误类似,但本程序旨在证明另一个具有完全不同原因的错误的存在,据信该错误存在于 3.10 至 5.14-rc1 版本的内核中(另请参见 PoC 执行结果)。
免责声明:此概念验证程序可能会导致您的 Linux 系统卡死、消耗大量电量,并且在触发时无法通过 UNIX 信号终止,使用风险自负。
在执行概念验证脚本之前,必须安装以下软件包或命令。
gcc
realpath
nm
Bash 及字符串处理命令(如 awk 和 grep)也是必需的,并且您的发行版中可能已随附。
虽然这是一个 bash 脚本,但指定 uprobe 的代码部分是平台相关的(我们不能在 uprobe 中使用 $argN),我们支持 i386、x86_64、arm 和 aarch64。欢迎您添加自己的平台支持。
要运行概念验证,只需以 root 权限 执行以下命令:
./rbdetonate

如果概念验证成功触发该错误,将会创建一个占用整个 CPU 核心的 dd 进程,并且无法通过 UNIX 信号(如 SIGKILL)将其杀死。
rbdetonate 脚本的 bash 进程可以被杀死,但是否能通过发送 SIGINT 信号终止它取决于 bash 的实现。较新版本的 bash 只能在生成的 dd 进程运行时才能通过 SIGINT 终止。

如果在多次重试后无法创建 dd 进程,rbdetonate 可能会退出并打印 Nothing buggy has been detected。然而,由于我们重试了 8192 次,这可能需要一些时间。
备注:理论上,此错误存在于所有具有用户空间跟踪功能的版本(>=3.10)中,但旧版内核的 uprobe 在许多方面无法正常工作。如果您能帮助我们纠正其行为,我们将不胜感激。
答:只需以 root 权限执行命令
echo > /sys/kernel/debug/tracing/instances/rbdetonate/trace
即可将程序从死循环中拉出。
答:不需要。此处使用的构建工具仅用于构建 rbwrite 程序,该程序按照我们设计的步骤仅通过写入 CPU#0 上的环形缓冲区页面来产生确定性的结果。
对于此概念验证,简单的已编译版本的 rbwrite 程序代码也可以使用,之后可以检索跟踪点的地址。
对于使用 linux 跟踪,如果您不介意应用程序产生的噪声,向系统调用和内核函数添加 kprobe 跟踪点也会生成事件。但对于概念验证来说,这可能会引入不确定性,因此不推荐。
| 版本 | 是否复现 | 截图 |
|---|
| 5.14.0-rc2-00479-g86020194bc7e (修复版本) | N | 5.14.0-rc2-00479-g86020194bc7e.png |
| 5.14.0-rc2-00478-g2734d6c1b1a0 (5.14.0-rc2) | Y | 5.14.0-rc2-00478-g2734d6c1b1a0.png |
| 5.4.0-77-generic | Y | 5.4.0-77-generic.png |
| 4.4.0-142-generic | Y | 4.4.0-142-generic.png |