* [PATCH bpf v3 0/2] Fix stale register bounds on LSM retval context load
@ 2026-06-22 23:01 Tristan Madani
2026-06-22 23:01 ` [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access() Tristan Madani
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Tristan Madani @ 2026-06-22 23:01 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Eduard Zingerman, Xu Kuohai, Jiri Olsa, John Fastabend,
Martin KaFai Lau, bpf, stable, tristan
From: Tristan Madani <tristan@talencesecurity.com>
check_mem_access() calls __mark_reg_s32_range() to narrow a register to
the LSM hook retval range, but the intersection preserves stale bounds
from prior instructions. Add mark_reg_unknown() before narrowing (same
pattern as the else branch) and a selftest that catches the mismatch.
Changes in v3:
- Add selftest demonstrating the issue (Eduard Zingerman)
- No code change in patch 1 from v2
Tristan Madani (2):
bpf: Reset register bounds before narrowing retval range in
check_mem_access()
selftests/bpf: Add test for stale bounds on LSM retval context load
kernel/bpf/verifier.c | 1 +
tools/testing/selftests/bpf/progs/verifier_lsm.c | 15 +++++++++++++++
2 files changed, 16 insertions(+)
--
2.47.3
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access()
2026-06-22 23:01 [PATCH bpf v3 0/2] Fix stale register bounds on LSM retval context load Tristan Madani
@ 2026-06-22 23:01 ` Tristan Madani
2026-06-22 23:48 ` bot+bpf-ci
2026-06-23 0:07 ` Eduard Zingerman
2026-06-22 23:01 ` [PATCH bpf v3 2/2] selftests/bpf: Add test for stale bounds on LSM retval context load Tristan Madani
2026-06-23 0:30 ` [PATCH bpf v3 0/2] Fix stale register " patchwork-bot+netdevbpf
2 siblings, 2 replies; 7+ messages in thread
From: Tristan Madani @ 2026-06-22 23:01 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Eduard Zingerman, Xu Kuohai, Jiri Olsa, John Fastabend,
Martin KaFai Lau, bpf, stable, tristan
From: Tristan Madani <tristan@talencesecurity.com>
When the BPF verifier processes a context load of an LSM hook return
value, it calls __mark_reg_s32_range() to narrow the register to the
hook's valid range. However, __mark_reg_s32_range() intersects the new
range with the register's existing bounds using max_t()/min_t() rather
than replacing them.
If the destination register carries stale bounds from a prior instruction
(e.g. BPF_MOV64_IMM), the intersection can produce a range narrower than
reality. The verifier then believes it knows the register's exact value,
while at runtime the actual hook return value is loaded, creating a
verifier/runtime mismatch that can be used to bypass BPF memory safety
checks.
The else branch already calls mark_reg_unknown() to reset register state
before any narrowing. Apply the same reset in the is_retval path so
stale bounds are cleared before __mark_reg_s32_range() intersects.
Fixes: 5d99e198be27 ("bpf, lsm: Add check for BPF LSM return value")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
kernel/bpf/verifier.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a2b348f98080..21a365d436a5 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -6201,6 +6201,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
*/
if (info.reg_type == SCALAR_VALUE) {
if (info.is_retval && get_func_retval_range(env->prog, &range)) {
+ mark_reg_unknown(env, regs, value_regno);
err = __mark_reg_s32_range(env, regs, value_regno,
range.minval, range.maxval);
if (err)
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH bpf v3 2/2] selftests/bpf: Add test for stale bounds on LSM retval context load
2026-06-22 23:01 [PATCH bpf v3 0/2] Fix stale register bounds on LSM retval context load Tristan Madani
2026-06-22 23:01 ` [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access() Tristan Madani
@ 2026-06-22 23:01 ` Tristan Madani
2026-06-23 0:08 ` Eduard Zingerman
2026-06-23 0:30 ` [PATCH bpf v3 0/2] Fix stale register " patchwork-bot+netdevbpf
2 siblings, 1 reply; 7+ messages in thread
From: Tristan Madani @ 2026-06-22 23:01 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Cc: Eduard Zingerman, Xu Kuohai, Jiri Olsa, John Fastabend,
Martin KaFai Lau, bpf, stable, tristan
From: Tristan Madani <tristan@talencesecurity.com>
Add a verifier test that catches the stale-bounds issue fixed in the
previous patch. The test sets r6 = 0 to create known bounds, then loads
the LSM hook return value into r6 from the context. Without the fix,
the verifier intersects the retval range with the stale bounds and
incorrectly narrows r6 to a single value, pruning the fall-through
branch as dead code and missing the div-by-zero.
Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
tools/testing/selftests/bpf/progs/verifier_lsm.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/tools/testing/selftests/bpf/progs/verifier_lsm.c b/tools/testing/selftests/bpf/progs/verifier_lsm.c
index 2f8103bfa14e..c724bf389f5c 100644
--- a/tools/testing/selftests/bpf/progs/verifier_lsm.c
+++ b/tools/testing/selftests/bpf/progs/verifier_lsm.c
@@ -197,4 +197,19 @@ int BPF_PROG(sleepable_lsm_cgroup)
return 0;
}
+SEC("lsm/file_mprotect")
+__description("lsm retval load must reset stale register bounds")
+__failure __msg("div by zero")
+__naked int retval_load_resets_bounds(void *ctx)
+{
+ asm volatile (
+ "r6 = 0;"
+ "r6 = *(u64 *)(r1 + 24);"
+ "if r6 == 0 goto +1;"
+ "r6 /= 0;"
+ "r0 = 0;"
+ "exit;"
+ ::: __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access()
2026-06-22 23:01 ` [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access() Tristan Madani
@ 2026-06-22 23:48 ` bot+bpf-ci
2026-06-23 0:07 ` Eduard Zingerman
1 sibling, 0 replies; 7+ messages in thread
From: bot+bpf-ci @ 2026-06-22 23:48 UTC (permalink / raw)
To: tristmd, ast, daniel, andrii
Cc: eddyz87, xukuohai, jolsa, john.fastabend, martin.lau, bpf, stable,
tristan, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song,
clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 1458 bytes --]
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index a2b348f98080..21a365d436a5 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -6201,6 +6201,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
> */
> if (info.reg_type == SCALAR_VALUE) {
> if (info.is_retval && get_func_retval_range(env->prog, &range)) {
> + mark_reg_unknown(env, regs, value_regno);
> err = __mark_reg_s32_range(env, regs, value_regno,
> range.minval, range.maxval);
> if (err)
In the v2 review thread
(https://lore.kernel.org/bpf/4eae275e93d8eb165da8485a127a1fd0e7f91510.camel@gmail.com/),
Eduard Zingerman requested that a selftest be added to demonstrate the
stale bounds issue. While the v3 cover letter claims the selftest was
added as patch 2/2, the selftest is missing from the current commit
being reviewed.
The suggested test should verify that loading an LSM hook return value
into a register with stale bounds (e.g., from r6 = 0) properly resets
the bounds, preventing the verifier from incorrectly pruning branches
based on assumed constant values.
Could the selftest be added as described in the v2 review feedback?
---
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/27990633425
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access()
2026-06-22 23:01 ` [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access() Tristan Madani
2026-06-22 23:48 ` bot+bpf-ci
@ 2026-06-23 0:07 ` Eduard Zingerman
1 sibling, 0 replies; 7+ messages in thread
From: Eduard Zingerman @ 2026-06-23 0:07 UTC (permalink / raw)
To: Tristan Madani, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko
Cc: Xu Kuohai, Jiri Olsa, John Fastabend, Martin KaFai Lau, bpf,
stable, tristan
On Mon, 2026-06-22 at 23:01 +0000, Tristan Madani wrote:
> From: Tristan Madani <tristan@talencesecurity.com>
>
> When the BPF verifier processes a context load of an LSM hook return
> value, it calls __mark_reg_s32_range() to narrow the register to the
> hook's valid range. However, __mark_reg_s32_range() intersects the new
> range with the register's existing bounds using max_t()/min_t() rather
> than replacing them.
>
> If the destination register carries stale bounds from a prior instruction
> (e.g. BPF_MOV64_IMM), the intersection can produce a range narrower than
> reality. The verifier then believes it knows the register's exact value,
> while at runtime the actual hook return value is loaded, creating a
> verifier/runtime mismatch that can be used to bypass BPF memory safety
> checks.
>
> The else branch already calls mark_reg_unknown() to reset register state
> before any narrowing. Apply the same reset in the is_retval path so
> stale bounds are cleared before __mark_reg_s32_range() intersects.
>
> Fixes: 5d99e198be27 ("bpf, lsm: Add check for BPF LSM return value")
> Cc: stable@vger.kernel.org
> Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
[...]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf v3 2/2] selftests/bpf: Add test for stale bounds on LSM retval context load
2026-06-22 23:01 ` [PATCH bpf v3 2/2] selftests/bpf: Add test for stale bounds on LSM retval context load Tristan Madani
@ 2026-06-23 0:08 ` Eduard Zingerman
0 siblings, 0 replies; 7+ messages in thread
From: Eduard Zingerman @ 2026-06-23 0:08 UTC (permalink / raw)
To: Tristan Madani, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko
Cc: Xu Kuohai, Jiri Olsa, John Fastabend, Martin KaFai Lau, bpf,
stable, tristan
On Mon, 2026-06-22 at 23:01 +0000, Tristan Madani wrote:
> From: Tristan Madani <tristan@talencesecurity.com>
>
> Add a verifier test that catches the stale-bounds issue fixed in the
> previous patch. The test sets r6 = 0 to create known bounds, then loads
> the LSM hook return value into r6 from the context. Without the fix,
> the verifier intersects the retval range with the stale bounds and
> incorrectly narrows r6 to a single value, pruning the fall-through
> branch as dead code and missing the div-by-zero.
>
> Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
> Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
[...]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf v3 0/2] Fix stale register bounds on LSM retval context load
2026-06-22 23:01 [PATCH bpf v3 0/2] Fix stale register bounds on LSM retval context load Tristan Madani
2026-06-22 23:01 ` [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access() Tristan Madani
2026-06-22 23:01 ` [PATCH bpf v3 2/2] selftests/bpf: Add test for stale bounds on LSM retval context load Tristan Madani
@ 2026-06-23 0:30 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-06-23 0:30 UTC (permalink / raw)
To: Tristan Madani
Cc: ast, daniel, andrii, eddyz87, xukuohai, jolsa, john.fastabend,
martin.lau, bpf, stable, tristan
Hello:
This series was applied to bpf/bpf.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Mon, 22 Jun 2026 23:01:21 +0000 you wrote:
> From: Tristan Madani <tristan@talencesecurity.com>
>
> check_mem_access() calls __mark_reg_s32_range() to narrow a register to
> the LSM hook retval range, but the intersection preserves stale bounds
> from prior instructions. Add mark_reg_unknown() before narrowing (same
> pattern as the else branch) and a selftest that catches the mismatch.
>
> [...]
Here is the summary with links:
- [bpf,v3,1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access()
https://git.kernel.org/bpf/bpf/c/5e0b273e0a62
- [bpf,v3,2/2] selftests/bpf: Add test for stale bounds on LSM retval context load
https://git.kernel.org/bpf/bpf/c/644332f48fc2
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-23 0:30 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22 23:01 [PATCH bpf v3 0/2] Fix stale register bounds on LSM retval context load Tristan Madani
2026-06-22 23:01 ` [PATCH bpf v3 1/2] bpf: Reset register bounds before narrowing retval range in check_mem_access() Tristan Madani
2026-06-22 23:48 ` bot+bpf-ci
2026-06-23 0:07 ` Eduard Zingerman
2026-06-22 23:01 ` [PATCH bpf v3 2/2] selftests/bpf: Add test for stale bounds on LSM retval context load Tristan Madani
2026-06-23 0:08 ` Eduard Zingerman
2026-06-23 0:30 ` [PATCH bpf v3 0/2] Fix stale register " patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox