Набор инструментов для исследования состояний гонки в ядре Linux с использованием трассировок KCOV: графический и терминальный просмотрщики параллельного выполнения и доступа к памяти, а также автоматическое тестирование упорядочивания A-B-A.
Это инструментарий для исследования состояний гонки в ядре Linux и для общей отладки ядра.
См. также анонсирующий пост в блоге https://projectzero.google/2026/09/maccconc-race-condition.html.
В настоящее время существует три инструмента:
Это не официально поддерживаемый продукт Google. Этот проект не имеет права на участие в Google Open Source Software Vulnerability Rewards Program.
Сначала получите версию LLVM, включающую коммит dc5c6d008f48; то есть либо сборку из HEAD, а не из ветки релиза, либо сборку версии >=23. Такие сборки, например, доступны на https://apt.llvm.org/ . Если вы сотрудник Google, см. http://go/maccconc-kernel-build-notes .
Получите дерево ядра с необходимыми патчами из https://github.com/thejh/linux , ветка kcov-tracing-full.
При конфигурировании и сборке ядра задайте переменные make
CC / LLVM / LLVM_PREFIX, как описано на
https://docs.kernel.org/kbuild/llvm.html, чтобы гарантировать использование
правильного инструментария 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.
Вы можете загрузить собранное ядро в обычной виртуальной машине QEMU, если включите необходимые флаги конфигурации ядра и используете образ диска с дистрибутивом Linux или что-то подобное; но рекомендуемый подход — вместо этого установить 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
Это даст вам оболочку в среде, где доступное только для чтения представление файловой системы хоста смонтировано в /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#
Это показывает, что существует A-B-A порядок для close(5) и dup(5), который приводит к тому, что dup(5) возвращает 5.
Обратите внимание, что kcov-autorace и другие инструменты используют жёстко заданный тайм-аут ожидания вращения
SPIN_LIMIT.
Инструмент kcov-terminal можно использовать для запуска тест-кейса с вручную заданными
ограничениями порядка. Они не задают полный порядок; вместо этого они
представляют собой набор правил «A должно произойти до B».
Этот инструмент используется в госте аналогично kcov-autorace.
Пример использования с тест-кейсом demo-inode-attr-change для запуска с ограничениями
порядка, которые демонстрируют, что чтение UID и GID функцией fstat() не
атомарно относительно 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