
Kit para explorar condições de corrida no kernel Linux usando traces KCOV: visualizadores GUI e de terminal para execução concorrente e acesso à memória, além de testes automáticos de ordenação A-B-A.
Este é um conjunto de ferramentas para explorar condições de corrida no kernel do Linux e para depuração geral do kernel.
Veja também o post de anúncio no blog https://projectzero.google/2026/09/maccconc-race-condition.html.
Atualmente existem três ferramentas:
Este não é um produto oficialmente suportado pelo Google. Este projeto não é elegível para o Google Open Source Software Vulnerability Rewards Program.
Primeiro, obtenha uma versão do LLVM que inclua o commit dc5c6d008f48; ou seja, uma compilação a partir do HEAD, em vez de um branch de release, ou uma compilação na versão >=23. Tais compilações estão, por exemplo, disponíveis em https://apt.llvm.org/ . Se você for um googler, consulte http://go/maccconc-kernel-build-notes .
Obtenha uma árvore do kernel com os patches necessários em https://github.com/thejh/linux , branch kcov-tracing-full.
Ao configurar e compilar o kernel, defina as variáveis make
CC / LLVM / LLVM_PREFIX conforme documentado em
https://docs.kernel.org/kbuild/llvm.html para garantir que a toolchain LLVM correta seja usada.
Defina esta variável de ambiente para obter informações mais claras sobre os blocos básicos executados (para a GUI) e evitar call stacks confusas devido à otimização de tail call:
export KCFLAGS="-fno-optimize-sibling-calls -mllvm -sanitizer-coverage-prune-blocks=false"
Configure o kernel como de costume; pode ser útil começar a partir de
make [...] kvm_guest.config se você não estiver partindo de uma configuração existente.
Certifique-se de que os seguintes flags de configuração do kernel estejam definidos (por exemplo, através da interface de configuração ncurses make [...] nconfig ou colando-os no final do .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
Você também pode habilitar o seguinte se quiser testar condições de corrida envolvendo RCU, mas observe que isso causará uma grande desaceleração e atualmente só funciona adequadamente se você usar a GUI.
CONFIG_RCU_EXPERT=y
CONFIG_RCU_STRICT_GRACE_PERIOD=y
Certifique-se de que quaisquer recursos do kernel que você deseja testar sejam compilados no kernel, não como módulos.
Recomenda-se compilar as ferramentas de espaço de usuário na máquina host; especialmente a GUI, que foi projetada para ser executada no host, não no guest.
Instale o git e as dependências de compilação; para Debian:
sudo apt install git build-essential pkg-config libcapstone-dev libdw-dev libglfw3-dev
Após clonar este repositório, baixe os submódulos com:
git submodule update --init --recursive
Compile com make.
Você pode inicializar o kernel compilado em uma VM QEMU normal se habilitar os flags de configuração do kernel necessários e usar uma imagem de disco com uma distribuição Linux, ou algo do tipo; mas a abordagem recomendada é instalar o kvmtool assim:
git clone https://git.kernel.org/pub/scm/linux/kernel/git/will/kvmtool.git
cd kvmtool
make
make install
Então você pode inicializar o kernel compilado da seguinte forma (assumindo que $HOME/bin está no seu $PATH):
lkvm run --kernel [path to kernel tree]/arch/x86/boot/bzImage --vsock 5 --console virtio
Isso lhe dará um shell em um ambiente onde uma visão somente leitura do sistema de arquivos do host é montada em /host, com um rootfs mínimo que consiste principalmente em symlinks para este sistema de arquivos do host para /bin, /lib, /usr e assim por diante. Tanto / quanto /host são sistemas de arquivos 9p.
Por favor, monte manualmente debugfs e tmpfs no guest após cada inicialização:
sh-5.3# mount -t debugfs none /sys/kernel/debug
sh-5.3# mount -t tmpfs none /tmp
sh-5.3#
Casos de teste são código C que define quatro funções:
void test_setup(void) { [...] }
void test_thread1(void) { [...] }
void test_thread2(void) { [...] }
void test_end(void) { [...] }
Para cada execução do caso de teste, test_setup() será executado primeiro; então test_thread1() e test_thread2() serão executados em paralelo; e finalmente, test_end() será executado.
Os casos de teste devem ser compilados como bibliotecas compartilhadas, assim:
$ cc -shared -o [name].so [name].c -fPIC
Os casos de teste de exemplo na pasta testcase/ também podem ser compilados via make, assim:
$ make testcase/demo-dup-vs-close.so
cc -shared -o testcase/demo-dup-vs-close.so testcase/demo-dup-vs-close.c -Wall
A ferramenta kcov-autorace pode explorar automaticamente ordenações de execução A-B-A. Ordenações A-B-A são aquelas em que a thread A executa até um ponto, então a thread B executa completamente, e então a thread A termina a execução.
Após compilar um caso de teste no host, você pode executá-lo no guest usando o
helper kcov-autorace. Por exemplo:
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#
Isso mostra que existe uma ordenação A-B-A de close(5) e dup(5) que resulta em dup(5) retornando 5.
Observe que kcov-autorace e as outras ferramentas usam um timeout de espera ocupada hardcoded
SPIN_LIMIT.
A ferramenta kcov-terminal pode ser usada para executar um caso de teste com restrições de ordenação especificadas manualmente. Estas não especificam uma ordenação completa; em vez disso,
são um conjunto de regras "A deve acontecer antes de B".
Esta ferramenta é usada no guest, de forma semelhante ao kcov-autorace.
Exemplo de uso com o caso de teste demo-inode-attr-change para executar com restrições
de ordenação que demonstram que a leitura de UID e GID por fstat() não é
atômica em relação a 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