| Age | Commit message (Collapse) | Author |
|
Convert all module name logging to use the mod_warn() and mod_error()
helpers, and pass the module to modpost_log() where used directly, to
always have the module name prefixed in the log message, with .ko suffix
for modules.
Pass struct module *mod around in a few places instead of just
mod->name.
Further unify the logging while at it. Use single quotes instead of
double quotes for symbols, sections, and namespaces. Explicitly state
it's a "symbol" when referencing symbols.
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Link: https://patch.msgid.link/17ed1bce5d54fb32533ba83bc83c429cb71adcb0.1786120005.git.jani.nikula@intel.com
Reviewed-by: Nicolas Schier <nsc@kernel.org>
Reviewed-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Nicolas Schier <nsc@kernel.org>
|
|
Kumar Kartikeya Dwivedi says:
====================
Redesign Verification Errors
TL;DR: This set reworks verifier error messages to include source and
instruction annotations, together with more causal context, making
failures easier to understand and more actionable when debugging and
repairing BPF programs.
Changelog:
----------
v4 -> v5
v4: https://lore.kernel.org/bpf/20260812233326.3575958-1-memxor@gmail.com
* Defer Verifier Limit reports and the dependent call-chain allocation
guards to follow-up work, reducing the series from 16 to 14 patches.
(Eduard)
* Make kfunc-name disassembly read-only before module-kfunc metadata is
resolved, retain instruction context without usable source metadata,
consolidate its fallback, and restrict source discovery to the containing
subprogram. (Eduard, Sashiko)
* Retain the newest diagnostic history in a bounded 64 MiB rotating buffer,
use absolute logical positions across verifier path switches, report
evicted shared history, and grow storage geometrically. (Eduard)
* Complete active-path history for BPF_LD_IMM64 and atomic fetches, call
clobbers and returns, outgoing stack arguments, legacy packet loads, and
RCU pointer transitions. (Eduard, Sashiko)
* Preserve causal lineage across equal snapshots, nullable pointer-cast
branches, and repeated same-depth function invocations using unique
diagnostic frame identities. Bound each rendered causal path to the oldest
and newest 32 matching events with an omission summary. (Eduard)
* Harden diagnostics for malformed release-kfunc signatures, fixed-size
argument ranges, and dynptr, iterator, memory-size, and required-RCU
failures by reporting the actual offending type or invariant. (Eduard,
Sashiko)
* Remove unrelated formatting and cross-patch churn, dead or single-use
helpers and filter paths, and align helper placement, includes, and commit
descriptions with the patches that first need them. (Eduard)
v3 -> v4
v3: https://lore.kernel.org/bpf/20260713153910.2556007-1-memxor@gmail.com
* Introduce helpers with their first callers and add printf annotations.
(Eduard, Sashiko)
* Remove "report" from diagnostic function names. (Sashiko)
* Reuse bpf_linfo_source and seq_buf, simplify internal names, and use shared
formatting storage. (Eduard)
* Use compact common event fields and record branches at successor entry.
(Eduard)
* Bound event storage at 1 MiB, use kvrealloc(), and drop events non-fatally.
(Eduard, Sashiko)
* Restore diagnostic history only for activated queued states, preserving the
active failure trace during cleanup. (Eduard, Sashiko)
* Record register changes through begin/end and scrub helpers, deriving targets
and origins without caller-saved snapshots. (Eduard)
* Store lineage marks on events and rewind shared formatting storage after
rendering each event. (Eduard)
* Record iterator return values before snapshotting alternate paths. (Sashiko)
* Use the current verifier instruction for global-subprogram dynptr errors.
(Sashiko)
* Use the supplied call name for nullable global-subprogram arguments.
(Sashiko)
* Describe global calls under locks as a verifier restriction rather than a
sleepability failure. (Sashiko)
* Keep diagnostic strings unsplit and put long call openings on their own
line. (Eduard)
* Keep kfunc metadata zeroed before early fetch and allowability failures.
(Sashiko)
* Drop the Verifier Internal Error report patch. (Eduard)
* Distinguish never-initialized registers from invalidated registers.
(local review)
* Preserve the legacy different-lock verifier message. (local review)
* Preserve nullable type qualifiers and stable mismatch formatting.
(local review)
* Mark truncated call chains with an ellipsis. (local review)
v2 -> v3
v2: https://lore.kernel.org/bpf/20260619205934.1312876-1-memxor@gmail.com
* Address various comments from Eduard and Sashiko.
* Move instruction context from a separate gutter into a new section
following source context, since surrounding source lines and BPF
instructions do not map one-to-one.
* Fix active-path branch reconstruction when switching to queued states,
and expand register histories to follow value lineage across spills,
fills, stack reads, helper/kfunc clobbers, and dynptr invalidation.
* Misc improvements and refinements.
v1 -> v2
v1: https://lore.kernel.org/bpf/20260605063412.974640-1-memxor@gmail.com
* Reworked diagnostic history from per-verifier-state log to active
path log with positions saved and reset when verifier search
backtracks. (Eduard)
* Moved reusable diagnostic formatting storage into struct bpf_diag
under struct bpf_verifier_env, and removed large per-report scratch
buffers from verifier stack frames. (Eduard)
* Added stack-slot events so diagnostics follow ordinary stack
spill/fill value flow and invalidations in register-scoped
histories. (Eduard)
* Reused existing source and BTF formatting helpers for diagnostics,
including bpf_get_linfo_file_line() and
btf_type_snprintf_show_name(). (Eduard)
* Fixed diagnostic edge cases around signed offset text,
BPF_MAX_VAR_OFF reporting, negative-offset clamping, poisoned
stack reads, and borrowed-reference invalidations. (Eduard)
* Fixed various miscellaneous diagnostic bugs. (Sashiko)
* Misc improvements and refinements.
---
Motivation
~~~~~~~~~~
The verifier log is the primary interface through which the verifier
communicates to the user its verdict on whether a program was accepted
or rejected.
To aid the debugging of rejection decisions, the verifier also reports
the symbolic state of the program at each instruction, across every explored
path of the BPF program. Such detailed information is critical to
introspect the correctness of verification decisions, and provide
insight into why a given program may have failed to load in the kernel.
A constant pain point in the BPF ecosystem throughout the years has
been the difficulty of debugging verification errors. The human-readable error
messages produced in response to a failure in satisfying safety-related
constraints are often terse, context-dependent, or insufficient for
understanding why a given error may have happened. Users must fall back
to the verbose instruction-by-instruction breakdown of how the symbolic
state evolved to surface the root cause. For programs with a huge log
volume due to high verification complexity, such logs quickly become
inscrutable.
All of this has made life difficult for users lacking an understanding
of how the verifier works, and the various heuristics and idiosyncrasies
used by it. In some cases, even seasoned BPF experts spend significant
time reverse engineering why a program may have failed, and have to
reach into the verifier's source code to form a complete picture of the
verification process.
Such a steep learning curve and cognitive burden also hurts the speed of
BPF development, as the verifier sits right in the middle of the user's
iteration loop while they make use of BPF to solve any given problem.
Expertise in debugging verifier errors does not scale in terms of teams
deploying these programs in production across a diverse set of kernels.
Overall, this leads to a poorer developer experience, causes visible
user dissatisfaction, and remains a drag on wider BPF adoption. With
some of the more recent developments where users increasingly leverage
AI tooling [0] to author their code, this bottleneck becomes even more
critical to address, since it throttles the much faster iteration loop
of AI agents.
[0]: https://lwn.net/Articles/1075067
Approach
~~~~~~~~
This series starts moving selected failures from terse terminal messages
toward diagnostics that carry the relevant context for a verification
failure. The existing verbose log remains the low-level trace. For selected
failures, the new report is emitted after this trace and answers the
immediate debugging questions:
- what verifier rule failed,
- why the current state does not satisfy it,
- where the failing instruction maps to source,
- which earlier branch or state event made this path fail,
- what kind of source change would satisfy the verifier.
The series adds a text-only diagnostics framework under kernel/bpf and
uses it to augment selected verifier errors. Existing verbose(env, ...)
messages are kept, so current selftest expectations and existing log
consumers continue to see the legacy text. The new report has a uniform
outer shape:
Verification failed: <category>: <problem>
Reason:
exact reason for the verification failure, with details
At:
source and instruction annotation
Causal path:
compressed branch and verifier-state events relevant for debugging
Suggestion:
speculation on potential fixes to repair the program
The outer shape is shared, but report construction is category-specific.
The categories are intentionally broad and reviewable. This revision
covers representative cases in Register Type Safety, Memory Safety,
Resource Lifetime Safety, Call Type Safety, Execution Context Safety,
Program Structure and Policy.
It does not attempt to convert every verbose(env, ...) site for now.
Additional verbose-only errors can be moved into the same framework
incrementally.
The following excerpts are copied from this current run on this branch:
./test_progs -j1 \
-a cpumask/test_populate_invalid_destination,\
cpumask/test_alloc_no_release,\
verifier_helper_value_access/via_variable_no_max_check_1,\
verifier_sock/invalidate_pkt_pointers_from_global_func \
-vv
They show the old terminal error and the exact new diagnostic report,
including the source and instruction annotations.
Call Type Safety, cpumask/test_populate_invalid_destination:
Legacy:
R1 type=scalar expected=fp
Diagnostic:
Verification failed: Call Type Safety: Invalid call argument
Reason:
The first argument (R1) to bpf_cpumask_populate does not satisfy the verifier contract: the kfunc
expects 24 bytes of memory for (struct bpf_cpumask), but it is an integer scalar and not
verifier-known memory.
At:
test_populate_invalid_destination @ cpumask_failure.c:234:8
Source context:
232 | ...
233 | ...
>>> 234 | ret = bpf_cpumask_populate(invalid, &bits, sizeof(bits));
| ^-- error: invalid first argument (R1) for bpf_cpumask_populate
235 | if (!ret)
236 | err = 2;
Instruction context:
2 | (b7) r1 = 1193046
3 | (b7) r3 = 8
>>> 4 | (85) call bpf_cpumask_populate#62860
5 | (56) if w0 != 0x0 goto pc+4
6 | (18) r1 = 0xffffc9000028e000
Causal path:
test_populate_invalid_destination @ cpumask_failure.c:234:8
Source context:
232 | ...
233 | ...
>>> 234 | ret = bpf_cpumask_populate(invalid, &bits, sizeof(bits));
| ^-- update: R1 changed from context pointer at offset 0 to integer scalar value
| 1193046
235 | if (!ret)
236 | err = 2;
Instruction context:
0 | (bf) r2 = r10
1 | (07) r2 += -8
>>> 2 | (b7) r1 = 1193046
3 | (b7) r3 = 8
4 | (85) call bpf_cpumask_populate#62860
Suggestion:
Pass stack, map, context, or other verifier-known memory of the expected type and size, not an
integer cast to a pointer.
Register Type Safety, verifier_sock/invalidate_pkt_pointers_from_global_func:
Legacy:
R7 invalid mem access 'scalar'
Diagnostic:
Verification failed: Register Type Safety: Invalid dereference
Reason:
R7 is an integer scalar here, not a pointer to memory.
At:
invalidate_pkt_pointers_from_global_func @ verifier_sock.c:1067:5
Source context:
1065 | ...
1066 | skb_pull_data1(sk, 0);
>>> 1067 | *p = 42; /* this is unsafe */
| ^-- error: invalid dereference of R7 (an integer scalar)
1068 | ...
1069 | }
Instruction context:
8 | (85) call pc+4
9 | (b4) w1 = 42
>>> 10 | (63) *(u32 *)(r7 +0) = r1
11 | (bc) w0 = w6
12 | (95) exit
Causal path:
invalidate_pkt_pointers_from_global_func @ verifier_sock.c:1062:29
Source context:
1060 | int invalidate_pkt_pointers_from_global_func(struct __sk_buff *sk)
1061 | ...
>>> 1062 | int *p = (void *)(long)sk->data;
| ^-- update: R7 changed from uninitialized value to pkt at offset 0
1063 | ...
1064 | if ((void *)(p + 1) > (void *)(long)sk->data_end)
Instruction context:
0 | (b4) w6 = 2
1 | (61) r2 = *(u32 *)(r1 +80)
>>> 2 | (61) r7 = *(u32 *)(r1 +76)
3 | (bf) r3 = r7
4 | (07) r3 += 4
invalidate_pkt_pointers_from_global_func @ verifier_sock.c:1064:22
Source context:
1062 | int *p = (void *)(long)sk->data;
1063 | ...
>>> 1064 | if ((void *)(p + 1) > (void *)(long)sk->data_end)
| ^-- branch: took the false branch of this conditional, goto not followed
1065 | ...
1066 | skb_pull_data1(sk, 0);
Instruction context:
3 | (bf) r3 = r7
4 | (07) r3 += 4
>>> 5 | (2d) if r3 > r2 goto pc+5
6 | (b4) w6 = 0
7 | (b4) w2 = 0
invalidate_pkt_pointers_from_global_func @ verifier_sock.c:1066:2
Source context:
1064 | if ((void *)(p + 1) > (void *)(long)sk->data_end)
1065 | ...
>>> 1066 | skb_pull_data1(sk, 0);
| ^-- invalidated: R7: packet data may have moved; previous value was pkt at
| offset 0
1067 | *p = 42; /* this is unsafe */
1068 | ...
Instruction context:
6 | (b4) w6 = 0
7 | (b4) w2 = 0
>>> 8 | (85) call pc+4
9 | (b4) w1 = 42
10 | (63) *(u32 *)(r7 +0) = r1
Suggestion:
Preserve a pointer-valued register where needed, or reload and revalidate the pointer after scalar
arithmetic, helper calls, or other operations that can invalidate it.
Memory Safety, verifier_helper_value_access/via_variable_no_max_check_1:
Legacy:
R1 unbounded memory access, make sure to bounds check any such access
Diagnostic:
Verification failed: Memory Safety: Access outside bounds
Reason:
The verifier cannot prove offset + access_size <= object_size. Here, the maximal bound for a
memory access is 4294967295 and exceeds maximum allowed offset of 536870912. R1 is map_value;
offset is variable: known bits 0x0, unknown mask 0xffffffff; signed range [0, 4294967295],
unsigned range [0, 4294967295]; access_size is 1; object_size is 48.
At:
via_variable_no_max_check_1 @ verifier_helper_value_access.c:627:2
Source context:
625 | ...
626 | ...
>>> 627 | asm volatile (" \
| ^-- error: access may be outside object bounds
628 | ...
629 | ...
Instruction context:
11 | (b7) r2 = 1
12 | (b7) r3 = 0
>>> 13 | (85) call bpf_probe_read_kernel#113
14 | (95) exit
Causal path:
via_variable_no_max_check_1 @ verifier_helper_value_access.c:627:2
Source context:
625 | ...
626 | ...
>>> 627 | asm volatile (" \
| ^-- update: R0 changed from uninitialized value to nullable map value from
| map_hash_48b at offset 0
628 | ...
629 | ...
Instruction context:
4 | (18) r1 = 0xffff88810a3ea000
>>> 6 | (85) call bpf_map_lookup_elem#1
7 | (15) if r0 == 0x0 goto pc+6
8 | (bf) r1 = r0
via_variable_no_max_check_1 @ verifier_helper_value_access.c:627:2
Source context:
625 | ...
626 | ...
>>> 627 | asm volatile (" \
| ^-- branch: took the false branch of this conditional, goto not followed
628 | ...
629 | ...
Instruction context:
6 | (85) call bpf_map_lookup_elem#1
>>> 7 | (15) if r0 == 0x0 goto pc+6
8 | (bf) r1 = r0
9 | (61) r3 = *(u32 *)(r0 +0)
via_variable_no_max_check_1 @ verifier_helper_value_access.c:627:2
Source context:
625 | ...
626 | ...
>>> 627 | asm volatile (" \
| ^-- update: R1 changed from uninitialized value to map value from map_hash_48b
| at offset 0
628 | ...
629 | ...
Instruction context:
6 | (85) call bpf_map_lookup_elem#1
7 | (15) if r0 == 0x0 goto pc+6
>>> 8 | (bf) r1 = r0
9 | (61) r3 = *(u32 *)(r0 +0)
10 | (0f) r1 += r3
via_variable_no_max_check_1 @ verifier_helper_value_access.c:627:2
Source context:
625 | ...
626 | ...
>>> 627 | asm volatile (" \
| ^-- update: R1 changed from map value from map_hash_48b at offset 0 to map value
| from map_hash_48b with variable offset: known bits 0x0, unknown mask
| 0xffffffff, signed range [0, 4294967295], unsigned range [0, 4294967295]
628 | ...
629 | ...
Instruction context:
8 | (bf) r1 = r0
9 | (61) r3 = *(u32 *)(r0 +0)
>>> 10 | (0f) r1 += r3
11 | (b7) r2 = 1
12 | (b7) r3 = 0
Suggestion:
Add or adjust a bounds check that proves offset + access_size stays within the object.
Resource Lifetime Safety, cpumask/test_alloc_no_release:
Legacy:
Unreleased reference id=2 alloc_insn=0
BPF_EXIT instruction in main prog would lead to reference leak
Diagnostic:
Verification failed: Resource Lifetime Safety: Unreleased resource
Reason:
Owned resource (id=2) was acquired at instruction 0 and still needs to be released before this
exit path.
At:
test_alloc_no_release @ cpumask_failure.c:36:5
Source context:
34 | ...
35 | ...
>>> 36 | int BPF_PROG(test_alloc_no_release, struct task_struct *task, u64 clone_flags)
| ^-- error: owned resource (id=2) still needs release
37 | ...
38 | ...
Instruction context:
19 | (7b) *(u64 *)(r10 -8) = r6
20 | (b4) w0 = 0
>>> 21 | (95) exit
Causal path:
test_alloc_no_release @ cpumask_common.h:78:12
Source context:
76 | ...
77 | ...
>>> 78 | cpumask = bpf_cpumask_create();
| ^-- acquired: owned resource (id=2)
79 | if (!cpumask) {
80 | err = 1;
Instruction context:
>>> 0 | (85) call bpf_cpumask_create#62851
1 | (bf) r6 = r0
2 | (55) if r6 != 0x0 goto pc+5
test_alloc_no_release @ cpumask_common.h:79:6
Source context:
77 | ...
78 | cpumask = bpf_cpumask_create();
>>> 79 | if (!cpumask) {
| ^-- branch: took the true branch of this conditional, goto followed
80 | err = 1;
81 | ...
Instruction context:
0 | (85) call bpf_cpumask_create#62851
1 | (bf) r6 = r0
>>> 2 | (55) if r6 != 0x0 goto pc+5
3 | (18) r1 = 0xffffc90000252000
test_alloc_no_release @ cpumask_common.h:84:6
Source context:
82 | ...
83 | ...
>>> 84 | if (!bpf_cpumask_empty(cast(cpumask))) {
| ^-- branch: took the true branch of this conditional, goto followed
85 | err = 2;
86 | bpf_cpumask_release(cpumask);
Instruction context:
9 | (85) call bpf_cpumask_empty#62852
10 | (54) w0 &= 1
>>> 11 | (56) if w0 != 0x0 goto pc+7
12 | (18) r1 = 0xffffc90000252000
Suggestion:
Release or transfer ownership of the acquired resource on every path before the program exits.
Patch layout:
- Patches 1-2 add the initial renderer, source-line lookup, and separate
source and instruction context blocks. Reusable report sections arrive with their first
category-specific consumers.
- Patches 3-7 add bounded, growable environment-owned diagnostic
history. It grows to 64 MiB and then retains the newest events in a
rotating buffer. The history follows the active verifier path and is
pruned when backtracking; it records branch outcomes, material register
changes, reference lifetime events, and execution-context events so
reports can explain the path and causal state transitions that led to
the failure.
- Patches 8-14 add the first category-specific reports. These patches
hook selected verifier failure sites and choose the evidence that is
useful for that error class.
Evaluation
~~~~~~~~~~
The evaluation below is retained from v4 while v5 changes are in progress.
It includes two Verifier Limit cases removed from v5 and must be refreshed
before posting.
To quantitatively assess diagnostic quality beyond subjective human
feedback, we use AI models (called over APIs) and veristat metrics to
compare results.
Models are used as a way to measure repair utility of the extra
diagnostics over a fixed test set. Each prompt contains only a sanitized
source snippet and either the legacy verifier log or the new diagnostic
log. To avoid leaking the answer through the test itself, comments,
annotations, and other source hints that describe the intended failure
were removed. The model is not given internet access, repository access,
test execution, verifier access, or the expected fix. The expected
causes and intended repairs are kept outside the prompt. Under those
constraints, correctness, exact repair rate, output size, reasoning
tokens, cost, and wall time provide a proxy for whether the additional
verifier context makes the failure easier to understand and turn into a
source-level fix.
Verifier cost is assessed by forcing the collection of diagnostics
information during normal verification. By default, this information is
collected and processed only when verbose logs are enabled, but forcing
it even without a verbose log helps us measure the CPU time and memory
cost of the extra data.
Both evaluations are covered in the sections below.
Repair Quality
--------------
Repair quality is measured by asking API-only models to propose source
fixes from a sanitized source snippet and verifier log. The criterion is
score >= 3 on a 0-4 local grading scale, where 3 means a likely fix with
incomplete detail and 4 means an actionable source-level fix. Score 4 is
reported separately as the exact repair rate. The reported model set
contains 596 completed API responses: 298 diagnostic and 298 legacy.
Main results (details available in Appendix):
Metric Diagnostic Legacy Delta
---------------------------------- ----------- ----------- --------
Answers 298 298
Success rate 97.0% 97.3% -0.3 pp
Exact repair rate 82.2% 72.1% +10.1 pp
Mean score 3.79 3.69 +0.10
Solver cost $8.93 $10.37 -13.8%
Mean output tokens per answer 1662 1975 -15.8%
Mean reasoning tokens per answer 951 1080 -11.9%
Mean wall time per answer 37.3s 44.1s -15.4%
Diagnostic prompts carry more input context. The resulting answers are
still shorter and cheaper. In this run, diagnostics do not materially
change the coarse success rate, but they increase exact repairs by 10.1
percentage points while reducing cost, output tokens, reasoning tokens,
and wall time.
Verifier cost
-------------
Verifier cost is measured with veristat over the BPF selftest programs
selected by tools/testing/selftests/bpf/veristat.cfg, with five
repetitions per configuration. With diagnostics gated by log level, wall
time and verifier duration stay close to baseline. Forcing diagnostics
on for every verifier run adds modest overhead on this workload.
memory.peak is measured with cgroup v2 memory accounting for each
program load. The table reports the mean wall time, the mean summed
verifier duration, and the mean of the per-repetition maximum
memory.peak values.
Configuration Wall time mean Verifier duration memory.peak
---------------------------- -------------- ----------------- -----------
bpf-next baseline 25.78s 9.86s 142 MiB
diagnostics, gated 26.64s 10.16s 144 MiB
diagnostics, forced on 28.01s 11.00s 148 MiB
TODO
~~~~
Known follow-up work:
- Convert more verbose-only verifier errors into category-specific
reports.
- Integrate loop-convergence failure summarization from Eduard.
- Report candidate kfuncs/helpers for releasing owned resources.
- Explore association of source variables with verifier registers
where debug info permits it.
- Refine suggestions per category and, where useful, link diagnostics
to maintained documentation.
- Bring verifier warnings into the same reporting framework.
Appendix: AI repair details
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 20 verifier-failing selftest cases are:
Case Diff Category Selftest selector
------- ------ -------------------------- ---------------------------------------------
case-001 easy Call Type Safety cpumask/test_populate_invalid_destination
case-002 easy Resource Lifetime Safety cpumask/test_alloc_no_release
case-003 easy Register Type Safety verifier_spill_fill/check_corrupted_spill_fill
case-004 easy Register Type Safety test_global_funcs/global_func12
case-005 easy Execution Context Safety preempt_lock/preempt_sleepable_helper
case-006 easy Policy verifier_helper_restricted/in_bpf_prog_type_kprobe_1
case-007 medium Memory Safety dynptr/dynptr_slice_var_len1
case-008 medium Call Type Safety dynptr/test_dynptr_skb_small_buff
case-009 medium Call Type Safety task_kfunc/task_kfunc_acquire_untrusted
case-010 medium Register Type Safety test_global_funcs/global_func6
case-011 medium Resource Lifetime Safety dynptr/ringbuf_missing_release2
case-012 medium Execution Context Safety irq/irq_sleepable_helper_global_subprog
case-013 medium Verifier Limit test_global_funcs/global_func1
case-014 hard Memory Safety verifier_helper_value_access/via_variable_no_max_check_1
case-015 hard Register Type Safety verifier_sock/invalidate_pkt_pointers_from_global_func
case-016 hard Resource Lifetime Safety verifier_ref_tracking/check_free_in_one_subbranch
case-017 hard Resource Lifetime Safety irq/irq_restore_ooo
case-018 hard Resource Lifetime Safety res_spin_lock_failure/res_spin_lock_ooo_unlock
case-019 hard Program Structure verifier_loops1/bounded_recursion
case-020 hard Verifier Limit verifier_liveness_exp/liveness_exponential_complexity
The grading scale is:
- 4: identifies the verifier cause and gives an actionable source-level fix.
- 3: gives a likely fix, but with incomplete explanation or detail.
- 2: identifies part of the issue, but not enough to fix confidently.
- 1: gives only a broad verifier-area answer, or a wrong/insufficient fix.
- 0: does not identify the intended verifier failure.
Detailed effort metrics for the model set:
Metric Variant Mean Median P99
----------------------- ---------- -------- -------- --------
Cost per answer diagnostic $0.030 $0.019 $0.203
Cost per answer legacy $0.035 $0.018 $0.223
Input tokens diagnostic 1391 1220 4048
Input tokens legacy 1052 805 3655
Output tokens diagnostic 1662 954 8680
Output tokens legacy 1975 1034 9912
Reasoning tokens diagnostic 951 208 8108
Reasoning tokens legacy 1080 228 6322
Wall time diagnostic 37.3s 18.3s 222.7s
Wall time legacy 44.1s 19.8s 255.5s
Per-model results for diagnostic prompts:
Model profile Ans Succ Exact Mean Cost OutK ReasK Wall
----------------------------------------- --- ----- ----- ---- ------- ---- ----- -----
anthropic-haiku-4.5-default 20 90.0 80.0 3.70 $0.087 11.4 0.0 5.0s
anthropic-opus-4.8-high 20 100.0 90.0 3.90 $0.819 25.5 0.0 15.5s
anthropic-opus-4.8-medium 20 95.0 90.0 3.85 $0.870 27.5 0.0 12.7s
anthropic-sonnet-4.6-high 20 95.0 80.0 3.75 $0.824 48.9 0.0 21.6s
anthropic-sonnet-4.6-medium 20 100.0 65.0 3.65 $0.278 12.4 0.0 6.6s
openai-gpt-5.3-codex-high 20 100.0 80.0 3.80 $0.601 39.8 33.9 25.0s
openai-gpt-5.3-codex-medium 20 95.0 85.0 3.80 $0.287 17.5 11.4 13.5s
openai-gpt-5.5-high 20 100.0 90.0 3.90 $2.356 74.4 65.2 56.8s
openai-gpt-5.5-low 20 100.0 90.0 3.90 $0.686 18.7 8.5 21.3s
openai-gpt-5.5-medium 19 100.0 84.2 3.84 $1.353 41.1 31.8 37.4s
openai-gpt-5.5-none 20 95.0 90.0 3.85 $0.457 11.1 0.0 10.4s
openrouter-deepseek-r1-0528 20 100.0 75.0 3.75 $0.145 61.5 53.8 98.3s
openrouter-deepseek-v3.2 19 100.0 78.9 3.79 $0.028 64.2 58.1 87.3s
openrouter-glm-5.1-high 20 95.0 80.0 3.75 $0.113 28.8 20.7 19.3s
openrouter-qwen3-coder 20 90.0 75.0 3.65 $0.028 12.4 0.0 7.1s
Per-model results for legacy prompts:
Model profile Ans Succ Exact Mean Cost OutK ReasK Wall
----------------------------------------- --- ----- ----- ---- ------- ---- ----- -----
anthropic-haiku-4.5-default 20 90.0 45.0 3.35 $0.081 11.6 0.0 5.0s
anthropic-opus-4.8-high 20 90.0 70.0 3.60 $1.192 42.2 0.0 17.5s
anthropic-opus-4.8-medium 20 95.0 85.0 3.80 $1.001 34.5 0.0 13.4s
anthropic-sonnet-4.6-high 20 100.0 75.0 3.75 $1.181 74.1 0.0 24.4s
anthropic-sonnet-4.6-medium 20 95.0 65.0 3.60 $0.420 23.4 0.0 12.3s
openai-gpt-5.3-codex-high 20 100.0 85.0 3.85 $0.562 37.8 31.6 27.1s
openai-gpt-5.3-codex-medium 20 100.0 75.0 3.75 $0.318 20.3 13.7 13.6s
openai-gpt-5.5-high 19 100.0 78.9 3.79 $2.613 84.0 75.4 98.1s
openai-gpt-5.5-low 20 100.0 75.0 3.75 $0.664 19.0 9.7 21.7s
openai-gpt-5.5-medium 20 100.0 75.0 3.75 $1.602 50.2 41.0 56.1s
openai-gpt-5.5-none 20 95.0 85.0 3.80 $0.416 10.7 0.0 10.9s
openrouter-deepseek-r1-0528 20 95.0 70.0 3.65 $0.149 64.6 57.5 92.5s
openrouter-deepseek-v3.2 20 100.0 60.0 3.60 $0.030 74.3 67.8 98.3s
openrouter-glm-5.1-high 19 100.0 63.2 3.63 $0.115 32.1 24.9 30.4s
openrouter-qwen3-coder 20 100.0 75.0 3.75 $0.022 9.5 0.0 5.4s
====================
Link: https://patch.msgid.link/20260815064612.378577-1-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Augment selected helper and kfunc allowability failures with Policy reports.
These reports explain which requested operation is forbidden and why, without
adding path history for non-path-dependent policy checks.
Cover unprivileged bpf2bpf and kfunc use, helper program-type restrictions,
GPL-only helpers, helper-specific allow callbacks, kfunc allowability, and
destructive kfunc capability checks.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-15-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Augment selected whole-program and subprogram CFG validation failures with
Program Structure reports. These errors are structural rather than
path-dependent, so the reports focus on source and instruction context
instead of causal history.
Cover direct and indirect jumps outside the program or current subprogram,
unprivileged backedges, missing and out-of-range jump tables, targets in the
second half of an ldimm64, unreachable instructions, subprogram fallthrough,
and recursive bpf2bpf call graph edges.
Format long jump-range reasons directly in diagnostics.c, and keep the
fallthrough suggestion aligned with the verifier check by suggesting exit or
explicit jumps.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-14-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Augment selected sleepability and critical-section failures with Execution
Context Safety reports. Keep the existing verifier messages and add source
context, path history, and suggestions tied to the active context.
Use the context history recorded earlier to anchor causal paths to lock, IRQ,
RCU, and preempt regions instead of unrelated register updates.
Cover global calls while holding a lock, sleepable global function calls,
sleepable helpers, sleepable kfunc calls from disallowed contexts, operations
that exit while a context is still active, and unmatched context exits.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-13-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Augment selected helper and kfunc argument-contract failures with Call Type
Safety reports. Keep the existing terse verifier messages and add reason,
source context, causal register or stack-argument history, and targeted
suggestions.
Cover helper register-type mismatch, helper and kfunc non-NULL pointer
requirements, release-helper ownership requirements, scalar and constant kfunc
arguments, trusted and RCU pointer contracts, kfunc memory arguments,
memory/length pairs, refcounted kptrs, constant strings, and IRQ flag stack
arguments.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-12-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Augment selected Resource Lifetime Safety failures with structured diagnostics
while preserving the existing verifier messages.
Report unreleased references from check_reference_leak() using
reference-scoped diagnostic history, and add state reports for dynptr,
iterator, lock, and IRQ-flag lifetime misuse.
IRQ restore mismatch and out-of-order diagnostics use IRQ context-scoped
history when an IRQ-disabled region is active, so retained save/restore context
is still visible after per-state history removal.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-11-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Augment selected memory-range verifier failures with Memory Safety reports
while preserving the existing terse verifier messages for compatibility.
Cover stack spill corruption, uninitialized stack reads, variable stack helper
accesses, and check_mem_region_access() range-proof failures. The bounds report
spells out the required offset + access_size <= object_size proof with concrete
values and uses scoped diagnostic history for causal context.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-10-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Augment selected register-state verifier failures with Register Type Safety
reports. The existing verbose verifier messages remain in place; the new
reports add reason, source context, causal path, and suggestions.
Cover invalid pointer dereferences, unreadable registers, missing outgoing
stack arguments for bpf2bpf and kfunc calls, and rejected pointer arithmetic.
Use scoped diagnostic history so reports start from the latest relevant value
change and then show later branch outcomes.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-9-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Record verifier context transitions in the diagnostic history so later reports
can anchor causal paths to the critical section that made an operation invalid.
This covers lock, IRQ, RCU, and preempt regions without adding any new
verifier error reports. Category-specific commits decide where those recorded
events should be rendered.
Use context depth when selecting scoped history so nested regions anchor at the
outer active region, and fall back to the earliest retained event when the
matching entry was pruned.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-8-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Add reference acquire and release events to diagnostic history so Resource
Lifetime Safety reports can show the lifetime of a specific reference id along
the path.
Record acquisitions after the verifier assigns the reference id. Record
releases only after release_reference_nomark() succeeds, including the
kptr_xchg RCU conversion path and owning-to-non-owning conversion path that
consume an owning reference.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-7-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Record material register and outgoing stack argument changes so diagnostics can
explain how a value reached its current type, bounds, or unreadable state.
Store old and new register types, scalar ranges, tnum value and mask, map and
BTF type identity, and basic operand metadata in the environment-owned
diagnostic event stream.
Record invalidations when packet data moves, references are released, or
borrowed references leave their protected region. Register-scoped history
starts at the latest matching modification and then shows later branch
outcomes.
Also record fixed stack spills and overwrites, and tag register fills from
stack so register-scoped history can follow value flow through spilled stack
slots.
The type_is_map_ptr() helper previously lived as a static function in
kernel/bpf/log.c since commit 0c95c9fdb696 ("bpf: emit map name in register
state if applicable and available"). Move it verbatim to
include/linux/bpf_verifier.h as a static inline, next to the other type
classifiers, so diagnostics.c can reuse it without duplicating the case list.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-6-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Save the diagnostic event-log position with each verifier stack entry and
reset the environment-owned stream together with the normal verifier log
when a queued state is popped. Also reset the diagnostic stream after
successful subprogram verification even when level-2 logging preserves the
normal verifier log.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-5-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Add an environment-owned diagnostic history for verifier reports. Event
payloads keep the user-facing branch history shape, while storage lives
in bpf_verifier_env and follows the active verifier path.
Grow the event array geometrically up to a 64 MiB limit. Once storage
reaches the limit, or an allocation fails, overwrite the oldest event so
diagnostics retain the newest useful suffix without adding per-event
metadata.
Represent saved positions as absolute logical sequence numbers. A restore
truncates to a retained position. If its prefix has already been evicted,
clear the abandoned suffix and preserve the missing-history position. This
keeps marks stable across rotation without increasing their size.
Add the branch event renderer and branch recording.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-4-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Teach verifier diagnostics to annotate an instruction with BTF source
line information and nearby BPF instructions. The renderer keeps source
text in a fixed-width lane and prints instructions in a stable right-hand
gutter.
Wrap annotation text under the source line so long error labels remain
readable while the source and instruction lanes keep their fixed layout.
Keeping source and instruction context in one commit preserves the visual
layout contract that later diagnostic reports rely on.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-3-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
Add the initial diagnostics renderer for verifier reports and wire it into
the BPF build. The helper emits the common failure header through the
verifier log.
Later patches add prose wrapping, reusable report sections, and source and
instruction context for category-specific diagnostics.
Gate the helpers on normal verifier log output from the start, so
BPF_LOG_STATS-only loads do not collect or render diagnostics.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20260815064612.378577-2-memxor@gmail.com
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
|
|
In principle, the desired performance level can be set in MSR_HWP_REQUEST
to indicate to the processor what performance level the OS would like
the given CPU to run at, but if the Dynamic Efficiency Control (DEC)
feature is enabled in the processor, doing so may result in confusing
the processor firmware. It is then better to let the processor firmware
figure out the most suitable performance level by itself.
Accordingly, make intel_pstate always set the desired performance level
to zero (which means "no preference") when running on a platform with
DEC enabled.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Link: https://patch.msgid.link/4758098.LvFx2qVVIh@rafael.j.wysocki
|
|
After previous changes, intel_pstate_hybrid_hwp_adjust() does not do
much and its name and kerneldoc comment (which is not really necessary
because the function is static) have become a bit confusing. Moreover,
the initialization of P-states on systems with HWP enabled is divided
between it and a direct conditional statement branch in
intel_pstate_get_cpu_pstates() which is not super-easy to follow.
Address this by introducing intel_pstate_get_hwp_pstates() for the
entire HWP-specific initialization of P-states and moving the code from
intel_pstate_hybrid_hwp_adjust() into it along with some HWP-related
code from intel_pstate_get_cpu_pstates().
No intentional functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://patch.msgid.link/6021518.DvuYhMxLoT@rafael.j.wysocki
|
|
rate_limit_us is an unsigned int, while NSEC_PER_USEC is defined as
1000L. On 32-bit systems, the multiplication is therefore performed
using 32-bit unsigned arithmetic before the result is assigned to
freq_update_delay_ns.
For example, writing 4294968 to rate_limit_us wraps the delay from
4294968000 ns to 704 ns. This makes schedutil update far more often
than configured.
Add sugov_update_rate_limit_us() to widen rate_limit_us to s64 before
converting it to nanoseconds. Use the helper when updating the tunable
through sysfs and when starting the governor, so both paths perform the
conversion without overflow.
Fixes: 9bdcb44e391d ("cpufreq: schedutil: New governor based on scheduler utilization data")
Signed-off-by: Hui Su <sh_def@163.com>
Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Cc: All applicable <stable@vger.kernel.org>
Link: https://patch.msgid.link/20260806142304.1761454-1-sh_def@163.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC fixes from Arnd Bergmann:
"These are three last-minute fixes for the 7.2 release, though nothing
alarming:
- one error handling fix for optee firmware
- incorrect i2c data for the apple M3 that was added in 7.2
- a boot time warning fix for nvidia tegra"
* tag 'soc-fixes-7.2-3' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc:
arm64: tegra: Add EL2 virtual timer interrupt for Tegra194
arm64: dts: apple: t8122: Fix I2C resources
optee: ffa: Add NULL check in optee_ffa_lend_protmem
|
|
Pull OpenRISC fix from Stafford Horne:
"A bug fix found by researchers:
- mask all privileged bits when restoring the supervisor register
from sigreturn"
* tag 'for-linus' of https://github.com/openrisc/linux:
openrisc: signal: do not restore privileged SR bits on sigreturn
|
|
The sample parsing test only validates grouped read values when
PERF_FORMAT_LOST is present.
For PERF_FORMAT_GROUP without PERF_FORMAT_LOST, the contents of
read.group.values[] are not validated, allowing corruption of the parsed
value and id fields to go undetected.
The values are also handed to the synthesis as a plain array of struct
sample_read_value, which always has a 24-byte stride, while
read.group.values is expected to be packed according to read_format --
evsel__parse_sample() points it into the event data. Without
PERF_FORMAT_LOST the stride is 16, so both the synthesis and the
comparison walk overlapping bytes and the test passes regardless of the
contents.
Validate value and id for grouped reads and continue to validate lost
when PERF_FORMAT_LOST is present, walking the entries with
next_sample_read_value(). Also build the input packed using
sample_read_value_size() so the compared fields are the real ones.
Verified with a deliberate stride bug in copy_read_group_values(): the
test still passes without this change and fails at read_format 0xc with
it applied.
Signed-off-by: PVS Narasimha Rao <venkatasuryapala@gmail.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
dso__read_symbol() asserts that len <= jited_prog_len, where len comes
from sym->end - sym->start (parsed from PERF_RECORD_KSYMBOL in
perf.data). Both values originate from untrusted file input.
With NDEBUG (production builds), the assert is compiled out, allowing
an out-of-bounds heap read when the BPF program buffer is accessed.
Without NDEBUG, a crafted perf.data crashes perf with an assertion
failure.
Replace the assert with a runtime bounds check that returns NULL with
an appropriate error code, matching the existing error handling
pattern in this function.
Fixes: aa04707f507e ("perf dso: Support BPF programs in dso__read_symbol()")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Song Liu <song@kernel.org>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
dso_cache__memcpy() computes cache_offset = offset - cache->offset,
then cache_size = min(cache->size - cache_offset, size). The RB tree
lookup in __dso_cache__find() matches using the full
DSO__DATA_CACHE_SIZE window, but cache->size reflects the actual pread
return value from dso_cache__populate().
A short pread (e.g. near end-of-file) makes cache->size smaller than
DSO__DATA_CACHE_SIZE. If a subsequent access targets an offset past
cache->offset + cache->size but within the DSO__DATA_CACHE_SIZE
window, the cache entry is found but cache_offset exceeds cache->size.
Since both are u64, the subtraction cache->size - cache_offset wraps
to a large value, min() selects the caller's size, and memcpy reads
out of bounds.
Return 0 for an offset past the valid cached data. For a regular
file a short pread only happens at end-of-file, so 0 is what a direct
pread() at that offset would return: cached_io() stops its read loop
as on EOF. Re-reading from the backing file would not help — a
second pread at the same offset returns the same short count.
Fixes: 366df72657e0 ("perf dso: Refactor dso_cache__read()")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
file_size()
file_read() and file_size() use ret = -errno when
dso__data(dso)->fd is negative after try_to_open_dso() fails. By this
point errno has been through mutex_lock(), nsinfo__mountns_enter(), and
multiple open() attempts inside try_to_open_dso() — it no longer
reflects the actual open failure. If errno happens to be 0, ret = 0
looks like EOF rather than an error, and file_size() callers like
dso__data_size() would then report a zero-sized file instead of
failing.
dso__data(dso)->fd is always negative on failure — -errno from
__open_dso() when no filename could be built (e.g. -EINVAL, -ENOENT),
or -1 when do_open() itself failed — and never 0, so use it directly
instead of reading the stale global errno.
No assert() or comment is needed after the assignment: the enclosing
if (dso__data(dso)->fd < 0) already guarantees ret < 0
[Namhyung Kim review].
Fixes: 33bdedcea2d7 ("perf tools: Protect dso cache fd with a mutex")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
dso__decompress_kmodule_path() unconditionally calls close(fd) on the
return value of decompress_kmodule(). When decompression fails or the
DSO is not compressed, decompress_kmodule() returns -1. close(-1)
fails with EBADF and clobbers errno, which callers up the chain
(dso__get_filename → __open_dso) depend on for error propagation.
Guard the close() call with fd >= 0 so only valid file descriptors are
closed.
Fixes: 42b3fa670825 ("perf tools: Introduce dso__decompress_kmodule_{fd,path}")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
__open_dso() computes fd = -errno when dso__get_filename() returns NULL.
Some failure paths in dso__get_filename() (e.g. binary type mismatch)
return NULL without making a syscall, leaving errno at 0 from a prior
successful call. fd = -0 = 0, which is stdin — subsequent code treats
it as a valid file descriptor.
Fall back to ENOENT when errno is 0, ensuring fd is always negative on
failure.
The forced ENOENT stays in errno for the callers that check it after a
negative fd. It must not misdirect the try_to_open_dso() fallback
loop, though: dso__get_filename()'s chroot fallback used to accept a
stale ENOENT even when stat() succeeded on a non-regular file (e.g. a
directory). Re-stat() there and only take the chroot path when
stat() actually failed with ENOENT [sashiko-bot review of PATCH 1/5].
Fixes: eba5102d2f0b ("perf tools: Add global list of opened dso objects")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
sched_class->balance() is gone from sched_ext and what balance_one() does is
run dispatch to produce something pickable. Update the balance-era names to
dispatch terms:
- balance_one() -> dispatch_one()
- SCX_RQ_IN_BALANCE -> SCX_RQ_IN_DISPATCH
No BPF scheduler reads the flag. The enum autogen headers gain the new name
with the old entry retained like other removed enumerators, zero-filling at
load time. No functional changes.
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
The fixup demoting a keep verdict when @prev is not on ext_sched_class
guarded against the rq-level SCX_RQ_BAL_KEEP flag going stale back when
balancing and picking were separate operations.
The verdict now travels in the return value, created and consumed in one
invocation against the @prev it evaluated, and every keep decision tests
SCX_TASK_QUEUED under the rq lock, which implies ext_sched_class as a class
switch dequeues first. Drop the fixup along with dispatch_core_pick()'s
copy.
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
kick_sync_wait_bal_cb() assumes it runs on the rq's CPU from the
__schedule() tail: the snapshots it compares against live in that CPU's
percpu area and the busy-wait runs with the rq lock dropped and IRQs
enabled.
However, dispatch can now drop the rq lock while the callback sits queued,
and rq lock takers in that window (the sched class change paths, the scx
task iterator) flush pending balance callbacks on release, running the
callback on a foreign CPU. Such a run compares against unrelated snapshots
and can deadlock when the executing CPU is itself a wait target.
Bail on a foreign CPU and leave the wait state alone. The wait only observes
progress that the resched kicks already guarantee and the rq's next wait
picks up the stale cpus_to_sync bits.
Fixes: 4c95380701f5 ("sched/ext: Fold balance_scx() into pick_task_scx()")
Cc: stable@vger.kernel.org # v6.19+
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
kernel/sched/ext/arena.c uses the gen_pool allocator, which is built only
when GENERIC_ALLOCATOR is set. SCHED_CLASS_EXT doesn't select it, so on
configs where nothing else does, the build fails to link:
build_policy.o: undefined reference to `gen_pool_create'
build_policy.o: undefined reference to `gen_pool_for_each_chunk'
build_policy.o: undefined reference to `gen_pool_destroy'
Fixes: 9eca087deb0b ("sched_ext: Sub-allocator over kernel-claimed BPF arena pages")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202608151315.tvN3X0Oq-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202608151632.3p91bTQj-lkp@intel.com/
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
fcg_dispatch() true-ups the current cgroup's cvtime when its slice
expires or its DSQ runs empty while the slice is still active:
__sync_fetch_and_add(&cgc->cvtime_delta,
(cpuc->cur_at + cgrp_slice_ns - now) *
FCG_HWEIGHT_ONE / (cgc->hweight ?: 1));
The true-up should be actual minus charged: on CNS_EXPIRE, the overrun
(now - cur_at - cgrp_slice_ns) should be added; on CNS_EMPTY, the
unused portion of the slice should be subtracted. The expression above
has the sign inverted, and in the CNS_EXPIRE case now is already past
cur_at + cgrp_slice_ns, so the u64 subtraction wraps. The
multiplication preserves the two's complement encoding but the
unsigned division by hweight destroys it, adding roughly 2^64/hweight
per expiry instead of a small correction.
Under saturation the hweight budget clamp in cgrp_cap_budget() masks
most of the garbage, so the weight distribution barely moves, but the
accounting is broken all the same. Compute the delta as a signed value
and use fetch_and_add()/fetch_and_sub() so that the dividends stay
positive, as BPF division is unsigned.
Instrumented the true-up and ran a saturated three-leaf cgroup tree on
a 4-CPU VM: without the fix, each expiry added ~5e15 (2^64/hweight
territory) to cvtime_delta; with it, the corrections are back to
slice scale, with the overrun added and the unused portion subtracted.
Fixes: a4103eacc2ab ("sched_ext: Add a cgroup scheduler which uses flattened hierarchy")
Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
scx_bpf_dsq_reenq() queues a deferred reenq (dru) that runs from
run_deferred(), not ops.dispatch(). If the DSQ is destroyed before the dru
runs, process_deferred_reenq_users() sees dsq->id == SCX_DSQ_INVALID and
hits the BUG_ON. destroy_dsq() doesn't flush pending drus, so just skip.
tj: Read dsq->id once with READ_ONCE(). Reading it separately in the INVALID
check and the BUG_ON would leave a window where destroy_dsq() can
invalidate the id between the two reads and still trigger the BUG_ON.
Fixes: 84b1a0ea0b7c ("sched_ext: Implement scx_bpf_dsq_reenq() for user DSQs")
Cc: stable@vger.kernel.org # v7.1+
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
libbpf strips the last ___flavor suffix when resolving kfunc externs, so
the bare ___v2 declaration resolves to scx_bpf_dsq_move_to_local, whose
BTF proto lacks @enq_flags. The extern never matches, bpf_ksym_exists()
returns false on every kernel that has the ___v2 kfunc, and the macro
falls back to ___v1, silently dropping @enq_flags.
Add the trailing ___compat suffix used by the other versioned externs in
this file (scx_bpf_dsq_insert___v2, scx_bpf_reenqueue_local___v2).
Any caller passing non-zero @enq_flags through the compat macro silently
loses them.
Fixes: 860683763ebf ("sched_ext: Add enq_flags to scx_bpf_dsq_move_to_local()")
Cc: stable@vger.kernel.org # v7.1+
Assisted-by: Z.ai:glm-5.2
Signed-off-by: fangqiurong <fangqiurong@kylinos.cn>
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
scx_bpf_events() always reads the root scheduler's event counters, so a
sub-scheduler program querying its own events silently gets the root's
instead and has no BPF-visible way to read its own (the per-scheduler sysfs
"events" file is the only interface). Resolve the scheduler from the calling
program with scx_prog_sched(). Unassociated programs follow the usual
scx_prog_sched() resolution: the root scheduler under a pre-sub-attach
compat root and zeroed counters otherwise.
Also fix up the malformed comment into proper kerneldoc.
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
scx_root_disable() invalidates each rq's clock before taking the rq lock.
scx_rq_clock_invalidate() is a plain read-modify-write of rq->scx.flags and
every other writer of the word runs under the rq lock, so the unlocked
update can race a concurrent flags update and lose one side's bits.
The invalidation doesn't matter in the first place. The cached clock is read
only by scx_bpf_now() from a loaded scheduler's BPF programs, nothing can
re-validate the clock while sched_ext is disabled as scx_rq_clock_update()
is gated on scx_enabled() too, and the usual rq lock cycles under the next
scheduler refresh or invalidate it before it's practically observable. Drop
the invalidation instead of fixing the locking.
v2: Description and comment updated - the invalidation is unnecessary rather
than subsumed by the rq lock cycle below.
Fixes: 3a9910b5904d ("sched_ext: Implement scx_bpf_now()")
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Changwoo Min <changwoo@igalia.com>
|
|
Fix missing pci_disable_device() in probe and remove.
Use pcim_enable_device(), pcim_request_region(), devm_ioremap(),
devm_ioremap_uc() and devm_ioremap_wc() for the PCI path. Convert
aux_start to devm_request_mem_region(). Guard atyfb_remove() to
only unmap/release for non-PCI (Atari) devices. Keep iounmap for
sprite.addr outside the guard since it uses raw ioremap().
Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
Signed-off-by: Helge Deller <deller@gmx.de>
|
|
Fix missing pci_disable_device() in probe and remove.
Use pcim_enable_device(), devm_request_mem_region(),
devm_ioremap() and devm_ioremap_wc() to replace manual resource
management. Remove all release_mem_region() and iounmap() calls.
Use devm_request_mem_region() instead of pcim_request_region()
because the requested sizes (16384 for MMIO, maxvram for FB) do
not match the full PCI BAR sizes.
Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
Signed-off-by: Helge Deller <deller@gmx.de>
|
|
Fix missing pci_disable_device() in probe and remove.
Use pcim_enable_device(), pcim_request_all_regions(),
devm_ioremap() and devm_ioremap_wc() to replace manual resource
management. Remove all pci_release_regions() and iounmap() calls.
Merge failed_init label into failed_enable.
Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
Signed-off-by: Helge Deller <deller@gmx.de>
|
|
Fix missing pci_disable_device() in probe and remove.
Use pcim_enable_device(), pcim_request_all_regions(),
devm_ioremap() and devm_ioremap_wc() to replace manual resource
management. Remove all pci_release_regions() and iounmap() calls.
Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
Signed-off-by: Helge Deller <deller@gmx.de>
|
|
Fix missing pci_disable_device() in probe and remove.
Use pcim_enable_device(), pcim_request_region(), devm_ioremap()
and devm_ioremap_wc() to replace manual resource management.
Remove all release_mem_region() and iounmap() calls.
Signed-off-by: Shixiong Ou <oushixiong@kylinos.cn>
Signed-off-by: Helge Deller <deller@gmx.de>
|
|
Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS to the default flag setting.
Gate the flag on the ABI version, but do not expose any userspace
control over this flag as it has no practical effect on the resulting
sandbox.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
Link: https://patch.msgid.link/20260809154544.1253100-6-utilityemal77@gmail.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|
|
Document setting no_new_privs with ruleset enforcement, following the
same compatibility section style as previous ABI additions.
Include a section explaining the tradeoffs of setting no_new_privs
through any means for privileged users of Landlock.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
Link: https://patch.msgid.link/20260809154544.1253100-5-utilityemal77@gmail.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|
|
Check that a successful landlock_restrict_self(2) call with
LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS sets no_new_privs without a prior
prctl(2) call nor CAP_SYS_ADMIN, that a failed call from both an
invalid ruleset and hitting the layer maximum leaves the attribute
unchanged, and that LANDLOCK_RESTRICT_SELF_TSYNC extends it to sibling
threads. Also check that this flag requires a ruleset.
Turn the multi_threaded_success test into a multi_threaded fixture with
success, no_new_privs, and no_new_privs_max_layers variants to factor
out the threading code.
Finally, rename restrict_self_fd_logging_flags to
restrict_self_fd_flags, and restrict_self_logging_flags to
restrict_self_flags to indicate that non-logging flags are now tested.
Test coverage for security/landlock is 91.8% of 2373 lines according to
LLVM 22.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
Link: https://patch.msgid.link/20260809154544.1253100-4-utilityemal77@gmail.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|
|
Add a landlock_restrict_self(2) flag to set the no_new_privs attribute
of the calling thread only after enforcement of the ruleset:
no_new_privs is set if and only if the call succeeds. This removes the
need for a prior prctl(2) PR_SET_NO_NEW_PRIVS call and guarantees that
a failed enforcement leaves the attribute unchanged.
Because no_new_privs is set by the call itself, the no_new_privs /
CAP_SYS_ADMIN requirement of landlock_restrict_self(2) is fulfilled by
construction, and the related EPERM check is skipped.
Unlike LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF, this flag always
requires a valid ruleset: with a ruleset_fd of -1, such a call would be
nothing more than a Landlock-flavored prctl(2) PR_SET_NO_NEW_PRIVS, and
there is no valid use case for setting no_new_privs (possibly with
LANDLOCK_RESTRICT_SELF_TSYNC) without also enforcing Landlock
restrictions. Rejecting these calls also keeps the option of giving
them a meaning later.
The attribute is only set past the last point of failure, just before
committing the new credentials. When combined with
LANDLOCK_RESTRICT_SELF_TSYNC, no_new_privs is set on the sibling threads
as well, in their commit phase, with the same ordering.
Bump the Landlock ABI version to 11, and include the minimal related
test changes to keep the tests bisectable.
Cc: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
Link: https://patch.msgid.link/20260809212459.2427878-1-utilityemal77@gmail.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|
|
landlock_restrict_self(2) currently checks the no_new_privs /
CAP_SYS_ADMIN requirement before validating the flags argument. An
unprivileged caller without no_new_privs thus gets EPERM even when the
passed flags are invalid, hiding the EINVAL error.
Move the no_new_privs / CAP_SYS_ADMIN check just after the flags check
so that malformed calls consistently error out with EINVAL whatever the
caller's privileges, the same way seccomp(2) validates its flags before
checking no_new_privs.
Update the restrict_self_checks_ordering test accordingly.
Cc: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
Link: https://patch.msgid.link/20260809154544.1253100-2-utilityemal77@gmail.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|
|
The documentation embeds the canonical erratum documentation from the
header file, which is already a self-contained description of the issue.
Signed-off-by: Günther Noack <gnoack@google.com>
Link: https://patch.msgid.link/20260813093157.1436894-7-gnoack@google.com
[mic: Update the documentation date]
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|
|
Even though OverlayFS uses vfs_rename() with RENAME_WHITEOUT on its
backing directories, and even though RENAME_WHITEOUT requires
LANDLOCK_ACCESS_FS_MAKE_REG, a process that renames non-regular files in
an OverlayFS can do so without having the LANDLOCK_ACCESS_FS_MAKE_REG
right in that location.
This works, and is supposed to work, because the changes to the backing
directories are done by OverlayFS, not by the originator task that did
the original rename() on the OverlayFS mount. Therefore, the changes
done to backing directories are not subject to the originator task's
credentials.
Test coverage for security/landlock is 91.8% of 2368 lines according to
LLVM 22.
Signed-off-by: Günther Noack <gnoack@google.com>
Link: https://patch.msgid.link/20260813093157.1436894-6-gnoack@google.com
[mic: Add test coverage, reflow commit message]
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|
|
Add audit_layout1.make_whiteout: This test looks similar to
audit_layout1.make_char, but creates a whiteout object through mknod().
Since whiteout object creation is now guarded with
LANDLOCK_ACCESS_FS_MAKE_REG rather than LANDLOCK_ACCESS_FS_MAKE_CHAR, it
also needs to log the matching denial to audit.
Signed-off-by: Günther Noack <gnoack@google.com>
Link: https://patch.msgid.link/20260813093157.1436894-5-gnoack@google.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|
|
Add tests to check that whiteout object creation is guarded by
LANDLOCK_ACCESS_FS_MAKE_REG, in the cases where these are created from
userspace:
* Conventional creation with mknod()
* Linking or renaming an existing whiteout object
* renameat2() with RENAME_WHITEOUT,
which creates a new whiteout object in the source location
* renameat2() with RENAME_EXCHANGE,
with one of the renamed objects being a whiteout object
Signed-off-by: Günther Noack <gnoack@google.com>
Link: https://patch.msgid.link/20260813093157.1436894-4-gnoack@google.com
[mic: Update commit message as requested]
Signed-off-by: Mickaël Salaün <mic@digikod.net>
|