Skip to content

Commit 4405951

Browse files
anakryikoKernel Patches Daemon
authored and
Kernel Patches Daemon
committed
bpf: enhance BPF_JEQ/BPF_JNE is_branch_taken logic
Use 32-bit subranges to prune some 64-bit BPF_JEQ/BPF_JNE conditions that otherwise would be "inconclusive" (i.e., is_branch_taken() would return -1). This can happen, for example, when registers are initialized as 64-bit u64/s64, then compared for inequality as 32-bit subregisters, and then followed by 64-bit equality/inequality check. That 32-bit inequality can establish some pattern for lower 32 bits of a register (e.g., s< 0 condition determines whether the bit #31 is zero or not), while overall 64-bit value could be anything (according to a value range representation). This is not a fancy quirky special case, but actually a handling that's necessary to prevent correctness issue with BPF verifier's range tracking: set_range_min_max() assumes that register ranges are non-overlapping, and if that condition is not guaranteed by is_branch_taken() we can end up with invalid ranges, where min > max. [0] https://lore.kernel.org/bpf/CACkBjsY2q1_fUohD7hRmKGqv1MV=eP2f6XK8kjkYNw7BaiF8iQ@mail.gmail.com/ Signed-off-by: Andrii Nakryiko <[email protected]>
1 parent 76ff116 commit 4405951

File tree

1 file changed

+24
-0
lines changed

1 file changed

+24
-0
lines changed

kernel/bpf/verifier.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14214,6 +14214,18 @@ static int is_scalar_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_sta
1421414214
return 0;
1421514215
if (smin1 > smax2 || smax1 < smin2)
1421614216
return 0;
14217+
if (!is_jmp32) {
14218+
/* if 64-bit ranges are inconclusive, see if we can
14219+
* utilize 32-bit subrange knowledge to eliminate
14220+
* branches that can't be taken a priori
14221+
*/
14222+
if (reg1->u32_min_value > reg2->u32_max_value ||
14223+
reg1->u32_max_value < reg2->u32_min_value)
14224+
return 0;
14225+
if (reg1->s32_min_value > reg2->s32_max_value ||
14226+
reg1->s32_max_value < reg2->s32_min_value)
14227+
return 0;
14228+
}
1421714229
break;
1421814230
case BPF_JNE:
1421914231
/* const tnums */
@@ -14229,6 +14241,18 @@ static int is_scalar_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_sta
1422914241
return 1;
1423014242
if (smin1 > smax2 || smax1 < smin2)
1423114243
return 1;
14244+
if (!is_jmp32) {
14245+
/* if 64-bit ranges are inconclusive, see if we can
14246+
* utilize 32-bit subrange knowledge to eliminate
14247+
* branches that can't be taken a priori
14248+
*/
14249+
if (reg1->u32_min_value > reg2->u32_max_value ||
14250+
reg1->u32_max_value < reg2->u32_min_value)
14251+
return 1;
14252+
if (reg1->s32_min_value > reg2->s32_max_value ||
14253+
reg1->s32_max_value < reg2->s32_min_value)
14254+
return 1;
14255+
}
1423214256
break;
1423314257
case BPF_JSET:
1423414258
if (!is_reg_const(reg2, is_jmp32)) {

0 commit comments

Comments
 (0)