
Toolkit zur Erkundung von Race Conditions im Linux-Kernel mithilfe von KCOV-Traces: GUI- und Terminal-Viewer für nebenläufige Ausführung und Speicherzugriffe, plus automatisches A-B-A-Reihenfolgentesten.
Dies ist ein Toolset zur Untersuchung von Race Conditions im Linux-Kernel sowie für allgemeines Kernel-Debugging.
Siehe auch den Ankündigungs-Blogbeitrag https://projectzero.google/2026/09/maccconc-race-condition.html.
Derzeit gibt es drei Tools:
Dies ist kein offiziell unterstütztes Google-Produkt. Dieses Projekt ist nicht für das Google Open Source Software Vulnerability Rewards Program berechtigt.
Beschaffen Sie zunächst eine Version von LLVM, die Commit dc5c6d008f48 enthält; das bedeutet entweder einen Build von HEAD statt von einem Release-Branch oder einen Build ab Version >=23. Solche Builds sind beispielsweise unter https://apt.llvm.org/ verfügbar. Wenn Sie ein Googler sind, siehe http://go/maccconc-kernel-build-notes .
Beschaffen Sie einen Kernel-Baum mit den erforderlichen Patches von https://github.com/thejh/linux , Branch kcov-tracing-full.
Setzen Sie beim Konfigurieren und Bauen des Kernels die Make-Variablen CC / LLVM / LLVM_PREFIX wie unter https://docs.kernel.org/kbuild/llvm.html dokumentiert, um sicherzustellen, dass die richtige LLVM-Toolchain verwendet wird.
Setzen Sie diese Umgebungsvariable, um klarere Informationen über ausgeführte Basisblöcke (für die GUI) zu erhalten und verwirrende Call Stacks aufgrund von Tail-Call-Optimierung zu vermeiden:
export KCFLAGS="-fno-optimize-sibling-calls -mllvm -sanitizer-coverage-prune-blocks=false"
Konfigurieren Sie den Kernel wie üblich; es kann nützlich sein, mit make [...] kvm_guest.config zu beginnen, wenn Sie nicht von einer vorhandenen Konfiguration ausgehen. Stellen Sie sicher, dass die folgenden Kernel-Konfigurationsflags gesetzt sind (zum Beispiel über die ncurses-Konfigurationsoberfläche make [...] nconfig oder indem Sie sie am Ende von .config einfügen):
# 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
Sie können auch Folgendes aktivieren, wenn Sie Race Conditions mit RCU testen möchten, aber beachten Sie, dass dies zu einer starken Verlangsamung führt und derzeit nur ordnungsgemäß funktioniert, wenn Sie die GUI verwenden.
CONFIG_RCU_EXPERT=y
CONFIG_RCU_STRICT_GRACE_PERIOD=y
Bitte stellen Sie sicher, dass alle Kernel-Features, die Sie testen möchten, in den Kernel einkompiliert und nicht als Module gebaut werden.
Es wird empfohlen, das Userspace-Tooling auf dem Host-Rechner zu bauen; insbesondere die GUI, die dafür ausgelegt ist, auf dem Host und nicht im Gast zu laufen.
Installieren Sie git und Build-Abhängigkeiten; für Debian:
sudo apt install git build-essential pkg-config libcapstone-dev libdw-dev libglfw3-dev
Laden Sie nach dem Klonen dieses Repositorys die Submodule herunter mit:
git submodule update --init --recursive
Bauen Sie mit make.
Sie können den gebauten Kernel in einer normalen QEMU-VM booten, wenn Sie die erforderlichen Kernel-Konfigurationsflags aktivieren und ein Disk-Image mit einer Linux-Distribution oder Ähnliches verwenden; der empfohlene Ansatz ist jedoch, stattdessen kvmtool wie folgt zu installieren:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/will/kvmtool.git
cd kvmtool
make
make install
Dann können Sie den gebauten Kernel wie folgt booten (angenommen, $HOME/bin ist in Ihrer $PATH):
lkvm run --kernel [path to kernel tree]/arch/x86/boot/bzImage --vsock 5 --console virtio
Dies gibt Ihnen eine Shell in einer Umgebung, in der eine schreibgeschützte Ansicht des Host-Dateisystems unter /host eingehängt ist, mit einem minimalen Rootfs, das größtenteils aus Symlinks in dieses Host-Dateisystem für /bin, /lib, /usr und so weiter besteht. Sowohl / als auch /host sind 9p-Dateisysteme.
Bitte hängen Sie debugfs und tmpfs im Gast nach jedem Boot manuell ein:
sh-5.3# mount -t debugfs none /sys/kernel/debug
sh-5.3# mount -t tmpfs none /tmp
sh-5.3#
Testfälle sind C-Code, der vier Funktionen definiert:
void test_setup(void) { [...] }
void test_thread1(void) { [...] }
void test_thread2(void) { [...] }
void test_end(void) { [...] }
Bei jeder Ausführung des Testfalls wird zuerst test_setup() ausgeführt; dann laufen test_thread1() und test_thread2() parallel; und schließlich wird test_end() ausgeführt.
Testfälle sollten als Shared Libraries gebaut werden, etwa so:
$ cc -shared -o [name].so [name].c -fPIC
Die Beispiel-Testfälle im Ordner testcase/ können auch über make gebaut werden, etwa so:
$ make testcase/demo-dup-vs-close.so
cc -shared -o testcase/demo-dup-vs-close.so testcase/demo-dup-vs-close.c -Wall
Das Tool kcov-autorace kann automatisch A-B-A-Ausführungsreihenfolgen untersuchen. A-B-A-Reihenfolgen sind solche, bei denen Thread A bis zu einem Punkt läuft, dann Thread B vollständig ausgeführt wird und dann Thread A die Ausführung beendet.
Nachdem Sie einen Testfall auf dem Host gebaut haben, können Sie ihn im Gast mit dem Helfer kcov-autorace ausführen. Zum Beispiel:
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#
Dies zeigt, dass es eine A-B-A-Reihenfolge von close(5) und dup(5) gibt, die dazu führt, dass dup(5) den Wert 5 zurückgibt.
Beachten Sie, dass kcov-autorace und die anderen Tools ein fest einprogrammiertes Spin-Wait-Timeout SPIN_LIMIT verwenden.
Das Tool kcov-terminal kann verwendet werden, um einen Testfall mit manuell angegebenen Reihenfolgebeschränkungen auszuführen. Diese legen keine vollständige Reihenfolge fest; stattdessen sind sie eine Menge von Regeln der Form „A sollte vor B passieren“.
Dieses Tool wird im Gast verwendet, ähnlich wie kcov-autorace.
Beispielverwendung mit dem Testfall demo-inode-attr-change, um mit Reihenfolgebeschränkungen auszuführen, die zeigen, dass das Lesen von UID und GID durch fstat() nicht atomar bezüglich fchown() ist:
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