* Re: [RFC PATCH v2 2/6] kcov: add build system support for dataflow instrumentation
From: Peter Zijlstra @ 2026-06-04 8:45 UTC (permalink / raw)
To: Yunseong Kim
Cc: Ingo Molnar, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Dmitry Vyukov, Andrey Konovalov, Andrew Morton,
Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Nicolas Schier, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
linux-kernel, kasan-dev, llvm, linux-kbuild, rust-for-linux,
workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-2-fee0939de2c4@est.tech>
On Wed, Jun 03, 2026 at 07:43:29PM +0200, Yunseong Kim wrote:
> Add CFLAGS_KCOV_DATAFLOW and RUSTFLAGS_KCOV_DATAFLOW exports to
> scripts/Makefile.kcov, containing:
> -fsanitize-coverage=dataflow-args,dataflow-ret -g
> (with optional -fno-inline via CONFIG_KCOV_DATAFLOW_NO_INLINE)
>
> scripts/Makefile.lib applies these flags when a module's Makefile sets:
> KCOV_DATAFLOW_file.o := y (per-file)
> KCOV_DATAFLOW := y (per-directory)
>
> Also supports CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL for global enablement.
> The flags are only applied to kernel objects (same guard as basic KCOV).
>
> Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
> ---
> scripts/Makefile.kcov | 6 ++++++
> scripts/Makefile.lib | 7 +++++++
> 2 files changed, 13 insertions(+)
>
> diff --git a/scripts/Makefile.kcov b/scripts/Makefile.kcov
> index 78305a84ba9d..101173fe194b 100644
> --- a/scripts/Makefile.kcov
> +++ b/scripts/Makefile.kcov
> @@ -2,10 +2,16 @@
> kcov-flags-y += -fsanitize-coverage=trace-pc
> kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -fsanitize-coverage=trace-cmp
>
> +# KCOV dataflow: trace function args and return values
> +kcov-dataflow-flags-y := -fsanitize-coverage=dataflow-args,dataflow-ret -g
> +kcov-dataflow-flags-$(CONFIG_KCOV_DATAFLOW_NO_INLINE) += -fno-inline
https://clang.llvm.org/docs/ClangCommandLineReference.html
Has no mention of -fno-inline, furthermore, what are the exact
semantics? Does it inhibit __always_inline?
^ permalink raw reply
* Re: [RFC PATCH v2 1/6] kcov: add per-task dataflow tracking for function arguments/return values
From: Peter Zijlstra @ 2026-06-04 8:41 UTC (permalink / raw)
To: Yunseong Kim
Cc: Ingo Molnar, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Dmitry Vyukov, Andrey Konovalov, Andrew Morton,
Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Nicolas Schier, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
linux-kernel, kasan-dev, llvm, linux-kbuild, rust-for-linux,
workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-1-fee0939de2c4@est.tech>
On Wed, Jun 03, 2026 at 07:43:28PM +0200, Yunseong Kim wrote:
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index e2f976c3301b..abd1a94589aa 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2261,6 +2261,28 @@ config KCOV_SELFTEST
> On test failure, causes the kernel to panic. Recommended to be
> enabled, ensuring critical functionality works as intended.
>
> +
^ This line...
> +config KCOV_DATAFLOW_ARGS
> + bool "Enable KCOV dataflow: function argument capture"
> + depends on KCOV
> + depends on $(cc-option,-fsanitize-coverage=dataflow-args)
> + help
> + Captures function arguments at entry via /sys/kernel/debug/kcov_dataflow.
> + Struct pointer arguments are auto-expanded using compiler DebugInfo
> + metadata, recording individual field values at runtime.
> + Enable per-module with: KCOV_DATAFLOW_file.o := y in the Makefile.
> + Requires clang with -fsanitize-coverage=dataflow-args support.
> +
> +config KCOV_DATAFLOW_RET
> + bool "Enable KCOV dataflow: return value capture"
> + depends on KCOV
> + depends on $(cc-option,-fsanitize-coverage=dataflow-ret)
> + help
> + Captures function return values via /sys/kernel/debug/kcov_dataflow.
> + Struct pointer returns are auto-expanded using compiler DebugInfo
> + metadata, recording individual field values at runtime.
> + Enable per-module with: KCOV_DATAFLOW_file.o := y in the Makefile.
> + Requires clang with -fsanitize-coverage=dataflow-ret support.
Probably wants to be here...
> config DEBUG_AID_FOR_SYZBOT
> bool "Additional debug code for syzbot"
> default n
>
> --
> 2.43.0
>
^ permalink raw reply
* Re: [RFC PATCH v2 0/6] kcov: per-task dataflow extraction at kernel function boundaries
From: Peter Zijlstra @ 2026-06-04 8:40 UTC (permalink / raw)
To: Yunseong Kim
Cc: Ingo Molnar, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
K Prateek Nayak, Dmitry Vyukov, Andrey Konovalov, Andrew Morton,
Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Nicolas Schier, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Jonathan Corbet, Shuah Khan,
linux-kernel, kasan-dev, llvm, linux-kbuild, rust-for-linux,
workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4@est.tech>
On Wed, Jun 03, 2026 at 07:43:27PM +0200, Yunseong Kim wrote:
> CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL instruments every function in the
> kernel.
Well, I would hope it would very much not instrument noinstr functions.
^ permalink raw reply
* Re: [PATCH net-next] docs: exclude driver and netdevsim bugs
From: kernel test robot @ 2026-06-04 6:03 UTC (permalink / raw)
To: Jakub Kicinski, davem
Cc: oe-kbuild-all, netdev, edumazet, pabeni, andrew+netdev, horms,
johannes, Jakub Kicinski, corbet, skhan, workflows, linux-doc
In-Reply-To: <20260603162943.2406080-1-kuba@kernel.org>
Hi Jakub,
kernel test robot noticed the following build warnings:
[auto build test WARNING on net-next/main]
url: https://github.com/intel-lab-lkp/linux/commits/Jakub-Kicinski/docs-exclude-driver-and-netdevsim-bugs/20260604-003949
base: net-next/main
patch link: https://lore.kernel.org/r/20260603162943.2406080-1-kuba%40kernel.org
patch subject: [PATCH net-next] docs: exclude driver and netdevsim bugs
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project f43d6834093b19baf79beda8c0337ab020ac5f17)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260604/202606040736.mHgLfIxh-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606040736.mHgLfIxh-lkp@intel.com/
All warnings (new ones prefixed by >>):
Checksumming on output with GSO
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [docutils]
Documentation/process/maintainer-netdev.rst:295: ERROR: Unexpected indentation. [docutils]
>> Documentation/process/maintainer-netdev.rst:299: WARNING: Block quote ends without a blank line; unexpected unindent. [docutils]
MAINTAINERS:40: WARNING: Inline strong start-string without end-string. [docutils]
Documentation/userspace-api/landlock:504: ./security/landlock/errata/abi-4.h:5: ERROR: Unexpected section title.
vim +299 Documentation/process/maintainer-netdev.rst
292
293 Additionally, netdev does not consider bugs to be ``net``-worthy
294 if they fulfill **all** of the following criteria:
295 - bug is in a hardware device driver;
296 - bug is either a missing error handling or is part of the error handling flow;
297 - bug was discovered by a static analysis / AI tool;
298 - bug was triggered/observed only with kernel changes or fault injection.
> 299 Fixes for such bugs should default to ``net-next`` and should **not** contain
300 a Fixes tag. Networking or driver maintainers may redirect such fixes to ``net``
301 at their discretion if they consider the condition to be relevant enough.
302
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH net-next] docs: exclude driver and netdevsim bugs
From: Jacob Keller @ 2026-06-03 22:54 UTC (permalink / raw)
To: Johannes Berg, Jakub Kicinski, davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, corbet, skhan,
workflows, linux-doc
In-Reply-To: <c78c1ff315ec96795461f100064bc42c524a67e3.camel@sipsolutions.net>
On 6/3/2026 1:12 PM, Johannes Berg wrote:
> On Wed, 2026-06-03 at 09:29 -0700, Jakub Kicinski wrote:
>>
>> +Additionally, netdev does not consider bugs to be ``net``-worthy
>> +if they fulfill **all** of the following criteria:
>> + - bug is in a hardware device driver;
>> + - bug is either a missing error handling or is part of the error handling flow;
>
> Do you really want to be this specific?
>
I agree, this does feel a little overly specific. Perhaps there is
better wording to clarify the intent such that it could cover your
example as well? Hmm.
> Take this fix for example that I mentioned the other day:
> https://patchwork.kernel.org/project/linux-wireless/patch/20260531145435.701703-1-runyu.xiao@seu.edu.cn/
>
> It doesn't formally fall under that definition, but I think it should,
> it's a silly thing to send to stable etc.
>
> This isn't even a USB device where you could reasonably argue that
> someone might plug in a random one and it could be programmed to look
> like the device in question and misbehave. Sure, you can build PCIe
> hardware too that can do that, technically, and there's technically
> external PCIe via Thunderbolt, but it's still far harder to actually do
> anything with.
>
>> + - bug was discovered by a static analysis / AI tool;
>
> I'm not (yet?) convinced that this bullet point is right.
>
> It risks getting into an argument about how much the LLM did to discover
> it, or if the actual discovery was a manual process after the LLM
> pointed out issues, or whatever ...
>
> Maybe more importantly, why should that even change the result?
>
> It's true that today the reason to start spelling this out more clearly
> is AI related, but that's really because of (a) the scale, and (b) many
> of the people running the LLMs not being aware of (and frankly often not
> really caring about) the community norms. I'm not convinced that the
> "silliness" of a change should be measured by how it originated.
>
Right. The point to me seems that "fixes" made purely to resolve tool
hits (static analysis, checkpatch, LLM, whatever) have lower value than
fixes which have a stronger motivation such as user reports.
I'm not sure I have a better wording, and perhaps you could remove this
bit entirely.
>> + - bug was triggered/observed only with kernel changes or fault injection.
>
> Given this fourth bullet point, we'd still accept fixes for such driver
> problems that people actually run into, while excluding "theoretical"
> things that are discovered by "reading the code".
>
Right. One could argue that some race conditions are difficult to
trigger because a window is very narrow, and fault injection could make
it much easier... But we could still accept such fixes as development
improvement rather than through the "net" tree, so I think this criteria
is good.
> johannes
>
^ permalink raw reply
* Re: [PATCH net-next] docs: exclude driver and netdevsim bugs
From: Jakub Kicinski @ 2026-06-03 20:13 UTC (permalink / raw)
To: Andrew Lunn
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, johannes,
corbet, skhan, workflows, linux-doc
In-Reply-To: <a0f191f4-3c09-4919-bc79-0b716d1ecc6f@lunn.ch>
On Wed, 3 Jun 2026 21:25:02 +0200 Andrew Lunn wrote:
> > +Additionally, netdev does not consider bugs to be ``net``-worthy
> > +if they fulfill **all** of the following criteria:
> > + - bug is in a hardware device driver;
> > + - bug is either a missing error handling or is part of the error handling flow;
> > + - bug was discovered by a static analysis / AI tool;
> > + - bug was triggered/observed only with kernel changes or fault injection.
> > +Fixes for such bugs should default to ``net-next`` and should **not** contain
> > +a Fixes tag. Networking or driver maintainers may redirect such fixes to ``net``
> > +at their discretion if they consider the condition to be relevant enough.
>
> I would also stress what the stable rules say:
>
> It must either fix a real bug that bothers people or ...
>
> Many of the bug fixes we are currently getting don't meet this
> criteria, so are net-next material.
I decided to leave that out in the end because it's a bit too open
to interpretation for my mind.
^ permalink raw reply
* Re: [PATCH net-next] docs: exclude driver and netdevsim bugs
From: Johannes Berg @ 2026-06-03 20:12 UTC (permalink / raw)
To: Jakub Kicinski, davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, corbet, skhan,
workflows, linux-doc
In-Reply-To: <20260603162943.2406080-1-kuba@kernel.org>
On Wed, 2026-06-03 at 09:29 -0700, Jakub Kicinski wrote:
>
> +Additionally, netdev does not consider bugs to be ``net``-worthy
> +if they fulfill **all** of the following criteria:
> + - bug is in a hardware device driver;
> + - bug is either a missing error handling or is part of the error handling flow;
Do you really want to be this specific?
Take this fix for example that I mentioned the other day:
https://patchwork.kernel.org/project/linux-wireless/patch/20260531145435.701703-1-runyu.xiao@seu.edu.cn/
It doesn't formally fall under that definition, but I think it should,
it's a silly thing to send to stable etc.
This isn't even a USB device where you could reasonably argue that
someone might plug in a random one and it could be programmed to look
like the device in question and misbehave. Sure, you can build PCIe
hardware too that can do that, technically, and there's technically
external PCIe via Thunderbolt, but it's still far harder to actually do
anything with.
> + - bug was discovered by a static analysis / AI tool;
I'm not (yet?) convinced that this bullet point is right.
It risks getting into an argument about how much the LLM did to discover
it, or if the actual discovery was a manual process after the LLM
pointed out issues, or whatever ...
Maybe more importantly, why should that even change the result?
It's true that today the reason to start spelling this out more clearly
is AI related, but that's really because of (a) the scale, and (b) many
of the people running the LLMs not being aware of (and frankly often not
really caring about) the community norms. I'm not convinced that the
"silliness" of a change should be measured by how it originated.
> + - bug was triggered/observed only with kernel changes or fault injection.
Given this fourth bullet point, we'd still accept fixes for such driver
problems that people actually run into, while excluding "theoretical"
things that are discovered by "reading the code".
johannes
^ permalink raw reply
* Re: [PATCH net-next] docs: exclude driver and netdevsim bugs
From: Andrew Lunn @ 2026-06-03 19:25 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, johannes,
corbet, skhan, workflows, linux-doc
In-Reply-To: <20260603162943.2406080-1-kuba@kernel.org>
> +Additionally, netdev does not consider bugs to be ``net``-worthy
> +if they fulfill **all** of the following criteria:
> + - bug is in a hardware device driver;
> + - bug is either a missing error handling or is part of the error handling flow;
> + - bug was discovered by a static analysis / AI tool;
> + - bug was triggered/observed only with kernel changes or fault injection.
> +Fixes for such bugs should default to ``net-next`` and should **not** contain
> +a Fixes tag. Networking or driver maintainers may redirect such fixes to ``net``
> +at their discretion if they consider the condition to be relevant enough.
I would also stress what the stable rules say:
It must either fix a real bug that bothers people or ...
Many of the bug fixes we are currently getting don't meet this
criteria, so are net-next material.
Andrew
^ permalink raw reply
* [RFC PATCH v2 6/6] kcov: add recursion guard and documentation for kcov-dataflow
From: Yunseong Kim @ 2026-06-03 17:43 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, Dmitry Vyukov,
Andrey Konovalov, Andrew Morton, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Nicolas Schier,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Jonathan Corbet, Shuah Khan
Cc: Yunseong Kim, linux-kernel, kasan-dev, llvm, linux-kbuild,
rust-for-linux, workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4@est.tech>
Add a per-task recursion guard to kcov_df_write() using the high bit of
kcov_dataflow_seq. This prevents infinite recursion when
CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL is enabled: functions called by the
callback itself (copy_from_kernel_nofault, xadd helpers) are also
instrumented and would re-enter kcov_df_write() without this guard.
The guard uses the sequence counter's bit 31 as a re-entrancy flag.
The low 24 bits (used for TLV record sequence numbers) are unaffected.
Also:
- Exclude kcov.o, extable.o, softirq.o from dataflow instrumentation
(same pattern as KCOV_INSTRUMENT exclusions)
- Add Documentation/dev-tools/kcov-dataflow.rst with:
- Prerequisites and Kconfig options
- Per-module instrumentation instructions
- Complete C example for data collection
- Ring buffer format specification
- Ioctl interface reference
- Fork interception example for child process tracing
- Rust module support via post-compilation pipeline
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
Documentation/dev-tools/kcov-dataflow.rst | 282 ++++++++++++++++++++++++++++++
kernel/Makefile | 3 +
kernel/kcov.c | 14 +-
3 files changed, 298 insertions(+), 1 deletion(-)
diff --git a/Documentation/dev-tools/kcov-dataflow.rst b/Documentation/dev-tools/kcov-dataflow.rst
new file mode 100644
index 000000000000..5941df9f29e6
--- /dev/null
+++ b/Documentation/dev-tools/kcov-dataflow.rst
@@ -0,0 +1,282 @@
+KCOV-Dataflow: function argument and return value extraction
+=============================================================
+
+KCOV-Dataflow captures function arguments and return values — including
+automatic struct field decomposition — at instrumented kernel function
+boundaries. It provides per-task, lock-free ring buffers accessible via
+``mmap()``, enabling data-flow-aware fuzzing and post-mortem contract
+verification.
+
+Unlike KCOV's ``trace-pc`` which reports *which* code executed,
+KCOV-Dataflow reports *what values* were passed and returned. This is
+a completely separate device from ``/sys/kernel/debug/kcov``.
+
+Prerequisites
+-------------
+
+KCOV-Dataflow requires Clang/LLVM with the ``dataflow-args`` and
+``dataflow-ret`` SanitizerCoverage extensions. Standard (unpatched)
+compilers will not expose these Kconfig options.
+
+To enable KCOV-Dataflow, configure the kernel with::
+
+ CONFIG_KCOV=y
+ CONFIG_KCOV_DATAFLOW_ARGS=y
+ CONFIG_KCOV_DATAFLOW_RET=y
+
+Optional: instrument the entire kernel (significant overhead)::
+
+ CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL=y
+
+Coverage data becomes accessible once debugfs is mounted::
+
+ mount -t debugfs none /sys/kernel/debug
+
+Per-module instrumentation
+--------------------------
+
+To instrument a specific module, add to its Makefile::
+
+ KCOV_DATAFLOW_my_module.o := y
+
+For example, to instrument the Android binder driver::
+
+ # drivers/android/Makefile
+ KCOV_DATAFLOW_binder.o := y
+ KCOV_DATAFLOW_binder_alloc.o := y
+
+For Rust modules, add to the crate's Makefile::
+
+ # drivers/android/binder/Makefile
+ KCOV_DATAFLOW := y
+
+To instrument an entire directory, set the variable without a filename::
+
+ # fs/Makefile
+ KCOV_DATAFLOW := y
+
+The build system automatically adds the required compiler flags
+(``-fsanitize-coverage=dataflow-args,dataflow-ret -g``).
+
+Data collection
+---------------
+
+The following program demonstrates how to collect function argument and
+return value data for a single syscall:
+
+.. code-block:: c
+
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <sys/types.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+
+ #define KCOV_DF_INIT_TRACE _IOR('d', 1, unsigned long)
+ #define KCOV_DF_ENABLE _IO('d', 100)
+ #define KCOV_DF_DISABLE _IO('d', 101)
+ #define BUF_SIZE (64 << 10) /* 64K words = 512KB */
+
+ int main(void)
+ {
+ int fd;
+ uint64_t *buf, n, i;
+
+ fd = open("/sys/kernel/debug/kcov_dataflow", O_RDWR);
+ if (fd == -1)
+ perror("open"), exit(1);
+
+ /* Allocate buffer (size in u64 words). */
+ if (ioctl(fd, KCOV_DF_INIT_TRACE, BUF_SIZE))
+ perror("ioctl(INIT)"), exit(1);
+
+ /* Map the buffer into user space. */
+ buf = (uint64_t *)mmap(NULL, BUF_SIZE * sizeof(uint64_t),
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (buf == MAP_FAILED)
+ perror("mmap"), exit(1);
+
+ /* Enable data-flow collection for this task. */
+ if (ioctl(fd, KCOV_DF_ENABLE, 0))
+ perror("ioctl(ENABLE)"), exit(1);
+
+ /* Reset counter. */
+ __atomic_store_n(&buf[0], 0, __ATOMIC_RELAXED);
+
+ /* === Trigger syscall(s) here === */
+ read(-1, NULL, 0);
+
+ /* Read how many words were written. */
+ n = __atomic_load_n(&buf[0], __ATOMIC_RELAXED);
+
+ /* Parse TLV records. */
+ i = 1;
+ while (i < n) {
+ uint64_t type_seq = buf[i];
+ uint64_t pc = buf[i + 1];
+ uint64_t meta = buf[i + 2];
+ uint32_t type = (type_seq >> 28) & 0xF;
+ uint32_t seq = type_seq & 0x00FFFFFF;
+ uint32_t arg_idx = (meta >> 56) & 0xFF;
+ uint32_t size = (meta >> 48) & 0xFF;
+
+ printf("[%s] seq=%u pc=0x%lx arg_idx=%u size=%u val=0x%lx\n",
+ type == 0xE ? "ENTRY" : "RET",
+ seq, pc, arg_idx, size, buf[i + 3]);
+ i += 4; /* minimum record size: 3 header + 1 value */
+ }
+
+ if (ioctl(fd, KCOV_DF_DISABLE, 0))
+ perror("ioctl(DISABLE)"), exit(1);
+
+ munmap(buf, BUF_SIZE * sizeof(uint64_t));
+ close(fd);
+ return 0;
+ }
+
+Ring buffer format
+------------------
+
+The buffer is an array of ``u64`` words::
+
+ buf[0]: atomic counter — total words written
+
+Each record occupies 3 + N words:
+
++--------+------------------+---------------------------------------------+
+| Offset | Field | Description |
++========+==================+=============================================+
+| 0 | type_and_seq | bits[31:28] = 0xE (entry) or 0xF (return), |
+| | | bits[23:0] = per-task sequence number |
++--------+------------------+---------------------------------------------+
+| 1 | pc | Instrumented function address |
++--------+------------------+---------------------------------------------+
+| 2 | meta | bits[63:56] = arg_idx (0 for return), |
+| | | bits[55:48] = size in bytes, |
+| | | bits[47:0] = raw pointer value |
++--------+------------------+---------------------------------------------+
+| 3..N | field_val[0..N] | Struct field values or single scalar |
++--------+------------------+---------------------------------------------+
+
+Magic values:
+
+- ``0xBADADD85``: field read failed (pointer was invalid/freed/poisoned)
+
+Safety
+------
+
+- Callbacks are ``notrace``, ``__no_sanitize_coverage``, ``noinline``
+ to prevent recursion.
+- All pointer reads use ``copy_from_kernel_nofault()`` — survives
+ freed, poisoned, or unmapped memory.
+- An ``in_task()`` guard rejects calls from hardirq/softirq/NMI context,
+ preventing reentrant buffer corruption.
+- No ``printk`` or allocation in the data path.
+- When not enabled for a task, overhead is a single boolean check.
+
+Ioctl interface
+---------------
+
++---------------------+----------------------------+---------------------------+
+| Command | Value | Description |
++=====================+============================+===========================+
+| KCOV_DF_INIT_TRACE | ``_IOR('d', 1, unsigned | Allocate buffer |
+| | long)`` | (size in u64 words) |
++---------------------+----------------------------+---------------------------+
+| KCOV_DF_ENABLE | ``_IO('d', 100)`` | Start collection for |
+| | | current task |
++---------------------+----------------------------+---------------------------+
+| KCOV_DF_DISABLE | ``_IO('d', 101)`` | Stop collection |
++---------------------+----------------------------+---------------------------+
+
+Compatibility
+-------------
+
+KCOV-Dataflow is completely independent from legacy KCOV:
+
+- Separate device: ``/sys/kernel/debug/kcov_dataflow``
+- Separate ioctl namespace (``'d'`` vs ``'c'``)
+- Separate per-task buffer
+- Both can be used simultaneously without interference
+- syzkaller and other KCOV users are unaffected
+
+Rust module support
+-------------------
+
+Rust kernel modules are supported via a post-compilation pipeline::
+
+ rustc --emit=llvm-ir -g module.rs
+ opt -passes=sancov-module \
+ -sanitizer-coverage-dataflow-args \
+ -sanitizer-coverage-dataflow-ret module.ll -S -o module_inst.ll
+ llc -filetype=obj module_inst.ll -o module.o
+
+This is the good method for capturing Rust function arguments at runtime.
+
+
+Tracing child processes (fork interception)
+-------------------------------------------
+
+KCOV-Dataflow is per-task: after ``fork()``, the child does not inherit
+the enabled state. To trace child processes, re-enable on the inherited
+file descriptor in the child before ``exec()``. The ``mmap``'d buffer is
+shared (``MAP_SHARED``), so both parent and child write to the same ring
+buffer atomically.
+
+.. code-block:: c
+
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
+ #include <sys/wait.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+
+ #define KCOV_DF_INIT_TRACE _IOR('d', 1, unsigned long)
+ #define KCOV_DF_ENABLE _IO('d', 100)
+ #define KCOV_DF_DISABLE _IO('d', 101)
+ #define BUF_SIZE (64 << 10)
+
+ int main(int argc, char **argv)
+ {
+ int fd = open("/sys/kernel/debug/kcov_dataflow", O_RDWR);
+ ioctl(fd, KCOV_DF_INIT_TRACE, BUF_SIZE);
+ uint64_t *buf = mmap(NULL, BUF_SIZE * 8,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ /* Enable for parent task */
+ ioctl(fd, KCOV_DF_ENABLE, 0);
+ __atomic_store_n(&buf[0], 0, __ATOMIC_RELAXED);
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* Child: re-enable on inherited fd.
+ * The shared mmap buffer receives records from both tasks.
+ */
+ ioctl(fd, KCOV_DF_ENABLE, 0);
+ execvp(argv[1], &argv[1]);
+ _exit(1);
+ }
+
+ waitpid(pid, NULL, 0);
+ ioctl(fd, KCOV_DF_DISABLE, 0);
+
+ uint64_t n = __atomic_load_n(&buf[0], __ATOMIC_RELAXED);
+ printf("Captured %lu words from parent + child\n", n);
+
+ munmap(buf, BUF_SIZE * 8);
+ close(fd);
+ return 0;
+ }
+
+Note: the child's ``ioctl(fd, KCOV_DF_ENABLE)`` will fail if the parent
+has not yet called ``KCOV_DF_DISABLE``, because only one task can be
+associated with a descriptor at a time. For true multi-process tracing,
+open a separate ``kcov_dataflow`` fd per child, or disable in the parent
+before the child enables (as shown above — the parent is blocked in
+``waitpid`` so it generates no records during that time anyway).
diff --git a/kernel/Makefile b/kernel/Makefile
index 1e1a31673577..9c56421c5390 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -37,6 +37,7 @@ KCOV_INSTRUMENT_extable.o := n
KCOV_INSTRUMENT_stacktrace.o := n
# Don't self-instrument.
KCOV_INSTRUMENT_kcov.o := n
+KCOV_DATAFLOW_kcov.o := n
# If sanitizers detect any issues in kcov, it may lead to recursion
# via printk, etc.
KASAN_SANITIZE_kcov.o := n
@@ -207,3 +208,5 @@ $(obj)/kheaders.md5: $(obj)/kheaders-srclist FORCE
$(call filechk,kheaders_md5sum)
clean-files := kheaders.md5 kheaders-srclist kheaders-objlist
+KCOV_DATAFLOW_extable.o := n
+KCOV_DATAFLOW_softirq.o := n
diff --git a/kernel/kcov.c b/kernel/kcov.c
index 373b8034ca5c..8d9d5e33549f 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -413,6 +413,16 @@ kcov_df_write(u64 type_marker, u64 pc, u64 meta, void *ptr,
if (!in_task())
return;
+ /*
+ * Prevent recursion: functions called by this callback
+ * (copy_from_kernel_nofault, xadd helpers) may be instrumented
+ * with INSTRUMENT_ALL. Use a per-task guard via the sequence
+ * counter's high bit.
+ */
+ if (t->kcov_dataflow_seq & (1U << 31))
+ return;
+ t->kcov_dataflow_seq |= (1U << 31);
+
area = (u64 *)t->kcov_df_area;
if (!area)
return;
@@ -449,7 +459,7 @@ kcov_df_write(u64 type_marker, u64 pc, u64 meta, void *ptr,
if (KCOV_DF_IS_ERR(ptr)) {
for (i = 0; i < num_fields; i++)
area[pos + 3 + i] = KCOV_DF_MAGIC_BAD;
- return;
+ goto out;
}
for (i = 0; i < num_fields; i++) {
u64 off, sz, val = KCOV_DF_MAGIC_BAD;
@@ -469,6 +479,8 @@ kcov_df_write(u64 type_marker, u64 pc, u64 meta, void *ptr,
area[pos + 3 + i] = val;
}
}
+out:
+ t->kcov_dataflow_seq &= ~(1U << 31);
}
#ifdef CONFIG_KCOV_DATAFLOW_ARGS
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v2 5/6] kcov: add interrupt context guard to kcov_df_write()
From: Yunseong Kim @ 2026-06-03 17:43 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, Dmitry Vyukov,
Andrey Konovalov, Andrew Morton, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Nicolas Schier,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Jonathan Corbet, Shuah Khan
Cc: Yunseong Kim, linux-kernel, kasan-dev, llvm, linux-kbuild,
rust-for-linux, workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4@est.tech>
The KCOV-Dataflow write path (kcov_df_write) only checks
t->kcov_df_enabled before writing to the shared ring buffer. Unlike
the standard KCOV check_kcov_mode() which rejects interrupt context,
kcov_df_write() has no such protection. This means instrumented code
running in hardirq, softirq, or NMI context that interrupts a task
mid-write can re-enter kcov_df_write(), causing:
- Data corruption in the ring buffer (interleaved records)
- Out-of-order sequence counter increments
- Potential faults from nested pointer dereferences
Add an in_task() check to reject calls from non-task context, matching
the safety model of the standard KCOV tracing path.
Also suppress -Wmissing-prototypes in the eight_args_c test module
Makefile, as the exported test functions intentionally lack a shared
header.
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
kernel/kcov.c | 4 ++++
tools/kcov-dataflow/eight_args_c/Makefile | 1 +
2 files changed, 5 insertions(+)
diff --git a/kernel/kcov.c b/kernel/kcov.c
index d3c9c0efe961..373b8034ca5c 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -409,6 +409,10 @@ kcov_df_write(u64 type_marker, u64 pc, u64 meta, void *ptr,
if (!t->kcov_df_enabled)
return;
+ /* Reject calls from hardirq/softirq/NMI to prevent reentrant corruption. */
+ if (!in_task())
+ return;
+
area = (u64 *)t->kcov_df_area;
if (!area)
return;
diff --git a/tools/kcov-dataflow/eight_args_c/Makefile b/tools/kcov-dataflow/eight_args_c/Makefile
index de35bb541f07..038775b49435 100644
--- a/tools/kcov-dataflow/eight_args_c/Makefile
+++ b/tools/kcov-dataflow/eight_args_c/Makefile
@@ -1,2 +1,3 @@
obj-m := eight_args_mod.o
KCOV_DATAFLOW_eight_args_mod.o := y
+ccflags-y += -Wno-missing-prototypes
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v2 4/6] tools/kcov-dataflow: add userspace consumer and test modules
From: Yunseong Kim @ 2026-06-03 17:43 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, Dmitry Vyukov,
Andrey Konovalov, Andrew Morton, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Nicolas Schier,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Jonathan Corbet, Shuah Khan
Cc: Yunseong Kim, linux-kernel, kasan-dev, llvm, linux-kbuild,
rust-for-linux, workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4@est.tech>
Add tools/kcov-dataflow/ with:
- trigger.c: userspace consumer that opens /sys/kernel/debug/kcov_dataflow,
mmaps the buffer, enables recording, triggers a kernel path, and dumps
the captured TLV records.
- kcov-view.py: visualization tool that parses and pretty-prints the
binary TLV buffer with struct field expansion and symbol resolution.
- eight_args_c/eight_args_mod.c: stress test with 1-8 argument functions
verifying correct capture of register and stack-passed arguments.
- eight_args_rust/eight_args_rust.rs: Rust equivalent of the 8-argument
stress test, verifying Rust module dataflow support.
- deep_module/deep_chain_mod.c: 10-level deep call chain demonstrating
taint propagation tracking across function boundaries.
Sample kcov-view.py output (C):
func2+0x0 [eight_args_mod](arg[0]=0x11, arg[1]=0x22)
ret = 0x33
func8+0x0 [eight_args_mod](arg[0]=0x11, .., arg[7]=0x88)
ret = 0x264
Sample kcov-view.py output (Rust):
rfunc2+0x0 [eight_args_rust](arg[0]=0x11, arg[1]=0x22)
ret = 0x33
rfunc8+0x0 [eight_args_rust](arg[0]=0x11, .., arg[7]=0x88)
ret = 0x264
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
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 | 2 +
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 ++++++++++
9 files changed, 848 insertions(+)
diff --git a/tools/kcov-dataflow/.gitignore b/tools/kcov-dataflow/.gitignore
new file mode 100644
index 000000000000..1f35df8fbd07
--- /dev/null
+++ b/tools/kcov-dataflow/.gitignore
@@ -0,0 +1,12 @@
+# Built binaries
+test_mock
+test_mock_binary
+trigger
+*.o
+*.ko
+*.mod
+*.mod.c
+Module.symvers
+modules.order
+.module-common.o
+*.ll
diff --git a/tools/kcov-dataflow/deep_module/Makefile b/tools/kcov-dataflow/deep_module/Makefile
new file mode 100644
index 000000000000..6afed580dc9a
--- /dev/null
+++ b/tools/kcov-dataflow/deep_module/Makefile
@@ -0,0 +1,2 @@
+obj-m := deep_chain_mod.o
+KCOV_DATAFLOW_deep_chain_mod.o := y
diff --git a/tools/kcov-dataflow/deep_module/deep_chain_mod.c b/tools/kcov-dataflow/deep_module/deep_chain_mod.c
new file mode 100644
index 000000000000..786e23c5d213
--- /dev/null
+++ b/tools/kcov-dataflow/deep_module/deep_chain_mod.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * deep_chain_mod.c - Demonstrates kcov_dataflow tracing through 10 nested
+ * function calls. An attacker-controlled "offset" value propagates from
+ * the entry point through transformations until it causes an OOB write
+ * in the deepest function.
+ *
+ * Call chain:
+ * entry_handler → parse_request → validate_header → extract_payload →
+ * transform_data → apply_filter → compute_index → lookup_slot →
+ * write_slot → commit_write (BUG: OOB here)
+ */
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+
+/* Simulated protocol structures */
+struct request_header {
+ u32 magic;
+ u32 version;
+ u32 payload_offset; /* ← attacker controls this */
+ u32 payload_size;
+};
+
+struct payload {
+ u64 session_id;
+ u32 transform_key;
+ u32 filter_mask;
+ u8 data[32];
+};
+
+struct slot_table {
+ u32 num_slots;
+ u64 slots[8]; /* only 8 slots! */
+};
+
+static struct proc_dir_entry *proc_deep;
+
+/* === 10 nested functions: deepest first === */
+
+/* Function 10 (DEEPEST): The vulnerable write */
+static noinline int commit_write(struct slot_table *table, u32 index, u64 value)
+{
+ /* BUG: no bounds check on index — if index >= 8, OOB write */
+ table->slots[index] = value;
+ return 0;
+}
+
+/* Function 9 */
+static noinline int write_slot(struct slot_table *table, u32 slot_idx,
+ u64 session_id)
+{
+ u64 combined = session_id ^ (u64)slot_idx;
+
+ return commit_write(table, slot_idx, combined);
+}
+
+/* Function 8 */
+static noinline u32 lookup_slot(struct slot_table *table, u32 computed_idx)
+{
+ /* Pass through — in real code this might do hash lookup */
+ u32 final_idx = computed_idx % 16; /* BUG: should be % 8 */
+
+ write_slot(table, final_idx, 0xDEADC0DE00000000ULL | final_idx);
+ return final_idx;
+}
+
+/* Function 7 */
+static noinline u32 compute_index(u32 transform_result, u32 filter_output)
+{
+ /* Combines two values into an index */
+ return (transform_result + filter_output) & 0xF; /* 0-15, but table has 8 */
+}
+
+/* Function 6 */
+static noinline u32 apply_filter(struct payload *pl, u32 transformed_val)
+{
+ u32 filtered = transformed_val & pl->filter_mask;
+
+ return filtered >> 1;
+}
+
+/* Function 5 */
+static noinline u32 transform_data(struct payload *pl, u32 raw_offset)
+{
+ /* Transforms the offset using the payload's key */
+ return raw_offset * pl->transform_key;
+}
+
+/* Function 4 */
+static noinline struct payload *extract_payload(void *buf, u32 offset, u32 size)
+{
+ /* In real code: validates and extracts payload from buffer */
+ return (struct payload *)((u8 *)buf + offset);
+}
+
+/* Function 3 */
+static noinline int validate_header(struct request_header *hdr)
+{
+ if (hdr->magic != 0x50524F54) /* "PROT" */
+ return -1;
+ if (hdr->version > 2)
+ return -1;
+ /* BUG: doesn't validate payload_offset bounds! */
+ return 0;
+}
+
+/* Function 2 */
+static noinline int parse_request(void *buf, u32 buf_size,
+ struct request_header **out_hdr,
+ struct payload **out_payload)
+{
+ struct request_header *hdr = (struct request_header *)buf;
+
+ if (validate_header(hdr) < 0)
+ return -1;
+
+ *out_hdr = hdr;
+ *out_payload = extract_payload(buf, hdr->payload_offset, hdr->payload_size);
+ return 0;
+}
+
+/* Function 1 (ENTRY): The syscall handler */
+static noinline int entry_handler(void *user_buf, u32 user_size)
+{
+ struct request_header *hdr;
+ struct payload *pl;
+ struct slot_table *table;
+ u32 transformed, filtered, index, slot;
+
+ if (parse_request(user_buf, user_size, &hdr, &pl) < 0)
+ return -1;
+
+ table = kzalloc(sizeof(*table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+ table->num_slots = 8;
+
+ /* The tainted data flow:
+ * hdr->payload_offset → extract_payload → pl
+ * pl->transform_key + payload_offset → transform_data → transformed
+ * transformed + pl->filter_mask → apply_filter → filtered
+ * transformed + filtered → compute_index → index
+ * index → lookup_slot → slot (% 16, should be % 8)
+ * slot → write_slot → commit_write (OOB if slot >= 8)
+ */
+ transformed = transform_data(pl, hdr->payload_offset);
+ filtered = apply_filter(pl, transformed);
+ index = compute_index(transformed, filtered);
+ slot = lookup_slot(table, index);
+
+ pr_info("deep_chain: slot=%u (OOB if >= 8)\n", slot);
+
+ kfree(table);
+ return 0;
+}
+
+/* Trigger: constructs a malicious request that causes index=12 (OOB) */
+static ssize_t deep_trigger_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ u8 *buf;
+ struct request_header *hdr;
+ struct payload *pl;
+
+ buf = kzalloc(256, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ /* Craft malicious request */
+ hdr = (struct request_header *)buf;
+ hdr->magic = 0x50524F54; /* valid magic */
+ hdr->version = 1; /* valid version */
+ hdr->payload_offset = 16; /* offset to payload (valid position) */
+ hdr->payload_size = sizeof(struct payload);
+
+ /* Craft payload that will produce OOB index */
+ pl = (struct payload *)(buf + 16);
+ pl->session_id = 0xAAAABBBBCCCCDDDDULL;
+ pl->transform_key = 3; /* multiplier */
+ pl->filter_mask = 0xFFFFFFFF; /* no filtering */
+ memcpy(pl->data, "ATTACKER_PAYLOAD_DATA!!!", 24);
+
+ /*
+ * Trace: payload_offset=16, transform_key=3
+ * transformed = 16 * 3 = 48
+ * filtered = (48 & 0xFFFFFFFF) >> 1 = 24
+ * index = (48 + 24) & 0xF = 72 & 0xF = 8
+ * lookup_slot: final_idx = 8 % 16 = 8 ← OOB! (table has slots[0..7])
+ */
+
+ pr_info("deep_chain: triggering 10-deep call chain with offset=%u\n",
+ hdr->payload_offset);
+
+ entry_handler(buf, 256);
+
+ kfree(buf);
+ return count;
+}
+
+static const struct proc_ops deep_proc_ops = {
+ .proc_write = deep_trigger_write,
+};
+
+static int __init deep_chain_init(void)
+{
+ proc_deep = proc_create("deep_trigger", 0200, NULL, &deep_proc_ops);
+ if (!proc_deep)
+ return -ENOMEM;
+ pr_info("deep_chain_mod: loaded. echo x > /proc/deep_trigger\n");
+ return 0;
+}
+
+static void __exit deep_chain_exit(void)
+{
+ proc_remove(proc_deep);
+}
+
+module_init(deep_chain_init);
+module_exit(deep_chain_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("10-deep call chain for kcov_dataflow visualization");
diff --git a/tools/kcov-dataflow/eight_args_c/Makefile b/tools/kcov-dataflow/eight_args_c/Makefile
new file mode 100644
index 000000000000..de35bb541f07
--- /dev/null
+++ b/tools/kcov-dataflow/eight_args_c/Makefile
@@ -0,0 +1,2 @@
+obj-m := eight_args_mod.o
+KCOV_DATAFLOW_eight_args_mod.o := y
diff --git a/tools/kcov-dataflow/eight_args_c/eight_args_mod.c b/tools/kcov-dataflow/eight_args_c/eight_args_mod.c
new file mode 100644
index 000000000000..660b27033756
--- /dev/null
+++ b/tools/kcov-dataflow/eight_args_c/eight_args_mod.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * eight_args_mod.c - Verify kcov_dataflow captures 1 through 8 argument functions.
+ */
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KCOV dataflow 8-argument stress test module");
+
+noinline u64 func1(u64 a1)
+{
+ return a1;
+}
+EXPORT_SYMBOL(func1);
+
+noinline u64 func2(u64 a1, u64 a2)
+{
+ return a1 + a2;
+}
+EXPORT_SYMBOL(func2);
+
+noinline u64 func3(u64 a1, u64 a2, u64 a3)
+{
+ return a1 + a2 + a3;
+}
+EXPORT_SYMBOL(func3);
+
+noinline u64 func4(u64 a1, u64 a2, u64 a3, u64 a4)
+{
+ return a1 + a2 + a3 + a4;
+}
+EXPORT_SYMBOL(func4);
+
+noinline u64 func5(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
+{
+ return a1 + a2 + a3 + a4 + a5;
+}
+EXPORT_SYMBOL(func5);
+
+noinline u64 func6(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6)
+{
+ return a1 + a2 + a3 + a4 + a5 + a6;
+}
+EXPORT_SYMBOL(func6);
+
+noinline u64 func7(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6,
+ u64 a7)
+{
+ return a1 + a2 + a3 + a4 + a5 + a6 + a7;
+}
+EXPORT_SYMBOL(func7);
+
+noinline u64 func8(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6,
+ u64 a7, u64 a8)
+{
+ return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8;
+}
+EXPORT_SYMBOL(func8);
+
+static ssize_t trigger_write(struct file *f, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ pr_info("func1(0x11)=0x%llx\n", func1(0x11));
+ pr_info("func2(0x11,0x22)=0x%llx\n", func2(0x11, 0x22));
+ pr_info("func3(0x11,0x22,0x33)=0x%llx\n",
+ func3(0x11, 0x22, 0x33));
+ pr_info("func4(0x11,..,0x44)=0x%llx\n",
+ func4(0x11, 0x22, 0x33, 0x44));
+ pr_info("func5(0x11,..,0x55)=0x%llx\n",
+ func5(0x11, 0x22, 0x33, 0x44, 0x55));
+ pr_info("func6(0x11,..,0x66)=0x%llx\n",
+ func6(0x11, 0x22, 0x33, 0x44, 0x55, 0x66));
+ pr_info("func7(0x11,..,0x77)=0x%llx\n",
+ func7(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77));
+ pr_info("func8(0x11,..,0x88)=0x%llx\n",
+ func8(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88));
+ return count;
+}
+
+static const struct proc_ops ops = { .proc_write = trigger_write };
+
+static int __init init_mod(void)
+{
+ proc_create("test_args", 0200, NULL, &ops);
+ return 0;
+}
+
+static void __exit exit_mod(void)
+{
+ remove_proc_entry("test_args", NULL);
+}
+
+module_init(init_mod);
+module_exit(exit_mod);
diff --git a/tools/kcov-dataflow/eight_args_rust/Makefile b/tools/kcov-dataflow/eight_args_rust/Makefile
new file mode 100644
index 000000000000..8881d369e670
--- /dev/null
+++ b/tools/kcov-dataflow/eight_args_rust/Makefile
@@ -0,0 +1,2 @@
+obj-m := eight_args_rust.o
+KCOV_DATAFLOW_eight_args_rust.o := y
diff --git a/tools/kcov-dataflow/eight_args_rust/eight_args_rust.rs b/tools/kcov-dataflow/eight_args_rust/eight_args_rust.rs
new file mode 100644
index 000000000000..11bbe1449eaf
--- /dev/null
+++ b/tools/kcov-dataflow/eight_args_rust/eight_args_rust.rs
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+//! Verify kcov_dataflow captures 1-arg through 8-arg functions.
+//! Write to /sys/kernel/debug/test_args_rust to trigger all 8.
+#![allow(missing_docs)]
+
+use kernel::prelude::*;
+use kernel::c_str;
+
+module! {
+ type: ArgsModule,
+ name: "eight_args_rust",
+ authors: ["kcov-dataflow"],
+ description: "1-8 arg verification",
+ license: "GPL",
+}
+
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rfunc1(a1: u64) -> u64 { a1 }
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rfunc2(a1: u64, a2: u64) -> u64 { a1 + a2 }
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rfunc3(a1: u64, a2: u64, a3: u64) -> u64 {
+ a1 + a2 + a3
+}
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rfunc4(a1: u64, a2: u64, a3: u64, a4: u64) -> u64 {
+ a1 + a2 + a3 + a4
+}
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rfunc5(
+ a1: u64, a2: u64, a3: u64, a4: u64, a5: u64,
+) -> u64 {
+ a1 + a2 + a3 + a4 + a5
+}
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rfunc6(
+ a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a6: u64,
+) -> u64 {
+ a1 + a2 + a3 + a4 + a5 + a6
+}
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rfunc7(
+ a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a6: u64, a7: u64,
+) -> u64 {
+ a1 + a2 + a3 + a4 + a5 + a6 + a7
+}
+#[no_mangle]
+#[inline(never)]
+pub extern "C" fn rfunc8(
+ a1: u64, a2: u64, a3: u64, a4: u64, a5: u64, a6: u64, a7: u64,
+ a8: u64,
+) -> u64 {
+ a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8
+}
+
+unsafe extern "C" fn write_handler(
+ _file: *mut kernel::bindings::file,
+ _buf: *const core::ffi::c_char,
+ count: usize,
+ _ppos: *mut kernel::bindings::loff_t,
+) -> kernel::ffi::c_long {
+ let r1 = rfunc1(0x11);
+ pr_info!("rfunc1: ret=0x{:x}\n", r1);
+ let r2 = rfunc2(0x11, 0x22);
+ pr_info!("rfunc2: ret=0x{:x}\n", r2);
+ let r3 = rfunc3(0x11, 0x22, 0x33);
+ pr_info!("rfunc3: ret=0x{:x}\n", r3);
+ let r4 = rfunc4(0x11, 0x22, 0x33, 0x44);
+ pr_info!("rfunc4: ret=0x{:x}\n", r4);
+ let r5 = rfunc5(0x11, 0x22, 0x33, 0x44, 0x55);
+ pr_info!("rfunc5: ret=0x{:x}\n", r5);
+ let r6 = rfunc6(0x11, 0x22, 0x33, 0x44, 0x55, 0x66);
+ pr_info!("rfunc6: ret=0x{:x}\n", r6);
+ let r7 = rfunc7(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77);
+ pr_info!("rfunc7: ret=0x{:x}\n", r7);
+ let r8 = rfunc8(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
+ pr_info!("rfunc8: ret=0x{:x}\n", r8);
+ count as kernel::ffi::c_long
+}
+
+#[repr(transparent)]
+struct SyncFops(kernel::bindings::file_operations);
+unsafe impl Sync for SyncFops {}
+
+static FOPS: SyncFops = SyncFops(kernel::bindings::file_operations {
+ write: Some(unsafe { core::mem::transmute(write_handler as *const ()) }),
+ ..unsafe { core::mem::zeroed() }
+});
+
+struct ArgsModule { d: *mut kernel::bindings::dentry }
+
+impl kernel::Module for ArgsModule {
+ fn init(_module: &'static ThisModule) -> Result<Self> {
+ let d = unsafe {
+ kernel::bindings::debugfs_create_file_unsafe(
+ c_str!("test_args_rust").as_char_ptr(),
+ 0o222, core::ptr::null_mut(), core::ptr::null_mut(), &FOPS.0,
+ )
+ };
+ Ok(Self { d })
+ }
+}
+impl Drop for ArgsModule {
+ fn drop(&mut self) { unsafe { kernel::bindings::debugfs_remove(self.d) }; }
+}
+unsafe impl Send for ArgsModule {}
+unsafe impl Sync for ArgsModule {}
diff --git a/tools/kcov-dataflow/kcov-view.py b/tools/kcov-dataflow/kcov-view.py
new file mode 100755
index 000000000000..70acb5474f5e
--- /dev/null
+++ b/tools/kcov-dataflow/kcov-view.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+"""
+kcov-view.py - Merged KCOV + KCOV_DATAFLOW viewer
+
+Reads both /sys/kernel/debug/kcov (PC trace) and /sys/kernel/debug/kcov_dataflow
+(args/ret), correlates by PC, and produces a human-readable call trace with
+argument values and struct field expansion.
+
+Usage (inside guest or with appropriate permissions):
+ python3 kcov-view.py <trigger_command>
+
+Example:
+ python3 kcov-view.py "echo x > /proc/uaf_trigger"
+
+Output:
+ func+0x0 [module]
+ → a(arg[0]=0x1, arg[1]=0x2, arg[2]=0x3, arg[3]=struct{.f[0]=1, .f[1]=2, .f[2]=3})
+ ← ret = struct{.f[0]=1, .f[1]=2, .f[2]=3}
+ → a(arg[0]=0x0, arg[1]=0x0, arg[2]=0x1, arg[3]=NULL)
+ ← ret = 0x0
+"""
+import os, sys, struct, mmap, fcntl, subprocess, re, ctypes
+from collections import defaultdict
+
+# Ioctl definitions (x86_64)
+KCOV_INIT_TRACE = 0x80086301 # _IOR('c', 1, unsigned long)
+KCOV_ENABLE = 0x6364 # _IO('c', 100)
+KCOV_DISABLE = 0x6365 # _IO('c', 101)
+KCOV_TRACE_PC = 0
+
+KCOV_DF_INIT_TRACE = 0x80086401 # _IOR('d', 1, unsigned long)
+KCOV_DF_ENABLE = 0x6464 # _IO('d', 100)
+KCOV_DF_DISABLE = 0x6465 # _IO('d', 101)
+
+BUF_SIZE = 65536 # 65536 * 8 = 512KB = 128 pages (page-aligned)
+
+# Load kallsyms for symbolization
+def load_kallsyms():
+ syms = {}
+ try:
+ with open("/proc/kallsyms") as f:
+ for line in f:
+ parts = line.split()
+ if len(parts) >= 3:
+ addr = int(parts[0], 16)
+ name = parts[2]
+ mod = parts[3].strip("[]") if len(parts) > 3 else ""
+ syms[addr] = (name, mod)
+ except:
+ pass
+ return syms
+
+def symbolize(pc, syms):
+ """Find nearest symbol <= pc"""
+ best_addr = 0
+ best_name = f"0x{pc:x}"
+ best_mod = ""
+ for addr, (name, mod) in syms.items():
+ if addr <= pc and addr > best_addr:
+ best_addr = addr
+ best_name = name
+ best_mod = mod
+ offset = pc - best_addr
+ if best_mod:
+ return f"{best_name}+0x{offset:x} [{best_mod}]"
+ return f"{best_name}+0x{offset:x}"
+
+def parse_dataflow(buf, n):
+ """Parse TLV records from kcov_dataflow buffer into a list of events."""
+ events = []
+ i = 1
+ while i <= n and i < BUF_SIZE:
+ hdr = buf[i]
+ typ = hdr & 0xF0000000
+ seq = hdr & 0x00FFFFFF
+
+ if typ not in (0xE0000000, 0xF0000000):
+ i += 1
+ continue
+
+ pc = buf[i + 1]
+ meta = buf[i + 2]
+ i += 3
+
+ # Collect field values
+ fields = []
+ while i <= n and i < BUF_SIZE:
+ v = buf[i]
+ vtype = v & 0xF0000000
+ if vtype == 0xE0000000 or vtype == 0xF0000000:
+ break
+ fields.append(v)
+ i += 1
+
+ if typ == 0xE0000000:
+ arg_idx = (meta >> 56) & 0xFF
+ arg_sz = (meta >> 48) & 0xFF
+ ptr = meta & 0xFFFFFFFFFFFF
+ events.append({
+ "type": "entry", "seq": seq, "pc": pc,
+ "arg_idx": arg_idx, "arg_size": arg_sz,
+ "ptr": ptr, "fields": fields
+ })
+ else:
+ ret_sz = (meta >> 48) & 0xFF
+ ptr = meta & 0xFFFFFFFFFFFF
+ events.append({
+ "type": "ret", "seq": seq, "pc": pc,
+ "ret_size": ret_sz, "ptr": ptr, "fields": fields
+ })
+ return events
+
+def format_value(val):
+ if val == 0xBADADD85:
+ return "FAULT"
+ if val == 0:
+ return "0"
+ return f"0x{val:x}"
+
+def format_entry(ev):
+ """Format an entry event as a function argument."""
+ if len(ev["fields"]) > 1:
+ # Struct: multiple fields
+ flds = ", ".join(f".f[{i}]={format_value(v)}" for i, v in enumerate(ev["fields"]))
+ return f"struct{{{flds}}}"
+ elif len(ev["fields"]) == 1:
+ v = ev["fields"][0]
+ if v == 0 and ev["ptr"] == 0:
+ return "NULL"
+ return format_value(v)
+ return format_value(ev["ptr"])
+
+def merge_and_display(pc_trace, df_events, syms):
+ """Display dataflow events with symbolization."""
+ print("\n╔═══════════════════════════════════════════════════════════╗")
+ print("║ Merged KCOV Coverage + Dataflow View ║")
+ print("╚═══════════════════════════════════════════════════════════╝\n")
+
+ if not df_events:
+ print(" (no dataflow events captured)")
+ return
+
+ # Group events into calls: consecutive entries for same PC followed by a ret
+ calls = []
+ current_args = []
+ current_pc = None
+
+ for ev in df_events:
+ if ev["type"] == "entry":
+ if current_pc is not None and ev["pc"] != current_pc:
+ calls.append({"pc": current_pc, "args": current_args, "ret": None})
+ current_args = []
+ current_pc = ev["pc"]
+ current_args.append(ev)
+ elif ev["type"] == "ret":
+ if current_pc == ev["pc"]:
+ calls.append({"pc": current_pc, "args": current_args, "ret": ev})
+ current_args = []
+ current_pc = None
+ else:
+ if current_args:
+ calls.append({"pc": current_pc, "args": current_args, "ret": None})
+ current_args = []
+ calls.append({"pc": ev["pc"], "args": [], "ret": ev})
+ current_pc = None
+
+ if current_args:
+ calls.append({"pc": current_pc, "args": current_args, "ret": None})
+
+ for call in calls:
+ sym = symbolize(call["pc"], syms)
+ args_parts = []
+ for a in call["args"]:
+ idx = a["arg_idx"]
+ if len(a["fields"]) > 1:
+ flds = ", ".join(f".f[{i}]={format_value(v)}" for i, v in enumerate(a["fields"]))
+ args_parts.append(f"arg[{idx}]=struct{{{flds}}}")
+ elif len(a["fields"]) == 1:
+ args_parts.append(f"arg[{idx}]={format_value(a['fields'][0])}")
+ else:
+ args_parts.append(f"arg[{idx}]=?")
+
+ print(f" → {sym}({', '.join(args_parts)})")
+
+ if call["ret"]:
+ r = call["ret"]
+ if len(r["fields"]) > 1:
+ flds = ", ".join(f".f[{i}]={format_value(v)}" for i, v in enumerate(r["fields"]))
+ print(f" ← ret = struct{{{flds}}}")
+ elif len(r["fields"]) == 1:
+ print(f" ← ret = {format_value(r['fields'][0])}")
+ print()
+
+def main():
+ if len(sys.argv) < 2:
+ print(f"Usage: {sys.argv[0]} <trigger_command>")
+ print(f"Example: {sys.argv[0]} 'echo x > /proc/uaf_trigger'")
+ sys.exit(1)
+
+ trigger_cmd = sys.argv[1]
+ syms = load_kallsyms()
+
+ # Setup ctypes mmap
+ libc = ctypes.CDLL("libc.so.6", use_errno=True)
+ libc.mmap.restype = ctypes.c_void_p
+ libc.mmap.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int,
+ ctypes.c_int, ctypes.c_int, ctypes.c_long]
+ PROT_RW = 0x3 # PROT_READ | PROT_WRITE
+ MAP_SHARED = 0x01
+
+ # Open both devices
+ kcov_fd = -1
+ df_fd = -1
+ kcov_arr = None
+ df_arr = None
+
+ # Legacy kcov (PC trace) - skip for now, use kallsyms for symbolization
+ kcov_arr = None
+
+ # Dataflow device - required
+ df_fd = os.open("/sys/kernel/debug/kcov_dataflow", os.O_RDWR)
+ fcntl.ioctl(df_fd, KCOV_DF_INIT_TRACE, BUF_SIZE)
+ df_ptr = libc.mmap(None, BUF_SIZE * 8, PROT_RW, MAP_SHARED, df_fd, 0)
+ if df_ptr == ctypes.c_void_p(-1).value:
+ print("Error: kcov_dataflow mmap failed")
+ sys.exit(1)
+ df_arr = (ctypes.c_uint64 * BUF_SIZE).from_address(df_ptr)
+
+ # Enable both
+ if kcov_arr:
+ fcntl.ioctl(kcov_fd, KCOV_ENABLE, KCOV_TRACE_PC)
+ kcov_arr[0] = 0
+
+ fcntl.ioctl(df_fd, KCOV_DF_ENABLE, 0)
+ df_arr[0] = 0
+
+ # Trigger - must happen in THIS process (kcov_dataflow is per-task)
+ if ">" in trigger_cmd:
+ target = trigger_cmd.split(">")[-1].strip()
+ else:
+ target = trigger_cmd
+ try:
+ fd_t = os.open(target, os.O_WRONLY)
+ os.write(fd_t, b"x")
+ os.close(fd_t)
+ except Exception as e:
+ print(f"Trigger failed: {e}")
+
+ # Read results
+ pc_trace = []
+ if kcov_arr:
+ n_pcs = kcov_arr[0]
+ for i in range(1, min(int(n_pcs) + 1, BUF_SIZE)):
+ pc_trace.append(kcov_arr[i])
+ fcntl.ioctl(kcov_fd, KCOV_DISABLE, 0)
+
+ n_df = int(df_arr[0])
+ df_raw = [int(df_arr[i]) for i in range(min(n_df + 10, BUF_SIZE))]
+ fcntl.ioctl(df_fd, KCOV_DF_DISABLE, 0)
+
+ # Parse and display
+ df_events = parse_dataflow(df_raw, int(n_df))
+ merge_and_display(pc_trace, df_events, syms)
+
+ # Cleanup
+ if kcov_arr:
+ os.close(kcov_fd)
+ os.close(df_fd)
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/kcov-dataflow/trigger.c b/tools/kcov-dataflow/trigger.c
new file mode 100644
index 000000000000..7fa7b4414770
--- /dev/null
+++ b/tools/kcov-dataflow/trigger.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * trigger.c - Uses /sys/kernel/debug/kcov_dataflow to capture
+ * function args/ret TLV records. Completely independent from legacy kcov.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#define KCOV_DF_INIT_TRACE _IOR('d', 1, unsigned long)
+#define KCOV_DF_ENABLE _IO('d', 100)
+#define KCOV_DF_DISABLE _IO('d', 101)
+
+#define COVER_SIZE (64 * 1024) /* 64K u64 words = 512KB */
+
+static void dump_buffer(uint64_t *cover, uint64_t n)
+{
+ uint64_t i = 1;
+
+ printf("=== KCOV Dataflow TLV Dump (%lu words) ===\n", n);
+ while (i <= n && i < COVER_SIZE) {
+ uint64_t hdr = cover[i];
+ uint64_t type = hdr & 0xF0000000ULL;
+ uint64_t seq = hdr & 0x00FFFFFFULL;
+ uint64_t pc = cover[i + 1];
+ uint64_t meta = cover[i + 2];
+
+ if (type == 0xE0000000ULL) {
+ uint32_t arg_idx = (meta >> 56) & 0xFF;
+ uint32_t arg_sz = (meta >> 48) & 0xFF;
+ uint64_t ptr = meta & 0xFFFFFFFFFFFFULL;
+
+ printf("[ENTRY] seq=%lu pc=0x%lx arg[%u](%u) ptr=0x%lx\n",
+ seq, pc, arg_idx, arg_sz, ptr);
+ } else if (type == 0xF0000000ULL) {
+ uint32_t ret_sz = (meta >> 48) & 0xFF;
+ uint64_t ptr = meta & 0xFFFFFFFFFFFFULL;
+
+ printf("[RET] seq=%lu pc=0x%lx ret(%u) ptr=0x%lx\n",
+ seq, pc, ret_sz, ptr);
+ } else {
+ i++;
+ continue;
+ }
+
+ /* Print field values */
+ i += 3;
+ while (i <= n && i < COVER_SIZE) {
+ uint64_t next = cover[i];
+ uint64_t next_type = next & 0xF0000000ULL;
+
+ if (next_type == 0xE0000000ULL || next_type == 0xF0000000ULL)
+ break;
+ if (next == 0xBADADD85ULL)
+ printf(" val = FAULT\n");
+ else
+ printf(" val = 0x%lx\n", next);
+ i++;
+ }
+ }
+ printf("=== Done ===\n");
+}
+
+int main(int argc, char **argv)
+{
+ const char *trigger_path = "/proc/uaf_trigger";
+ int fd, tfd;
+ uint64_t *cover;
+ uint64_t n;
+
+ if (argc > 1)
+ trigger_path = argv[1];
+
+ fd = open("/sys/kernel/debug/kcov_dataflow", O_RDWR);
+ if (fd < 0) {
+ perror("open kcov_dataflow");
+ return 1;
+ }
+
+ if (ioctl(fd, KCOV_DF_INIT_TRACE, COVER_SIZE)) {
+ perror("KCOV_DF_INIT_TRACE");
+ close(fd);
+ return 1;
+ }
+
+ cover = mmap(NULL, COVER_SIZE * sizeof(uint64_t),
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (cover == MAP_FAILED) {
+ perror("mmap");
+ close(fd);
+ return 1;
+ }
+
+ if (ioctl(fd, KCOV_DF_ENABLE, 0)) {
+ perror("KCOV_DF_ENABLE");
+ munmap(cover, COVER_SIZE * sizeof(uint64_t));
+ close(fd);
+ return 1;
+ }
+
+ /* Reset */
+ __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED);
+
+ /* Trigger */
+ tfd = open(trigger_path, O_WRONLY);
+ if (tfd >= 0) {
+ write(tfd, "x", 1);
+ close(tfd);
+ }
+
+ n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);
+
+ ioctl(fd, KCOV_DF_DISABLE, 0);
+
+ dump_buffer(cover, n);
+
+ munmap(cover, COVER_SIZE * sizeof(uint64_t));
+ close(fd);
+ return 0;
+}
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v2 3/6] kcov: add CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL and NO_INLINE
From: Yunseong Kim @ 2026-06-03 17:43 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, Dmitry Vyukov,
Andrey Konovalov, Andrew Morton, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Nicolas Schier,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Jonathan Corbet, Shuah Khan
Cc: Yunseong Kim, linux-kernel, kasan-dev, llvm, linux-kbuild,
rust-for-linux, workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4@est.tech>
Add two Kconfig options for global dataflow instrumentation control:
- CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL: instruments all kernel objects
with dataflow tracing by default (mirrors CONFIG_KCOV_INSTRUMENT_ALL).
Individual files can opt out with: KCOV_DATAFLOW_file.o := n
- CONFIG_KCOV_DATAFLOW_NO_INLINE: adds -fno-inline to instrumented files
for complete argument visibility (default y). Setting to n allows
global enablement without stack overflow or BUILD_BUG_ON failures.
Overhead with INSTRUMENT_ALL (NO_INLINE=n, KASAN baseline):
.text: +9.5%, .data: +44%, boot: +71%, syscall: +133%
Comparable to KASAN (+100-200%) and acceptable for fuzzing kernels.
rust/Makefile: opt out core.o from dataflow (same as KCOV_INSTRUMENT).
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
lib/Kconfig.debug | 23 ++++++++++++++++++++++-
rust/Makefile | 1 +
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index abd1a94589aa..3b952b6361a8 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2261,7 +2261,6 @@ config KCOV_SELFTEST
On test failure, causes the kernel to panic. Recommended to be
enabled, ensuring critical functionality works as intended.
-
config KCOV_DATAFLOW_ARGS
bool "Enable KCOV dataflow: function argument capture"
depends on KCOV
@@ -2283,6 +2282,28 @@ config KCOV_DATAFLOW_RET
metadata, recording individual field values at runtime.
Enable per-module with: KCOV_DATAFLOW_file.o := y in the Makefile.
Requires clang with -fsanitize-coverage=dataflow-ret support.
+
+config KCOV_DATAFLOW_INSTRUMENT_ALL
+ bool "Instrument all code with KCOV dataflow by default"
+ depends on KCOV_DATAFLOW_ARGS || KCOV_DATAFLOW_RET
+ help
+ If enabled, all kernel objects are compiled with dataflow
+ instrumentation (like CONFIG_KCOV_INSTRUMENT_ALL for basic KCOV).
+ Individual files can opt out with: KCOV_DATAFLOW_file.o := n
+ Increases compile time and binary size significantly.
+ Suitable for fuzzing and security auditing kernels.
+
+config KCOV_DATAFLOW_NO_INLINE
+ bool "Disable inlining for dataflow-instrumented files"
+ depends on KCOV_DATAFLOW_ARGS || KCOV_DATAFLOW_RET
+ default y
+ help
+ Adds -fno-inline to dataflow-instrumented files for complete
+ argument visibility. Without this, inlined functions will not
+ have their arguments captured individually.
+ Disabling allows global enablement with lower overhead at the
+ cost of missing inlined function traces.
+
config DEBUG_AID_FOR_SYZBOT
bool "Additional debug code for syzbot"
default n
diff --git a/rust/Makefile b/rust/Makefile
index b9e9f512cec3..d122a65226dc 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -656,6 +656,7 @@ ifneq ($(or $(CONFIG_X86_64),$(CONFIG_X86_32)),)
$(obj)/core.o: scripts/target.json
endif
KCOV_INSTRUMENT_core.o := n
+KCOV_DATAFLOW_core.o := n
$(obj)/compiler_builtins.o: private skip_gendwarfksyms = 1
$(obj)/compiler_builtins.o: private rustc_objcopy = -w -W '__*'
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v2 2/6] kcov: add build system support for dataflow instrumentation
From: Yunseong Kim @ 2026-06-03 17:43 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, Dmitry Vyukov,
Andrey Konovalov, Andrew Morton, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Nicolas Schier,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Jonathan Corbet, Shuah Khan
Cc: Yunseong Kim, linux-kernel, kasan-dev, llvm, linux-kbuild,
rust-for-linux, workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4@est.tech>
Add CFLAGS_KCOV_DATAFLOW and RUSTFLAGS_KCOV_DATAFLOW exports to
scripts/Makefile.kcov, containing:
-fsanitize-coverage=dataflow-args,dataflow-ret -g
(with optional -fno-inline via CONFIG_KCOV_DATAFLOW_NO_INLINE)
scripts/Makefile.lib applies these flags when a module's Makefile sets:
KCOV_DATAFLOW_file.o := y (per-file)
KCOV_DATAFLOW := y (per-directory)
Also supports CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL for global enablement.
The flags are only applied to kernel objects (same guard as basic KCOV).
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
scripts/Makefile.kcov | 6 ++++++
scripts/Makefile.lib | 7 +++++++
2 files changed, 13 insertions(+)
diff --git a/scripts/Makefile.kcov b/scripts/Makefile.kcov
index 78305a84ba9d..101173fe194b 100644
--- a/scripts/Makefile.kcov
+++ b/scripts/Makefile.kcov
@@ -2,10 +2,16 @@
kcov-flags-y += -fsanitize-coverage=trace-pc
kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -fsanitize-coverage=trace-cmp
+# KCOV dataflow: trace function args and return values
+kcov-dataflow-flags-y := -fsanitize-coverage=dataflow-args,dataflow-ret -g
+kcov-dataflow-flags-$(CONFIG_KCOV_DATAFLOW_NO_INLINE) += -fno-inline
+
kcov-rflags-y += -Cpasses=sancov-module
kcov-rflags-y += -Cllvm-args=-sanitizer-coverage-level=3
kcov-rflags-y += -Cllvm-args=-sanitizer-coverage-trace-pc
kcov-rflags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -Cllvm-args=-sanitizer-coverage-trace-compares
export CFLAGS_KCOV := $(kcov-flags-y)
+export CFLAGS_KCOV_DATAFLOW := $(kcov-dataflow-flags-y)
+export RUSTFLAGS_KCOV_DATAFLOW := -Cpasses=sancov-module -Cllvm-args=-sanitizer-coverage-level=3 -Cllvm-args=-sanitizer-coverage-dataflow-args -Cllvm-args=-sanitizer-coverage-dataflow-ret -Cdebuginfo=2
export RUSTFLAGS_KCOV := $(kcov-rflags-y)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 80e127c75a93..519bf651cdcf 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -88,6 +88,13 @@ _c_flags += $(if $(patsubst n%,, \
_rust_flags += $(if $(patsubst n%,, \
$(KCOV_INSTRUMENT_$(target-stem).o)$(KCOV_INSTRUMENT)$(if $(is-kernel-object),$(CONFIG_KCOV_INSTRUMENT_ALL))), \
$(RUSTFLAGS_KCOV))
+# KCOV dataflow: per-file opt-in or global via CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL
+_c_flags += $(if $(patsubst n%,, \
+ $(KCOV_DATAFLOW_$(target-stem).o)$(KCOV_DATAFLOW)$(if $(is-kernel-object),$(CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL))), \
+ $(CFLAGS_KCOV_DATAFLOW))
+_rust_flags += $(if $(patsubst n%,, \
+ $(KCOV_DATAFLOW_$(target-stem).o)$(KCOV_DATAFLOW)$(if $(is-kernel-object),$(CONFIG_KCOV_DATAFLOW_INSTRUMENT_ALL))), \
+ $(RUSTFLAGS_KCOV_DATAFLOW))
endif
#
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v2 1/6] kcov: add per-task dataflow tracking for function arguments/return values
From: Yunseong Kim @ 2026-06-03 17:43 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, Dmitry Vyukov,
Andrey Konovalov, Andrew Morton, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Nicolas Schier,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Jonathan Corbet, Shuah Khan
Cc: Yunseong Kim, linux-kernel, kasan-dev, llvm, linux-kbuild,
rust-for-linux, workflows, linux-doc, Yunseong Kim
In-Reply-To: <20260603-kcov-dataflow-next-20260603-v2-0-fee0939de2c4@est.tech>
Add a new KCOV subsystem that captures function arguments at entry and
return values at exit, with automatic struct field expansion using
compiler-generated DebugInfo metadata.
Key components:
- CONFIG_KCOV_DATAFLOW_ARGS: enables argument capture
- CONFIG_KCOV_DATAFLOW_RET: enables return value capture
- /sys/kernel/debug/kcov_dataflow: separate device from legacy kcov
- Ioctl namespace 'd' (KCOV_DF_INIT_TRACE, KCOV_DF_ENABLE, KCOV_DF_DISABLE)
- Per-task buffer: task->kcov_df_area with atomic xadd reservation
- Fault-tolerant: all reads via copy_from_kernel_nofault()
- Recursion-safe: notrace __no_sanitize_coverage noinline
- ERR_PTR aware: skips struct expansion for error pointers
The callbacks (__sanitizer_cov_trace_args/ret) are inserted by the
compiler when -fsanitize-coverage=dataflow-args,dataflow-ret is used.
The Kconfig options depend on cc-option to verify compiler support.
Buffer format (TLV records, all u64):
area[0]: atomic word count
[pos+0]: type_and_seq (0xE=entry, 0xF=return in upper 4 bits)
[pos+1]: PC
[pos+2]: meta (arg_idx | arg_size | ptr)
[pos+3..N]: field values read via copy_from_kernel_nofault()
This is completely independent from legacy /sys/kernel/debug/kcov.
Existing users (syzkaller, oss-fuzz) are unaffected.
Signed-off-by: Yunseong Kim <yunseong.kim@est.tech>
---
include/linux/sched.h | 8 ++
kernel/kcov.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++
lib/Kconfig.debug | 22 ++++
3 files changed, 321 insertions(+)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c4433c185ad8..03be4b495f70 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1533,6 +1533,14 @@ struct task_struct {
/* KCOV sequence number: */
int kcov_sequence;
+ /* KCOV dataflow per-task sequence counter for TLV records: */
+ u32 kcov_dataflow_seq;
+
+ /* KCOV dataflow: separate buffer for trace-args/trace-ret */
+ unsigned int kcov_df_size;
+ void *kcov_df_area;
+ bool kcov_df_enabled;
+
/* Collect coverage from softirq context: */
unsigned int kcov_softirq;
#endif
diff --git a/kernel/kcov.c b/kernel/kcov.c
index 1df373fb562b..d3c9c0efe961 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -353,6 +353,288 @@ void notrace __sanitizer_cov_trace_switch(kcov_u64 val, void *arg)
EXPORT_SYMBOL(__sanitizer_cov_trace_switch);
#endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */
+#if defined(CONFIG_KCOV_DATAFLOW_ARGS) || defined(CONFIG_KCOV_DATAFLOW_RET)
+/*
+ * KCOV Dataflow: /sys/kernel/debug/kcov_dataflow
+ *
+ * Completely separate from legacy /sys/kernel/debug/kcov.
+ * Own buffer, own ioctl, own mmap. No printk — buffer only.
+ *
+ * TLV record layout (all u64):
+ * area[0]: total u64 words written (atomic counter)
+ * [pos+0]: type_and_seq (0xE=entry|0xF=return in upper 4 bits, seq in lower 24)
+ * [pos+1]: PC
+ * [pos+2]: raw pointer | (arg_idx << 56) | (arg_size << 48) for entry
+ * [pos+3..N]: field values (or scalar value if num_fields=0)
+ */
+#define KCOV_DF_TYPE_ENTRY 0xE0000000ULL
+#define KCOV_DF_TYPE_RET 0xF0000000ULL
+#define KCOV_DF_MAGIC_BAD 0xBADADD85ULL
+#define KCOV_DF_IS_ERR(p) ((unsigned long)(p) >= (unsigned long)-4095UL)
+
+/* Ioctl commands for /sys/kernel/debug/kcov_dataflow */
+#define KCOV_DF_INIT_TRACE _IOR('d', 1, unsigned long)
+#define KCOV_DF_ENABLE _IO('d', 100)
+#define KCOV_DF_DISABLE _IO('d', 101)
+
+struct kcov_dataflow {
+ refcount_t refcount;
+ spinlock_t lock;
+ unsigned int size; /* in u64 words */
+ void *area;
+ struct task_struct *t;
+};
+
+static void kcov_df_put(struct kcov_dataflow *df)
+{
+ if (refcount_dec_and_test(&df->refcount)) {
+ vfree(df->area);
+ kfree(df);
+ }
+}
+
+/*
+ * Core write function — no printk, no locks, just atomic buffer write.
+ * Called from __sanitizer_cov_trace_args/ret in instrumented code.
+ */
+static noinline notrace __no_sanitize_coverage void
+kcov_df_write(u64 type_marker, u64 pc, u64 meta, void *ptr,
+ u64 *offsets, u32 num_fields)
+{
+ struct task_struct *t = current;
+ u64 *area;
+ unsigned long pos, max_pos;
+ u32 record_len, seq, i;
+
+ if (!t->kcov_df_enabled)
+ return;
+
+ area = (u64 *)t->kcov_df_area;
+ if (!area)
+ return;
+
+ max_pos = t->kcov_df_size;
+
+ /* Record: header(1) + pc(1) + meta(1) + fields or scalar(max 1) */
+ record_len = 3 + (num_fields > 0 ? num_fields : 1);
+
+ /* Atomic reservation */
+ pos = 1 + xadd((unsigned long *)&area[0], record_len);
+ if (unlikely(pos + record_len > max_pos)) {
+ xadd((unsigned long *)&area[0], -(long)record_len);
+ return;
+ }
+
+ seq = ++t->kcov_dataflow_seq;
+ area[pos] = type_marker | (seq & 0x00FFFFFFULL);
+ area[pos + 1] = pc;
+ area[pos + 2] = meta;
+
+ if (num_fields == 0) {
+ /* Scalar: read value from ptr using size from meta */
+ u64 val = 0;
+ u32 sz = (meta >> 48) & 0xFF;
+
+ if (sz > sizeof(val))
+ sz = sizeof(val);
+ if (ptr && !KCOV_DF_IS_ERR(ptr))
+ copy_from_kernel_nofault(&val, ptr, sz);
+ area[pos + 3] = val;
+ } else {
+ /* Struct fields */
+ if (KCOV_DF_IS_ERR(ptr)) {
+ for (i = 0; i < num_fields; i++)
+ area[pos + 3 + i] = KCOV_DF_MAGIC_BAD;
+ return;
+ }
+ for (i = 0; i < num_fields; i++) {
+ u64 off, sz, val = KCOV_DF_MAGIC_BAD;
+ void *fa;
+
+ if (copy_from_kernel_nofault(&off, &offsets[i * 2], sizeof(off)) ||
+ copy_from_kernel_nofault(&sz, &offsets[i * 2 + 1], sizeof(sz))) {
+ area[pos + 3 + i] = KCOV_DF_MAGIC_BAD;
+ continue;
+ }
+ fa = (void *)((unsigned long)ptr + off);
+ val = 0;
+ if (sz <= sizeof(val))
+ copy_from_kernel_nofault(&val, fa, sz);
+ else
+ copy_from_kernel_nofault(&val, fa, sizeof(val));
+ area[pos + 3 + i] = val;
+ }
+ }
+}
+
+#ifdef CONFIG_KCOV_DATAFLOW_ARGS
+noinline void notrace __no_sanitize_coverage
+__sanitizer_cov_trace_args(u64 pc, u32 arg_idx, u32 arg_size, void *arg_ptr,
+ u64 *offsets, u32 num_fields);
+
+noinline void notrace __no_sanitize_coverage
+__sanitizer_cov_trace_args(u64 pc, u32 arg_idx, u32 arg_size, void *arg_ptr,
+ u64 *offsets, u32 num_fields)
+{
+ /* meta: [arg_idx(8) | arg_size(8) | ptr(48)] */
+ u64 meta = ((u64)arg_idx << 56) | ((u64)arg_size << 48) |
+ ((u64)(unsigned long)arg_ptr & 0xFFFFFFFFFFFFULL);
+ kcov_df_write(KCOV_DF_TYPE_ENTRY, pc, meta, arg_ptr,
+ offsets, num_fields);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_args);
+#endif
+
+#ifdef CONFIG_KCOV_DATAFLOW_RET
+noinline void notrace __no_sanitize_coverage
+__sanitizer_cov_trace_ret(u64 pc, u32 ret_size, void *ret_val,
+ u64 *offsets, u32 num_fields);
+
+noinline void notrace __no_sanitize_coverage
+__sanitizer_cov_trace_ret(u64 pc, u32 ret_size, void *ret_val,
+ u64 *offsets, u32 num_fields)
+{
+ u64 meta = ((u64)ret_size << 48) |
+ ((u64)(unsigned long)ret_val & 0xFFFFFFFFFFFFULL);
+ kcov_df_write(KCOV_DF_TYPE_RET, pc, meta, ret_val,
+ offsets, num_fields);
+}
+EXPORT_SYMBOL(__sanitizer_cov_trace_ret);
+#endif
+
+/* --- /sys/kernel/debug/kcov_dataflow file operations --- */
+
+static int kcov_df_open(struct inode *inode, struct file *filep)
+{
+ struct kcov_dataflow *df;
+
+ df = kzalloc(sizeof(*df), GFP_KERNEL);
+ if (!df)
+ return -ENOMEM;
+ spin_lock_init(&df->lock);
+ refcount_set(&df->refcount, 1);
+ filep->private_data = df;
+ return nonseekable_open(inode, filep);
+}
+
+static int kcov_df_close(struct inode *inode, struct file *filep)
+{
+ struct kcov_dataflow *df = filep->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&df->lock, flags);
+ if (df->t == current) {
+ current->kcov_df_enabled = false;
+ current->kcov_df_area = NULL;
+ current->kcov_df_size = 0;
+ df->t = NULL;
+ }
+ spin_unlock_irqrestore(&df->lock, flags);
+ kcov_df_put(df);
+ return 0;
+}
+
+static int kcov_df_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ struct kcov_dataflow *df = filep->private_data;
+ unsigned long size, off;
+ struct page *page;
+ unsigned long flags;
+ void *area;
+ int res = 0;
+
+ spin_lock_irqsave(&df->lock, flags);
+ size = df->size * sizeof(u64);
+ if (!df->area || vma->vm_pgoff != 0 ||
+ vma->vm_end - vma->vm_start != size) {
+ res = -EINVAL;
+ goto out;
+ }
+ area = df->area;
+ spin_unlock_irqrestore(&df->lock, flags);
+
+ vm_flags_set(vma, VM_DONTEXPAND);
+ for (off = 0; off < size; off += PAGE_SIZE) {
+ page = vmalloc_to_page(area + off);
+ res = vm_insert_page(vma, vma->vm_start + off, page);
+ if (res)
+ return res;
+ }
+ return 0;
+out:
+ spin_unlock_irqrestore(&df->lock, flags);
+ return res;
+}
+
+static long kcov_df_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ struct kcov_dataflow *df = filep->private_data;
+ unsigned long flags;
+ unsigned long size;
+ int res = 0;
+
+ spin_lock_irqsave(&df->lock, flags);
+ switch (cmd) {
+ case KCOV_DF_INIT_TRACE:
+ if (df->area) {
+ res = -EBUSY;
+ break;
+ }
+ size = arg;
+ if (size < 2 || size > (128 << 20) / sizeof(u64)) {
+ res = -EINVAL;
+ break;
+ }
+ spin_unlock_irqrestore(&df->lock, flags);
+ df->area = vmalloc_user(size * sizeof(u64));
+ if (!df->area)
+ return -ENOMEM;
+ spin_lock_irqsave(&df->lock, flags);
+ df->size = size;
+ break;
+
+ case KCOV_DF_ENABLE:
+ if (!df->area || df->t) {
+ res = -EINVAL;
+ break;
+ }
+ df->t = current;
+ current->kcov_df_area = df->area;
+ current->kcov_df_size = df->size;
+ current->kcov_dataflow_seq = 0;
+ /* Barrier before enabling */
+ barrier();
+ current->kcov_df_enabled = true;
+ break;
+
+ case KCOV_DF_DISABLE:
+ if (df->t != current) {
+ res = -EINVAL;
+ break;
+ }
+ current->kcov_df_enabled = false;
+ barrier();
+ current->kcov_df_area = NULL;
+ current->kcov_df_size = 0;
+ df->t = NULL;
+ break;
+
+ default:
+ res = -ENOTTY;
+ }
+ spin_unlock_irqrestore(&df->lock, flags);
+ return res;
+}
+
+static const struct file_operations kcov_df_fops = {
+ .open = kcov_df_open,
+ .unlocked_ioctl = kcov_df_ioctl,
+ .compat_ioctl = kcov_df_ioctl,
+ .mmap = kcov_df_mmap,
+ .release = kcov_df_close,
+};
+#endif /* CONFIG_KCOV_DATAFLOW_ARGS || CONFIG_KCOV_DATAFLOW_RET */
+
static void kcov_start(struct task_struct *t, struct kcov *kcov,
unsigned int size, void *area, enum kcov_mode mode,
int sequence)
@@ -1146,6 +1428,15 @@ static int __init kcov_init(void)
*/
debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops);
+#if defined(CONFIG_KCOV_DATAFLOW_ARGS) || defined(CONFIG_KCOV_DATAFLOW_RET)
+ /*
+ * Toggle verbose printk: echo 1 > /sys/kernel/debug/kcov_dataflow_verbose
+ * Default off — zero overhead when not debugging.
+ */
+ debugfs_create_file_unsafe("kcov_dataflow", 0600, NULL, NULL,
+ &kcov_df_fops);
+#endif
+
#ifdef CONFIG_KCOV_SELFTEST
selftest();
#endif
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index e2f976c3301b..abd1a94589aa 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2261,6 +2261,28 @@ config KCOV_SELFTEST
On test failure, causes the kernel to panic. Recommended to be
enabled, ensuring critical functionality works as intended.
+
+config KCOV_DATAFLOW_ARGS
+ bool "Enable KCOV dataflow: function argument capture"
+ depends on KCOV
+ depends on $(cc-option,-fsanitize-coverage=dataflow-args)
+ help
+ Captures function arguments at entry via /sys/kernel/debug/kcov_dataflow.
+ Struct pointer arguments are auto-expanded using compiler DebugInfo
+ metadata, recording individual field values at runtime.
+ Enable per-module with: KCOV_DATAFLOW_file.o := y in the Makefile.
+ Requires clang with -fsanitize-coverage=dataflow-args support.
+
+config KCOV_DATAFLOW_RET
+ bool "Enable KCOV dataflow: return value capture"
+ depends on KCOV
+ depends on $(cc-option,-fsanitize-coverage=dataflow-ret)
+ help
+ Captures function return values via /sys/kernel/debug/kcov_dataflow.
+ Struct pointer returns are auto-expanded using compiler DebugInfo
+ metadata, recording individual field values at runtime.
+ Enable per-module with: KCOV_DATAFLOW_file.o := y in the Makefile.
+ Requires clang with -fsanitize-coverage=dataflow-ret support.
config DEBUG_AID_FOR_SYZBOT
bool "Additional debug code for syzbot"
default n
--
2.43.0
^ permalink raw reply related
* [RFC PATCH v2 0/6] kcov: per-task dataflow extraction at kernel function boundaries
From: Yunseong Kim @ 2026-06-03 17:43 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
Valentin Schneider, K Prateek Nayak, Dmitry Vyukov,
Andrey Konovalov, Andrew Morton, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Nicolas Schier,
Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Jonathan Corbet, Shuah Khan
Cc: Yunseong Kim, linux-kernel, kasan-dev, llvm, linux-kbuild,
rust-for-linux, workflows, linux-doc, Yunseong Kim
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 <yunseong.kim@est.tech>
---
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/20260603-kcov-dataflow-next-20260603-v1-0-e64300bf17cf@est.tech
To: Ingo Molnar <mingo@redhat.com>
To: Peter Zijlstra <peterz@infradead.org>
To: Juri Lelli <juri.lelli@redhat.com>
To: Vincent Guittot <vincent.guittot@linaro.org>
To: Dietmar Eggemann <dietmar.eggemann@arm.com>
To: Steven Rostedt <rostedt@goodmis.org>
To: Ben Segall <bsegall@google.com>
To: Mel Gorman <mgorman@suse.de>
To: Valentin Schneider <vschneid@redhat.com>
To: K Prateek Nayak <kprateek.nayak@amd.com>
To: Dmitry Vyukov <dvyukov@google.com>
To: Andrey Konovalov <andreyknvl@gmail.com>
To: Andrew Morton <akpm@linux-foundation.org>
To: Nathan Chancellor <nathan@kernel.org>
To: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
To: Bill Wendling <morbo@google.com>
To: Justin Stitt <justinstitt@google.com>
To: Nicolas Schier <nsc@kernel.org>
To: Miguel Ojeda <ojeda@kernel.org>
To: Boqun Feng <boqun@kernel.org>
To: Gary Guo <gary@garyguo.net>
To: Björn Roy Baron <bjorn3_gh@protonmail.com>
To: Benno Lossin <lossin@kernel.org>
To: Andreas Hindborg <a.hindborg@kernel.org>
To: Alice Ryhl <aliceryhl@google.com>
To: Trevor Gross <tmgross@umich.edu>
To: Danilo Krummrich <dakr@kernel.org>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <skhan@linuxfoundation.org>
Cc: linux-kernel@vger.kernel.org
Cc: kasan-dev@googlegroups.com
Cc: llvm@lists.linux.dev
Cc: linux-kbuild@vger.kernel.org
Cc: rust-for-linux@vger.kernel.org
Cc: workflows@vger.kernel.org
Cc: linux-doc@vger.kernel.org
---
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 <yunseong.kim@est.tech>
^ permalink raw reply
* [PATCH net-next] docs: exclude driver and netdevsim bugs
From: Jakub Kicinski @ 2026-06-03 16:29 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, pabeni, andrew+netdev, horms, johannes,
Jakub Kicinski, corbet, skhan, workflows, linux-doc
Initial wave of AI-generated fixes was mostly for core and protocols
we care about. But the number of irrelevant driver fixes is slowly
increasing. Add a section of explicit exclusions to our maintainer
profile.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
CC: corbet@lwn.net
CC: skhan@linuxfoundation.org
CC: workflows@vger.kernel.org
CC: linux-doc@vger.kernel.org
---
Documentation/process/maintainer-netdev.rst | 28 +++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst
index ec7b9aa2877f..cc4b5fa3b5c1 100644
--- a/Documentation/process/maintainer-netdev.rst
+++ b/Documentation/process/maintainer-netdev.rst
@@ -272,6 +272,34 @@ the case today. Please follow the standard stable rules in
:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`,
and make sure you include appropriate Fixes tags!
+Bug fixes
+~~~~~~~~~
+
+Unless explicitly excluded all bug fixes should be targeting the ``net``
+tree and contain an appropriate Fixes tag.
+
+Obvious exclusions:
+
+ - fixes for bugs which only exist in ``net-next`` should target ``net-next``
+ (please still include the Fixes tag in the commit message)
+ - bugs which cannot be reached, e.g. in code paths not executed given
+ current in-tree callers
+ - fixes for compiler warnings and typos
+
+Fixes for selftests and selftest-related infrastructure (most notably
+including the ``netdevsim`` driver) are only considered ``net``-worthy
+if they substantially reduce the flakiness of the test.
+
+Additionally, netdev does not consider bugs to be ``net``-worthy
+if they fulfill **all** of the following criteria:
+ - bug is in a hardware device driver;
+ - bug is either a missing error handling or is part of the error handling flow;
+ - bug was discovered by a static analysis / AI tool;
+ - bug was triggered/observed only with kernel changes or fault injection.
+Fixes for such bugs should default to ``net-next`` and should **not** contain
+a Fixes tag. Networking or driver maintainers may redirect such fixes to ``net``
+at their discretion if they consider the condition to be relevant enough.
+
Security fixes
~~~~~~~~~~~~~~
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] nios2: remove the architecture
From: Simon Schuster @ 2026-06-02 7:13 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Miguel Ojeda, Ethan Nelson-Moore, Wolfram Sang, Peter Zijlstra,
Arnd Bergmann, Dinh Nguyen, linux-doc, devicetree, workflows,
Linux-Arch, dmaengine, linux-i2c, linux-iio, Netdev, linux-pci,
linux-pwm, linux-hardening, linux-kbuild,
linux-csky@vger.kernel.org, Jonathan Corbet, Shuah Khan,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano,
Thomas Gleixner, Alex Shi, Yanteng Si, Dongliang Mu, Hu Haowen,
Kees Cook, Oleg Nesterov, Will Deacon, Aneesh Kumar K.V (Arm),
Andrew Morton, Nicholas Piggin, Vinod Koul, Frank Li,
Dave Penkler, Andi Shyti, Jonathan Cameron, David Lechner,
Nuno Sá, Andy Shevchenko, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Lorenzo Pieralisi,
Krzysztof WilczyDski, Andreas Oetken
In-Reply-To: <ah3TN93e7lRpVihW@ashevche-desk.local>
Hello Andy,
On Mon, Jun 01, 2026 at 09:45:11PM +0300, Andy Shevchenko wrote:
> Supported implies that one gets real money for the job. Is this the case here?
Thank you for caring about NIOSII. I'm doing so as part of my
employment at Siemens Energy; if this is real enough then yes :)
Best regards
Simon
^ permalink raw reply
* Re: [PATCH] nios2: remove the architecture
From: Andy Shevchenko @ 2026-06-02 8:00 UTC (permalink / raw)
To: Simon Schuster
Cc: Miguel Ojeda, Ethan Nelson-Moore, Wolfram Sang, Peter Zijlstra,
Arnd Bergmann, Dinh Nguyen, linux-doc, devicetree, workflows,
Linux-Arch, dmaengine, linux-i2c, linux-iio, Netdev, linux-pci,
linux-pwm, linux-hardening, linux-kbuild,
linux-csky@vger.kernel.org, Jonathan Corbet, Shuah Khan,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano,
Thomas Gleixner, Alex Shi, Yanteng Si, Dongliang Mu, Hu Haowen,
Kees Cook, Oleg Nesterov, Will Deacon, Aneesh Kumar K.V (Arm),
Andrew Morton, Nicholas Piggin, Vinod Koul, Frank Li,
Dave Penkler, Andi Shyti, Jonathan Cameron, David Lechner,
Nuno Sá, Andy Shevchenko, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Lorenzo Pieralisi,
Krzysztof WilczyDski, Andreas Oetken
In-Reply-To: <20260602071311.gtvif43wcjyulphh@dev-vm-schuster>
On Tue, Jun 02, 2026 at 09:13:11AM +0200, Simon Schuster wrote:
> On Mon, Jun 01, 2026 at 09:45:11PM +0300, Andy Shevchenko wrote:
> > Supported implies that one gets real money for the job. Is this the case here?
>
> Thank you for caring about NIOSII. I'm doing so as part of my
> employment at Siemens Energy; if this is real enough then yes :)
Then Supported is exactly what a record in the MAINTAINERS needs and it
facilitates the existence of the code in kernel for as long as this kept
true.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: Proposal: preflight checklist/lint for AI-assisted Linux kernel bug reports
From: Konstantin Ryabitsev @ 2026-06-01 20:13 UTC (permalink / raw)
To: mo to; +Cc: workflows, tools
In-Reply-To: <CAJLQH1vPmWd0gL2MqfsTPF74_cSKqb7H8LL8nwjK2gYv6mB55Q@mail.gmail.com>
On Fri, May 29, 2026 at 10:09:37PM +0900, mo to wrote:
> I understand that AI-assisted vulnerability and bug reports have
> recently become a burden for kernel maintainers, especially when
> reports are duplicated, unverified, or lack enough technical detail to
> be actionable.
>
> I would like to suggest a lightweight “preflight” process for
> AI-assisted bug reports.
>
> The goal is not to replace the existing Linux kernel email workflow,
> nor to move kernel development into a web-based ticket system.
> Instead, the idea is to add a simple validation layer before a report
> reaches maintainers.
This is generally along the lines of my suggestions here:
https://lore.kernel.org/ksummit/20260402-expert-maroon-partridge-f77f94@lemur/
(see under "new bug reporting")
I've done quite a bit of work on git-bug integration already, but I had to
step back to refocus on the infra again as we deal with upgrades, migrations,
and new kernel reboots. I hope to refocus on this work again soon.
> For AI-assisted reports, the submitter could be required to include a
> structured checklist such as:
I think if we *require* it, we'll never get any bug reports, because the
process of getting all of the below information is daunting even for someone
who deals with infrastructure all the time:
> - Kernel version:
> - Commit hash:
This is not easily established.
> - Architecture:
> - Kernel config:
They may not have access to it.
> - Affected subsystem / file / function:
That's often not obvious even for people who wrote the affected subsystem. ;)
> - Reproducer:
This may not be possible anyway, depending on the nature of the bug.
> - Reproduction rate:
This suggests a lot of effort spent on narrowing down the bug already.
> - Full dmesg / KASAN / UBSAN / lockdep / syzkaller log:
These are huge! Definitely not email attachment material -- we have to figure
out some place where we can store them, in a way that won't leak someone's
private info all over the place.
> - Checked latest mainline: yes/no
> - Checked stable trees: yes/no
It's pretty optimistic to think that the submitter will be willing to go that
far.
> - Checked lore.kernel.org for duplicates: yes/no
How would this even work? I'm in charge of lore.kernel.org and I'm not even
sure how I would check for bug duplicates without having to manually read
hundreds of entries.
> - Existing patch found: yes/no
> - Why this is considered a security issue:
> - Impact assessment:
> - Suggested fix or mitigation:
These usually happen late in the bug lifecycle and probably won't be relevant
at the start of the bug report process.
> - Human verification performed: yes/no
>
> Reports that do not include basic information such as a tested commit,
> reproducer, full logs, duplicate search summary, and existing-patch
> check could be automatically rejected or redirected before maintainers
> spend time on them.
That would be awesome, but that would basically mean "zarro boogs" every time
you check. :)
-K
^ permalink raw reply
* Re: [PATCH] Documentation: Fix syntax of kmalloc_objs example in coding style doc
From: Kees Cook @ 2026-06-01 20:08 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Jonathan Corbet, Manuel Ebner, Vlastimil Babka (SUSE),
SeongJae Park, Shuah Khan, workflows, linux-doc, linux-kernel
In-Reply-To: <20260529081006.2019687-2-ukleinek@kernel.org>
On Fri, May 29, 2026 at 10:10:05AM +0200, Uwe Kleine-König wrote:
> The first parameter should match the variable that the allocated memory
> is assigned to. Fix the example accordingly, the one for kmalloc_obj got
> it right already.
>
> Fixes: 7c6d969d5349 ("Documentation: adopt new coding style of type-aware kmalloc-family")
> Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
oops, thank you!
Reviewed-by: Kees Cook <kees@kernel.org>
--
Kees Cook
^ permalink raw reply
* Re: [PATCH v1] docs: kgdb: Fix stale source file paths
From: Jonathan Corbet @ 2026-06-01 19:04 UTC (permalink / raw)
To: Costa Shulyupin, Jason Wessel, Daniel Thompson, Douglas Anderson,
Shuah Khan, Randy Dunlap, kgdb-bugreport, workflows, linux-doc,
linux-kernel
Cc: Costa Shulyupin
In-Reply-To: <20260531140207.4114764-1-costa.shul@redhat.com>
Costa Shulyupin <costa.shul@redhat.com> writes:
> Update two file paths that became stale when kgdb/kdb sources
> were reorganized:
> - kernel/debugger/debug_core.c -> kernel/debug/debug_core.c
> - drivers/char/kdb_keyboard.c -> kernel/debug/kdb/kdb_keyboard.c
...which happened for 2.6.35 in 2009...
> Assisted-by: Claude:claude-opus-4-6
> Signed-off-by: Costa Shulyupin <costa.shul@redhat.com>
> ---
> Documentation/process/debugging/kgdb.rst | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
Applied, thanks.
jon
^ permalink raw reply
* Re: [PATCH] docs: changes.rst: restore pahole 1.26 minimum (regressed by sort)
From: Jonathan Corbet @ 2026-06-01 18:50 UTC (permalink / raw)
To: Zhan Xusheng; +Cc: Shuah Khan, workflows, linux-doc, linux-kernel, Zhan Xusheng
In-Reply-To: <20260526022033.1301884-1-zhanxusheng@xiaomi.com>
Zhan Xusheng <zhanxusheng1024@gmail.com> writes:
> Commit 9edd04c4189e ("docs: Raise minimum pahole version to 1.26 for
> KF_IMPLICIT_ARGS kfuncs") raised the minimum required pahole version
> from 1.22 to 1.26 in the requirements table and added a paragraph
> explaining the failure mode for distributions still shipping pahole
> v1.25 (e.g. Ubuntu 24.04 LTS).
>
> The next day, commit ece7e57afd51 ("docs: changes.rst and ver_linux:
> sort the lists") came through a different tree (docs vs sched_ext) and
> re-flowed the table alphabetically, but its base did not include
> 9edd04c4189e. When the two commits met in mainline, the textual rewrite
> of the table won and the version bump was lost. The added "Since Linux
> 7.0..." paragraph also disappeared.
>
> The result is that changes.rst on master (v7.1-rc5) lists pahole 1.22
> again, even though sched_ext kfuncs annotated with KF_IMPLICIT_ARGS
> genuinely require v1.26 to produce a correct vmlinux BTF. Users on
> distributions with pahole v1.25 hit "func_proto incompatible with
> vmlinux" when loading any sched_ext BPF program (scx_simple,
> scx_qmap, ...) and have no documentation pointing them at the version
> gap.
>
> Restore both changes from 9edd04c4189e.
>
> Fixes: ece7e57afd51 ("docs: changes.rst and ver_linux: sort the lists")
> Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
> ---
> Documentation/process/changes.rst | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
Oops, that is not good. Thanks for catching that; fix applied.
jon
^ permalink raw reply
* Re: [PATCH] Documentation: Fix syntax of kmalloc_objs example in coding style doc
From: Jonathan Corbet @ 2026-06-01 18:48 UTC (permalink / raw)
To: Uwe Kleine-König, Manuel Ebner, Vlastimil Babka (SUSE),
SeongJae Park
Cc: Shuah Khan, workflows, linux-doc, linux-kernel
In-Reply-To: <20260529081006.2019687-2-ukleinek@kernel.org>
Uwe Kleine-König <ukleinek@kernel.org> writes:
> The first parameter should match the variable that the allocated memory
> is assigned to. Fix the example accordingly, the one for kmalloc_obj got
> it right already.
>
> Fixes: 7c6d969d5349 ("Documentation: adopt new coding style of type-aware kmalloc-family")
> Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
> ---
> Documentation/process/coding-style.rst | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/process/coding-style.rst b/Documentation/process/coding-style.rst
> index a3bf75dc7c88..a8336582f60b 100644
> --- a/Documentation/process/coding-style.rst
> +++ b/Documentation/process/coding-style.rst
> @@ -959,13 +959,13 @@ The preferred form for allocating an array is the following:
>
> .. code-block:: c
>
> - p = kmalloc_objs(*ptr, n, ...);
> + p = kmalloc_objs(*p, n, ...);
>
> The preferred form for allocating a zeroed array is the following:
>
> .. code-block:: c
>
> - p = kzalloc_objs(*ptr, n, ...);
> + p = kzalloc_objs(*p, n, ...);
>
> Both forms check for overflow on the allocation size n * sizeof(...),
> and return NULL if that occurred.
Applied, thanks.
jon
^ permalink raw reply
* Re: [PATCH] nios2: remove the architecture
From: Andy Shevchenko @ 2026-06-01 18:45 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Simon Schuster, Ethan Nelson-Moore, Wolfram Sang, Peter Zijlstra,
Arnd Bergmann, Dinh Nguyen, linux-doc, devicetree, workflows,
Linux-Arch, dmaengine, linux-i2c, linux-iio, Netdev, linux-pci,
linux-pwm, linux-hardening, linux-kbuild,
linux-csky@vger.kernel.org, Jonathan Corbet, Shuah Khan,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Daniel Lezcano,
Thomas Gleixner, Alex Shi, Yanteng Si, Dongliang Mu, Hu Haowen,
Kees Cook, Oleg Nesterov, Will Deacon, Aneesh Kumar K.V (Arm),
Andrew Morton, Nicholas Piggin, Vinod Koul, Frank Li,
Dave Penkler, Andi Shyti, Jonathan Cameron, David Lechner,
Nuno Sá, Andy Shevchenko, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Lorenzo Pieralisi,
Krzysztof WilczyDski, Andreas Oetken
In-Reply-To: <CANiq72=6oYtHf0Q1NaLXZ+25uQyYbej2xnvUhtgpHyvozhP7_Q@mail.gmail.com>
On Tue, May 19, 2026 at 01:07:46PM +0200, Miguel Ojeda wrote:
> On Tue, May 19, 2026 at 12:41 PM Simon Schuster
> <schuster.simon@siemens-energy.com> wrote:
> >
> > Sure, I'd be glad to do so, but so far I refrained from it as I was a bit
> > unsure about the netiquette (can I simply do so by self-proclamation? At
> > least the git history seems to suggest so...).
>
> Up to the existing maintainer, in general.
>
> I would also suggest changing the support level to "Supported",
> instead of "Maintained" -- that would help justify keeping it in
> mainline.
Supported implies that one gets real money for the job. Is this the case here?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: Proposal: preflight checklist/lint for AI-assisted Linux kernel bug reports
From: Geert Uytterhoeven @ 2026-06-01 8:27 UTC (permalink / raw)
To: mo to; +Cc: workflows, tools
In-Reply-To: <CAJLQH1vPmWd0gL2MqfsTPF74_cSKqb7H8LL8nwjK2gYv6mB55Q@mail.gmail.com>
On Fri, 29 May 2026 at 15:09, mo to <pitar21@gmail.com> wrote:
> I understand that AI-assisted vulnerability and bug reports have
> recently become a burden for kernel maintainers, especially when
> reports are duplicated, unverified, or lack enough technical detail to
> be actionable.
>
> I would like to suggest a lightweight “preflight” process for
> AI-assisted bug reports.
>
> The goal is not to replace the existing Linux kernel email workflow,
> nor to move kernel development into a web-based ticket system.
> Instead, the idea is to add a simple validation layer before a report
> reaches maintainers.
>
> For AI-assisted reports, the submitter could be required to include a
> structured checklist such as:
>
> AI-assisted bug report checklist:
Which of the below are not suitable for a non-AI-assisted bug report?
> - Kernel version:
> - Commit hash:
> - Architecture:
> - Kernel config:
Do you always need the full .config?
> - Affected subsystem / file / function:
> - Reproducer:
> - Reproduction rate:
> - Full dmesg / KASAN / UBSAN / lockdep / syzkaller log:
Ouch.
Fortunately I didn't do that when reporting 'thousands of "sync_state()
pending due to" and hundreds of "deferred probe pending" messages'...
> - Checked latest mainline: yes/no
> - Checked stable trees: yes/no
> - Checked lore.kernel.org for duplicates: yes/no
Definitely! Also for mere humans.
(Hi nvram mutex fixes ;-)
> - Existing patch found: yes/no
> - Why this is considered a security issue:
> - Impact assessment:
> - Suggested fix or mitigation:
> - Human verification performed: yes/no
Perhaps only yes should be permitted?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox