> diff --git a/Documentation/admin-guide/tainted-kernels.rst
> b/Documentation/admin-guide/tainted-kernels.rst
> index 9ead927a37c0..630f24996e7b 100644
> --- a/Documentation/admin-guide/tainted-kernels.rst
> +++ b/Documentation/admin-guide/tainted-kernels.rst
> @@ -79,30 +79,31 @@ which bits are set::
> Table for decoding tainted state
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> -=== === ====== ========================================================
> -Bit Log Number Reason that got the kernel tainted
> -=== === ====== ========================================================
[ ... ]
> + 19 _/J 524288 userspace used a mutating debug operation in fwctl
> + 20 _/V 1048576 an unsafe eBPF program (mutating helper) was loaded
> +=== === ======= ========================================================
This isn't a bug, but the bottom border has 7 equals signs (=======) for
the Number column while the top and header borders have 6 (======). Will
this cause a Sphinx 'Malformed table' warning when rendering the
documentation?
Earlier in the same file, around line 77, there's a shell command example
for checking taint bits. With the addition of bit 20, shouldn't that
command be updated from 'seq 20' to 'seq 21' so it checks all 21 bits
(0-20)?
The current command only checks bits 0-19:
$ for i in $(seq 20); do echo $(($i-1)) $(($(cat
/proc/sys/kernel/tainted)>>($i-1)&1));done
Since 'seq 20' produces 1..20, and the expression uses $(($i-1)), it only
computes bit positions 0..19, missing the newly added bit 20.
> @@ -189,3 +190,8 @@ More detailed explanation for tainting
> 19) ``J`` if userspace opened /dev/fwctl/* and performed a
> FWTCL_RPC_DEBUG_WRITE
> to use the devices debugging features. Device debugging features could
> cause the device to malfunction in undefined ways.
> +
> + 20) ``V`` if an eBPF program utilising unsafe, mutating helpers (such as
> + bpf_probe_write_user() or bpf_override_return()) was loaded. These
> helpers
> + bypass standard eBPF safety guarantees and can alter execution flow or
> + corrupt memory.
> diff --git a/include/linux/panic.h b/include/linux/panic.h
> index f1dd417e54b2..8622c02c2c24 100644
> --- a/include/linux/panic.h
> +++ b/include/linux/panic.h
> @@ -88,7 +88,8 @@ static inline void set_arch_panic_timeout(int timeout, int
> arch_default_timeout)
> #define TAINT_RANDSTRUCT 17
> #define TAINT_TEST 18
> #define TAINT_FWCTL 19
> -#define TAINT_FLAGS_COUNT 20
> +#define TAINT_UNSAFE_BPF 20
> +#define TAINT_FLAGS_COUNT 21
> #define TAINT_FLAGS_MAX ((1UL << TAINT_FLAGS_COUNT) - 1)
>
> struct taint_flag {
> diff --git a/kernel/panic.c b/kernel/panic.c
> index 20feada5319d..1ae19bd8fc1d 100644
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -825,6 +825,7 @@ const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
> TAINT_FLAG(RANDSTRUCT, 'T', ' '),
> TAINT_FLAG(TEST, 'N', ' '),
> TAINT_FLAG(FWCTL, 'J', ' '),
> + TAINT_FLAG(UNSAFE_BPF, 'V', ' '),
> };
>
> #undef TAINT_FLAG
There's a comment earlier in this file that explicitly states: "if you
modify the taint_flags or TAINT_FLAGS_COUNT, please also modify
tools/debugging/kernel-chktaint and
Documentation/admin-guide/tainted-kernels.rst".
While the Documentation was updated, was tools/debugging/kernel-chktaint
also updated? The script currently processes flags 0-19 and ends with the
J flag check. Without adding a section to check bit 20, the script won't
decode the 'V' character in the taint string output when
TAINT_UNSAFE_BPF is set.
The script would need something like:
T=`expr $T / 2`
if [ `expr $T % 2` -eq 0 ]; then
addout " "
else
addout "V"
echo " * an unsafe eBPF program (mutating helper) was loaded (#20)"
fi
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index a822c589c9bd..3f893d9ea764 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
> @@ -183,6 +183,7 @@ unsigned int trace_call_bpf_faultable(struct
> trace_event_call *call, void *ctx)
> #ifdef CONFIG_BPF_KPROBE_OVERRIDE
> BPF_CALL_2(bpf_override_return, struct pt_regs *, regs, unsigned long, rc)
> {
> + add_taint(TAINT_UNSAFE_BPF, LOCKDEP_STILL_OK);
> regs_set_return_value(regs, rc);
> override_function_with_return(regs);
> return 0;
Since bpf_override_return is a helper invoked at runtime and can execute
frequently on hot kprobes, will calling add_taint() here cause severe
cache line bouncing?
Looking at add_taint(), it unconditionally calls set_bit() on the global
tainted_mask.
Also, the commit message and documentation mention the system is tainted
when an unsafe eBPF program 'was loaded'. By applying the taint here
during execution instead of at program load time (e.g., in the verifier),
could this allow an unsafe BPF program to remain dormant and avoid
detection until a specific trigger occurs?
> @@ -372,6 +373,8 @@ BPF_CALL_3(bpf_probe_write_user, void __user *,
> unsafe_ptr, const void *, src,
> if (unlikely(!nmi_uaccess_okay()))
> return -EPERM;
>
> + add_taint(TAINT_UNSAFE_BPF, LOCKDEP_STILL_OK);
> +
> return copy_to_user_nofault(unsafe_ptr, src, size);
> }
Similarly here, will invoking add_taint() on every execution of
bpf_probe_write_user() cause significant performance degradation when
executed concurrently across multiple CPUs?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/25269516443