这是一套用于探索 Linux 内核竞态条件以及进行通用内核调试的工具。
另请参阅公告博客文章 https://projectzero.google/2026/09/maccconc-race-condition.html。
目前有三个工具:
这不是 Google 官方支持的产品。本项目不符合 Google 开源软件漏洞奖励计划 的资格。
首先,获取一个包含提交 dc5c6d008f48 的 LLVM 版本;这意味着要么从 HEAD 构建,而不是从发布分支构建,要么使用版本 >=23 的构建。例如,此类构建可从 https://apt.llvm.org/ 获取。 如果你是 Google 员工,请参阅 http://go/maccconc-kernel-build-notes 。
从 https://github.com/thejh/linux 获取包含所需补丁的内核树,分支为 kcov-tracing-full。
在配置和构建内核时,按照 https://docs.kernel.org/kbuild/llvm.html 中的说明设置 make 变量
CC / LLVM / LLVM_PREFIX,以确保使用正确的 LLVM 工具链。
设置此环境变量以获取有关已执行基本块的更清晰信息(供 GUI 使用),并避免因尾调用优化而导致令人困惑的调用栈:
export KCFLAGS="-fno-optimize-sibling-calls -mllvm -sanitizer-coverage-prune-blocks=false"
像往常一样配置内核;如果你不是从现有配置开始,从
make [...] kvm_guest.config 开始可能会有用。
确保设置以下内核配置标志(例如通过 ncurses 配置界面 make [...] nconfig 或将它们粘贴到 .config 底部):
# for core functionality
CONFIG_SMP=y
CONFIG_NR_CPUS=4
CONFIG_KASAN=y
CONFIG_KASAN_OUTLINE=y
CONFIG_KCOV=y
CONFIG_KCOV_EXT_RECORDS=y
CONFIG_KCOV_MEMORY=y
CONFIG_KALLSYMS_ALL=y
# to give the GUI information about source lines and inlining
CONFIG_DEBUG_INFO_DWARF5=y
# for communicating with the GUI
CONFIG_VSOCKETS=y
CONFIG_VIRTIO_VSOCKETS=y
CONFIG_VIRTIO_PCI=y
# for maximizing the potential for race conditions
CONFIG_PREEMPT=y
# for making virtual addresses at runtime the same as in vmlinux
CONFIG_RANDOMIZE_BASE=n
# needed for several samples
CONFIG_TMPFS=y
如果你想要测试涉及 RCU 的竞态条件,也可以启用以下配置,但请注意这会导致大幅减速,并且目前仅在你使用 GUI 时才能正常工作。
CONFIG_RCU_EXPERT=y
CONFIG_RCU_STRICT_GRACE_PERIOD=y
请确保你想要测试的任何内核功能都编译进内核,而不是作为模块。
建议在主机上构建用户空间工具;尤其是 GUI,它设计为在主机上运行,而不是在客户机中。
安装 git 和构建依赖;对于 Debian:
sudo apt install git build-essential pkg-config libcapstone-dev libdw-dev libglfw3-dev
克隆此仓库后,使用以下命令下载子模块:
git submodule update --init --recursive
使用 make 构建。
如果你启用了所需的内核配置标志并使用带有 Linux 发行版的磁盘镜像或类似内容,你可以在普通的 QEMU 虚拟机中启动构建好的内核;但推荐的方法是改为像这样安装 kvmtool:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/will/kvmtool.git
cd kvmtool
make
make install
然后你可以按如下方式启动构建好的内核(假设 $HOME/bin 在你的 $PATH 中):
lkvm run --kernel [path to kernel tree]/arch/x86/boot/bzImage --vsock 5 --console virtio
这将为你提供一个 shell 环境,其中主机文件系统的只读视图挂载在 /host,一个最小化的 rootfs 主要由指向该主机文件系统的符号链接组成,用于 /bin、/lib、/usr 等。 / 和 /host 都是 9p 文件系统。
请在每次启动后手动在客户机中挂载 debugfs 和 tmpfs:
sh-5.3# mount -t debugfs none /sys/kernel/debug
sh-5.3# mount -t tmpfs none /tmp
sh-5.3#
测试用例是定义四个函数的 C 代码:
void test_setup(void) { [...] }
void test_thread1(void) { [...] }
void test_thread2(void) { [...] }
void test_end(void) { [...] }
对于测试用例的每次执行,test_setup() 将首先运行;然后 test_thread1() 和 test_thread2() 将并行运行;最后,test_end() 将运行。
测试用例应构建为共享库,如下所示:
$ cc -shared -o [name].so [name].c -fPIC
testcase/ 文件夹中的示例测试用例也可以通过 make 构建,例如:
$ make testcase/demo-dup-vs-close.so
cc -shared -o testcase/demo-dup-vs-close.so testcase/demo-dup-vs-close.c -Wall
kcov-autorace 工具可以自动探索 A-B-A 执行顺序。A-B-A 顺序是指线程 A 运行到某一点,然后线程 B 完全执行,然后线程 A 完成执行。
在主机上构建测试用例后,你可以使用 kcov-autorace 辅助工具在客户机中运行它。例如:
sh-5.3# cd /host/{path to checkout on the host}
sh-5.3# ./kcov-autorace testcase/demo-dup-vs-close.so
loading kallsyms
RCU state (excluded): base=ffffffff82770100 len=500
loading testcase
initializing kcov
collecting A-B coverage
dup(5) = 6 (success)
testing candidates
dup(5) = -1 (Bad file descriptor)
dup(5) = -1 (Bad file descriptor)
dup(5) = -1 (Bad file descriptor)
dup(5) = 5 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
dup(5) = 6 (success)
stats: injection-failed:0 wait-timeout:7 reordered:4
sh-5.3#
这表明存在 close(5) 和 dup(5) 的 A-B-A 顺序,导致 dup(5) 返回 5。
请注意,kcov-autorace 和其他工具使用硬编码的自旋等待超时 SPIN_LIMIT。
kcov-terminal 工具可用于运行带有手动指定顺序约束的测试用例。这些约束并不指定完整顺序;相反,它们是一组“A 应在 B 之前发生”的规则。
此工具在客户机中使用,类似于 kcov-autorace。
使用测试用例 demo-inode-attr-change 的示例用法,运行带有顺序约束,以证明 fstat() 读取 UID 和 GID 相对于 fchown() 不是原子的:
sh-5.3# ./kcov-terminal testcase/demo-inode-attr-change.so
uid=0 gid=0
===== filtered to interference set, no RCU core =====
LEGEND:
type: R=read W=write M=modify(read+write) F=free A=atomic