Introduces a new KCOV exetened feature that captures function arguments and
return values at kernel function boundaries, enabling per-process visibility
into runtime dataflow.
Motivation
==========
Even for highly experienced developers, it is not straightforward to
determine, at any given moment, which specific kernel paths a user
process is executing or how function arguments and return values evolve
during execution. This lack of visibility makes debugging and security
auditing significantly more challenging.
Limitations of existing tools in per-task dataflow extraction:
- ftrace/kprobes provide dynamic tracing at specific probe points
- eBPF enables programmable in-kernel analysis but requires manual
specification of struct layouts rather than automatic extraction
from compiler debug metadata
- perf provides statistical sampling of hardware/software events,
inherently lossy and designed for performance profiling rather
than deterministic data-flow capture
This is NOT a performance tool. The purpose is auditing and contract
verification — confirming that kernel functions receive and return
expected values at runtime.
Real-World Result: Android Binder Vulnerabilities
=================================================
Using kcov-dataflow with CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL, I
audited the Android binder driver (both C and Rust implementations)
and discovered two exploitable logic bugs:
Bug 1: BINDER_SET_MAX_THREADS accepts 0xFFFFFFFF without validation.
kcov-dataflow showed: set_max_threads(max=0xffffffff) → return 0
Impact: bypasses RLIMIT_NPROC, OOM from unprivileged userspace.
Bug 2: BC_ENTER_LOOPER accepted twice without error.
kcov-dataflow showed: looper_enter() called with ENTERED already set,
no rejection, return=0 on both calls.
Impact: thread pool state corruption.
These bugs are invisible to:
- KASAN: no memory corruption occurs
- Edge coverage: same code paths for valid/invalid values
- ftrace: shows "function called" but not argument values
Only by capturing the actual runtime values at function boundaries
could I detect that 0xFFFFFFFF passes through without rejection, or
that the same state-mutating command succeeds twice.
The fixes are submitted separately:
[PATCH 1/4] binder: cap BINDER_SET_MAX_THREADS at RLIMIT_NPROC
[PATCH 2/4] binder: reject duplicate BC_ENTER_LOOPER commands
[PATCH 3/4] rust_binder: cap set_max_threads at RLIMIT_NPROC
[PATCH 4/4] rust_binder: reject duplicate BC_ENTER_LOOPER in looper_enter
Approach
========
Rather than tracing individual probe points, this patch set enables
continuous per-task extraction of data flow across all instrumented
function boundaries — capturing how argument values enter and return
values exit each function as execution progresses through a subsystem.
The key insight is that function boundaries are natural observation
points: arguments at entry reveal what data enters a subsystem, and
return values reveal what comes out.
The compiler (clang with a SanitizerCoverage extension) inserts
callbacks at function entry/exit that record argument values into a
per-task mmap'd buffer. The kernel backend reads struct fields safely
via copy_from_kernel_nofault(). When not enabled for a task, the
overhead is a single boolean check per instrumented function.
Design
======
- Completely independent from legacy /sys/kernel/debug/kcov
- Separate device: /sys/kernel/debug/kcov_dataflow
- Separate ioctl namespace ('d'), separate per-task buffer
- Per-module opt-in: KCOV_DATAFLOW_file.o := y
- Optional global enablement: CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL
- Supports both C and Rust kernel modules
- Safe in process context; rejects interrupt/NMI via in_task() guard
- Recursion guard via sequence counter bit 31
- Requires clang with -fsanitize-coverage=dataflow-args,dataflow-ret
(Kconfig uses cc-option to verify compiler support)
Performance Note
================
This feature is designed for auditing and security analysis, NOT for
production use or performance measurement. It should not be compared
to runtime tracing tools optimized for low overhead.
Per-module instrumentation (recording active):
~27ns per callback (dominated by LOCK XADD + copy_from_kernel_nofault)
Global instrumentation (INSTRUMENT_ALL, recording disabled):
.text: +9.5%, .data: +44%, boot: +71%, syscall latency: +133%
CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL instruments every function in the
kernel. This incurs significant overhead comparable to KMSAN and is
intended exclusively for:
- Fuzzer-driven whole-kernel auditing (syzkaller integration)
- Full-subsystem contract verification (as demonstrated with binder)
- Capturing complete call-flow data for post-mortem analysis
For targeted auditing, use per-module opt-in (KCOV_DATAFLOW_file.o := y)
which limits overhead to the specific subsystem under investigation.
Patches
=======
1/6: Core kernel implementation (kernel/kcov.c, sched.h, Kconfig)
2/6: Build system support (Makefile.kcov, Makefile.lib)
3/6: CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL and NO_INLINE
4/6: Userspace tools and test modules
5/6: Harden kcov_df_write() against interrupt reentry
6/6: Recursion guard and documentation
Prerequisites / Toolchain
=========================
This kernel patch relies on a custom LLVM SanitizerCoverage pass that
emits __sanitizer_cov_trace_args() and __sanitizer_cov_trace_ret()
callbacks at function boundaries, extracting struct field layouts from
DWARF debug metadata at compile time.
To build and test this patchset, compile the kernel using the modified
toolchain:
1. LLVM/Clang (adds -fsanitize-coverage=dataflow-args,dataflow-ret):
https://github.com/llvm/llvm-project/pull/201410
2. Rust (rustc 1.98 built against the above LLVM 23, for Rust module support):
https://github.com/yskzalloc/rust
Build instructions:
# Build the modified clang
cd llvm-project && cmake -G Ninja -S llvm -B build \
-DLLVM_ENABLE_PROJECTS="clang;lld" -DCMAKE_BUILD_TYPE=Release
ninja -C build clang
# Build the kernel with dataflow support
export PATH=$HOME/llvm-project/build/bin:$PATH
export RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc
export RUST_LIB_SRC=$HOME/rust/library
make LLVM=1 defconfig
scripts/config --enable KCOV \
--enable KCOV_DATAFLOW_ARGS \
--enable KCOV_DATAFLOW_RET
make LLVM=1 olddefconfig
make LLVM=1 -j$(nproc)
Note: CONFIG_KCOV_DATAFLOW_ARGS and CONFIG_KCOV_DATAFLOW_RET depend on
CONFIG_KCOV and use $(cc-option) to verify the compiler supports the
new flags. With standard (unpatched) clang, these options will not
appear in menuconfig and silently remain disabled.
Optional configs:
--enable KCOV_DATAFLOW_INSTRUMENT_ALL (instrument entire kernel)
--enable KCOV_DATAFLOW_NO_INLINE (enabled by default)
--set-val FRAME_WARN 4096 (needed for INSTRUMENT_ALL)
--disable KASAN (conflicts with INSTRUMENT_ALL)
Testing
=======
Tested on linux-next 7.1.0-rc5 with custom clang/LLVM 23 and
rustc 1.98-nightly (built against the same LLVM). Verified under
virtme-ng (QEMU/KVM, 1GB RAM):
- Per-module C (eight_args_mod): all 8 functions captured
- Per-module C (deep_chain_mod): 10-deep call chain captured
- Per-module Rust (eight_args_rust): all 8 rfunc functions captured
- Interrupt safety: in_task() + recursion guard prevents corruption
- Binder auditing: discovered 2 exploitable bugs (patches separate)
- Standard clang (without patch): Kconfig options correctly hidden
- Global enablement (INSTRUMENT_ALL): kernel boots, 104K records
captured during single copy.fail exploit reproduction
https://github.com/yskzalloc/kcov-dataflow/blob/main/copy.fail/origin/converted.txt
Signed-off-by: Yunseong Kim <[email protected]>
---
Changes in v2:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- Link to v1:
https://patch.msgid.link/[email protected]
To: Ingo Molnar <[email protected]>
To: Peter Zijlstra <[email protected]>
To: Juri Lelli <[email protected]>
To: Vincent Guittot <[email protected]>
To: Dietmar Eggemann <[email protected]>
To: Steven Rostedt <[email protected]>
To: Ben Segall <[email protected]>
To: Mel Gorman <[email protected]>
To: Valentin Schneider <[email protected]>
To: K Prateek Nayak <[email protected]>
To: Dmitry Vyukov <[email protected]>
To: Andrey Konovalov <[email protected]>
To: Andrew Morton <[email protected]>
To: Nathan Chancellor <[email protected]>
To: Nick Desaulniers <[email protected]>
To: Bill Wendling <[email protected]>
To: Justin Stitt <[email protected]>
To: Nicolas Schier <[email protected]>
To: Miguel Ojeda <[email protected]>
To: Boqun Feng <[email protected]>
To: Gary Guo <[email protected]>
To: Björn Roy Baron <[email protected]>
To: Benno Lossin <[email protected]>
To: Andreas Hindborg <[email protected]>
To: Alice Ryhl <[email protected]>
To: Trevor Gross <[email protected]>
To: Danilo Krummrich <[email protected]>
To: Jonathan Corbet <[email protected]>
To: Shuah Khan <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
Yunseong Kim (6):
kcov: add per-task dataflow tracking for function arguments/return values
kcov: add build system support for dataflow instrumentation
kcov: add CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL and NO_INLINE
tools/kcov-dataflow: add userspace consumer and test modules
kcov: add interrupt context guard to kcov_df_write()
kcov: add recursion guard and documentation for kcov-dataflow
Documentation/dev-tools/kcov-dataflow.rst | 282 +++++++++++++++++++
include/linux/sched.h | 8 +
kernel/Makefile | 3 +
kernel/kcov.c | 307 +++++++++++++++++++++
lib/Kconfig.debug | 43 +++
rust/Makefile | 1 +
scripts/Makefile.kcov | 6 +
scripts/Makefile.lib | 7 +
tools/kcov-dataflow/.gitignore | 12 +
tools/kcov-dataflow/deep_module/Makefile | 2 +
tools/kcov-dataflow/deep_module/deep_chain_mod.c | 224 +++++++++++++++
tools/kcov-dataflow/eight_args_c/Makefile | 3 +
tools/kcov-dataflow/eight_args_c/eight_args_mod.c | 95 +++++++
tools/kcov-dataflow/eight_args_rust/Makefile | 2 +
.../eight_args_rust/eight_args_rust.rs | 114 ++++++++
tools/kcov-dataflow/kcov-view.py | 272 ++++++++++++++++++
tools/kcov-dataflow/trigger.c | 125 +++++++++
17 files changed, 1506 insertions(+)
---
base-commit: f7af91adc230aa99e23330ecf85bc9badd9780ad
change-id: 20260603-kcov-dataflow-next-20260603-8bf628f98086
Best regards,
--
Yunseong Kim <[email protected]>