Skip to content

Commit 42d31dd

Browse files
anakryikoborkmann
authored andcommitted
bpf: Improve JEQ/JNE branch taken logic
When determining if an if/else branch will always or never be taken, use signed range knowledge in addition to currently used unsigned range knowledge. If either signed or unsigned range suggests that condition is always/never taken, return corresponding branch_taken verdict. Current use of unsigned range for this seems arbitrary and unnecessarily incomplete. It is possible for *signed* operations to be performed on register, which could "invalidate" unsigned range for that register. In such case branch_taken will be artificially useless, even if we can still tell that some constant is outside of register value range based on its signed bounds. veristat-based validation shows zero differences across selftests, Cilium, and Meta-internal BPF object files. Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Shung-Hsi Yu <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 06646da commit 42d31dd

File tree

1 file changed

+8
-0
lines changed

1 file changed

+8
-0
lines changed

kernel/bpf/verifier.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14031,12 +14031,16 @@ static int is_branch32_taken(struct bpf_reg_state *reg, u32 val, u8 opcode)
1403114031
return !!tnum_equals_const(subreg, val);
1403214032
else if (val < reg->u32_min_value || val > reg->u32_max_value)
1403314033
return 0;
14034+
else if (sval < reg->s32_min_value || sval > reg->s32_max_value)
14035+
return 0;
1403414036
break;
1403514037
case BPF_JNE:
1403614038
if (tnum_is_const(subreg))
1403714039
return !tnum_equals_const(subreg, val);
1403814040
else if (val < reg->u32_min_value || val > reg->u32_max_value)
1403914041
return 1;
14042+
else if (sval < reg->s32_min_value || sval > reg->s32_max_value)
14043+
return 1;
1404014044
break;
1404114045
case BPF_JSET:
1404214046
if ((~subreg.mask & subreg.value) & val)
@@ -14108,12 +14112,16 @@ static int is_branch64_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
1410814112
return !!tnum_equals_const(reg->var_off, val);
1410914113
else if (val < reg->umin_value || val > reg->umax_value)
1411014114
return 0;
14115+
else if (sval < reg->smin_value || sval > reg->smax_value)
14116+
return 0;
1411114117
break;
1411214118
case BPF_JNE:
1411314119
if (tnum_is_const(reg->var_off))
1411414120
return !tnum_equals_const(reg->var_off, val);
1411514121
else if (val < reg->umin_value || val > reg->umax_value)
1411614122
return 1;
14123+
else if (sval < reg->smin_value || sval > reg->smax_value)
14124+
return 1;
1411714125
break;
1411814126
case BPF_JSET:
1411914127
if ((~reg->var_off.mask & reg->var_off.value) & val)

0 commit comments

Comments
 (0)