Skip to contentSkip to conversation

bpf: handle jset (if a & b ...) as a jump in CFG computation

PATCH Applied Eduard Zingerman 2 participants 3 messages Jun 13, 2025

Subsystems (4)
lore
Share & tools
lore

Eduard Zingerman

author maintainer
#0 lore raw

PATCH 1/2 bpf: handle jset (if a & b ...) as a jump in CFG computation

BPF_JSET is a conditional jump and currently verifier.c:can_jump() does not know about that. This can lead to incorrect live registers and SCC computation.

E.g. in the following example:

   1: r0 = 1;
   2: r2 = 2;
   3: if r1 & 0x7 goto +1;
   4: exit;
   5: r0 = r2;
   6: exit;

W/o this fix insn_successors(3) will return only (4), a jump to (5) would be missed and r2 won't be marked as alive at (3).

Fixes 14c8552db644 ("bpf: simple DFA-based live registers analysis")
Reported-by [email protected]
---
 kernel/bpf/verifier.c | 1 +
 1 file changed, 1 insertion(+)
kernel/bpf/verifier.c +1 -0
index c378074516cf..e76eb0322912 100644
@@ -23950,6 +23950,7 @@ static bool can_jump(struct bpf_insn *insn)
 	case BPF_JSLT:
 	case BPF_JSLE:
 	case BPF_JCOND:
+	case BPF_JSET:
 		return true;
 	}
 
Signature · 1 line
2.47.1
author maintainer
#1 lore raw

PATCH 2/2 selftests/bpf: verify jset handling in CFG computation

A test case to check if both branches of jset are explored when computing program CFG.

At 'if r1 & 0x7 ...':
- register 'r2' is computed alive only if jump branch of jset instruction is followed;
- register 'r0' is computed alive only if fallthrough branch of jset instruction is followed.

---
 .../selftests/bpf/progs/compute_live_registers.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
tools/testing/selftests/bpf/progs/compute_live_registers.c +16 -0
index f3d79aecbf93..6884ab99a421 100644
@@ -240,6 +240,22 @@ __naked void if2(void)
 		::: __clobber_all);
 }
 
+/* Verifier misses that r2 is alive if jset is not handled properly */
+SEC("socket")
+__log_level(2)
+__msg("2: 012....... (45) if r1 & 0x7 goto pc+1")
+__naked void if3_jset_bug(void)
+{
+	asm volatile (
+		"r0 = 1;"
+		"r2 = 2;"
+		"if r1 & 0x7 goto +1;"
+		"exit;"
+		"r0 = r2;"
+		"exit;"
+		::: __clobber_all);
+}
+
 SEC("socket")
 __log_level(2)
 __msg("0: .......... (b7) r1 = 0")
Signature · 1 line
2.47.1
#2 lore raw
In reply to Eduard Zingerman
This series was applied to bpf/bpf-next.git (master) by Alexei Starovoitov <[email protected]>:

Hello:

This series was applied to bpf/bpf-next.git (master) by Alexei Starovoitov <[email protected]>:

Quoted 6 lines · On Fri, 13 Jun 2025 10:53:30 -0700 you wrote:

BPF_JSET is a conditional jump and currently verifier.c:can_jump() does not know about that. This can lead to incorrect live registers and SCC computation.

E.g. in the following example:

Quoted 8 lines
   1: r0 = 1;
   2: r2 = 2;
   3: if r1 & 0x7 goto +1;
   4: exit;
   5: r0 = r2;
   6: exit;

[...]

Here is the summary with links:
- [bpf-next,v1,1/2] bpf: handle jset (if a & b ...) as a jump in CFG computation

    https://git.kernel.org/bpf/bpf-next/c/3157f7e29996
  - [bpf-next,v1,2/2] selftests/bpf: verify jset handling in CFG computation
    https://git.kernel.org/bpf/bpf-next/c/4a4b84ba9e45

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html