bpf: Fix bounds when ranges cross sign boundary
cover bpf: Fix bounds when ranges cross sign boundary
As discussed in [1] yesterday, this series backports two sets of fixes for BPF, with their selftests:
- 00bf8d0c6c9b ("bpf: Improve bounds when s64 crosses sign boundary")
- 26e5e346a52c ("selftests/bpf: Test cross-sign 64bits range refinement")
- f96841bbf4a1 ("selftests/bpf: Test invariants on JSLT crossing sign")
- 5dbb19b16ac4 ("bpf: Add third round of bounds deduction")
- fbc7aef517d8 ("bpf: Fix u32/s32 bounds when ranges cross min/max boundary")
- f81fdfd16771 ("selftests/bpf: test refining u32/s32 bounds when ranges cross min/max boundary")
Using Shung-Hsi's stable CI repo [2], I verified the BPF selftests pass with these commits applied on top of v6.12.
1: https://lore.kernel.org/stable/2026040240-friday-gurgling-7088@gregkh/
2: https://github.com/pchaigno/stable-bpf-ci/actions/runs/23940850516/job/69826632354
Eduard Zingerman (2):
bpf: Fix u32/s32 bounds when ranges cross min/max boundary selftests/bpf: test refining u32/s32 bounds when ranges cross min/max
boundary
Paul Chaignon (4):
bpf: Improve bounds when s64 crosses sign boundary selftests/bpf: Test cross-sign 64bits range refinement selftests/bpf: Test invariants on JSLT crossing sign
bpf: Add third round of bounds deduction
kernel/bpf/verifier.c | 77 +++++++++ .../selftests/bpf/prog_tests/reg_bounds.c | 62 ++++++- .../selftests/bpf/progs/verifier_bounds.c | 159 +++++++++++++++++- 3 files changed, 292 insertions(+), 6 deletions(-)
Signature · 1 line
2.43.0
PATCH 1/6 bpf: Improve bounds when s64 crosses sign boundary
[ Upstream commit 00bf8d0c6c9be0c481fc45a3f7d87c7f8812f229 ]
__reg64_deduce_bounds currently improves the s64 range using the u64 range and vice versa, but only if it doesn't cross the sign boundary.
This patch improves __reg64_deduce_bounds to cover the case where the s64 range crosses the sign boundary but overlaps with the u64 range on only one end. In that case, we can improve both ranges. Consider the following example, with the s64 range crossing the sign boundary:
0 U64_MAX
| [xxxxxxxxxxxxxx u64 range xxxxxxxxxxxxxx] |
|----------------------------|----------------------------|
|xxxxx s64 range xxxxxxxxx] [xxxxxxx|
0 S64_MAX S64_MIN -1
The u64 range overlaps only with positive portion of the s64 range. We can thus derive the following new s64 and u64 ranges.
0 U64_MAX
| [xxxxxx u64 range xxxxx] |
|----------------------------|----------------------------|
| [xxxxxx s64 range xxxxx] |
0 S64_MAX S64_MIN -1
The same logic can probably apply to the s32/u32 ranges, but this patch doesn't implement that change.
In addition to the selftests, the __reg64_deduce_bounds change was also tested with Agni, the formal verification tool for the range analysis [1].
--- kernel/bpf/verifier.c | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
kernel/bpf/verifier.c +52 -0
@@ -2129,6 +2129,58 @@ static void __reg64_deduce_bounds(struct bpf_reg_state *reg)if ((u64 )reg->smin_value <= (u64 )reg->smax_value) { reg->umin_value =max_t (u64, reg->smin_value, reg->umin_value); reg->umax_value =min_t (u64, reg->smax_value, reg->umax_value); + }else { +/* If the s64 range crosses the sign boundary, then it's split +* between the beginning and end of the U64 domain. In that +* case, we can derive new bounds if the u64 range overlaps +* with only one end of the s64 range. +* +* In the following example, the u64 range overlaps only with +* positive portion of the s64 range. +* +* 0 U64_MAX +* | [xxxxxxxxxxxxxx u64 range xxxxxxxxxxxxxx] | +* |----------------------------|----------------------------| +* |xxxxx s64 range xxxxxxxxx] [xxxxxxx| +* 0 S64_MAX S64_MIN -1 +* +* We can thus derive the following new s64 and u64 ranges. +* +* 0 U64_MAX +* | [xxxxxx u64 range xxxxx] | +* |----------------------------|----------------------------| +* | [xxxxxx s64 range xxxxx] | +* 0 S64_MAX S64_MIN -1 +* +* If they overlap in two places, we can't derive anything +* because reg_state can't represent two ranges per numeric +* domain. +* +* 0 U64_MAX +* | [xxxxxxxxxxxxxxxxx u64 range xxxxxxxxxxxxxxxxx] | +* |----------------------------|----------------------------| +* |xxxxx s64 range xxxxxxxxx] [xxxxxxxxxx| +* 0 S64_MAX S64_MIN -1 +* +* The first condition below corresponds to the first diagram +* above. +*/ +if (reg->umax_value < (u64 )reg->smin_value) { + reg->smin_value = (s64 )reg->umin_value; + reg->umax_value =min_t (u64, reg->umax_value, reg->smax_value); + }else if ((u64 )reg->smax_value < reg->umin_value) { +/* This second condition considers the case where the u64 range +* overlaps with the negative portion of the s64 range: +* +* 0 U64_MAX +* | [xxxxxxxxxxxxxx u64 range xxxxxxxxxxxxxx] | +* |----------------------------|----------------------------| +* |xxxxxxxxx] [xxxxxxxxxxxx s64 range | +* 0 S64_MAX S64_MIN -1 +*/ + reg->smax_value = (s64 )reg->umax_value; + reg->umin_value =max_t (u64, reg->umin_value, reg->smin_value); + } } }
Signature · 1 line
2.43.0
PATCH 2/6 selftests/bpf: Test cross-sign 64bits range refinement
In reply to Paul Chaignon[ Upstream commit 26e5e346a52c796190e63af1c2a80a417fda261a ]
This patch adds coverage for the new cross-sign 64bits range refinement logic. The three tests cover the cases when the u64 and s64 ranges overlap (1) in the negative portion of s64, (2) in the positive portion of s64, and (3) in both portions.
The first test is a simplified version of a BPF program generated by syzkaller that caused an invariant violation [1]. It looks like syzkaller could not extract the reproducer itself (and therefore didn't report it to the mailing list), but I was able to extract it from the console logs of a crash.
The principle is similar to the invariant violation described in commit 6279846b9b25 ("bpf: Forget ranges when refining tnum after JSET"): the verifier walks a dead branch, uses the condition to refine ranges, and ends up with inconsistent ranges. In this case, the dead branch is when we fallthrough on both jumps. The new refinement logic improves the bounds such that the second jump is properly detected as always-taken and the verifier doesn't end up walking a dead branch.
The second and third tests are inspired by the first, but rely on condition jumps to prepare the bounds instead of ALU instructions. An R10 write is used to trigger a verifier error when the bounds can't be refined.
--- .../selftests/bpf/progs/verifier_bounds.c | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+)
tools/testing/selftests/bpf/progs/verifier_bounds.c +118 -0
@@ -1200,4 +1200,122 @@ l0_%=: r0 = 0; \ : __clobber_all); } +/* This test covers the bounds deduction on 64bits when the s64 and u64 ranges +* overlap on the negative side. At instruction 7, the ranges look as follows: +* +* 0 umin=0xfffffcf1 umax=0xff..ff6e U64_MAX +* | [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] | +* |----------------------------|------------------------------| +* |xxxxxxxxxx] [xxxxxxxxxxxx| +* 0 smax=0xeffffeee smin=-655 -1 +* +* We should therefore deduce the following new bounds: +* +* 0 u64=[0xff..ffd71;0xff..ff6e] U64_MAX +* | [xxx] | +* |----------------------------|------------------------------| +* | [xxx] | +* 0 s64=[-655;-146] -1 +* +* Without the deduction cross sign boundary, we end up with an invariant +* violation error. +*/ +SEC("socket") +__description("bounds deduction cross sign boundary, negative overlap") +__success __log_level(2) __flag(BPF_F_TEST_REG_INVARIANTS) +__msg("7: (1f) r0 -= r6 {{.*}} R0=scalar(smin=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,smin32=-783,umin32=0xfffffcf1,umax32=0xffffff6e,var_off=(0xfffffffffffffc00; 0x3ff))") +__retval(0) +__naked void bounds_deduct_negative_overlap(void) +{ + asmvolatile (" \ +call %[bpf_get_prandom_u32]; \ +w3 = w0; \ +w6 = (s8)w0; \ +r0 = (s8)r0; \ +if w6 >= 0xf0000000 goto l0_%=; \ +r0 += r6; \ +r6 += 400; \ +r0 -= r6; \ +if r3 < r0 goto l0_%=; \ +l0_%=: r0 = 0; \ +exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +/* This test covers the bounds deduction on 64bits when the s64 and u64 ranges +* overlap on the positive side. At instruction 3, the ranges look as follows: +* +* 0 umin=0 umax=0xffffffffffffff00 U64_MAX +* [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] | +* |----------------------------|------------------------------| +* |xxxxxxxx] [xxxxxxxx| +* 0 smax=127 smin=-128 -1 +* +* We should therefore deduce the following new bounds: +* +* 0 u64=[0;127] U64_MAX +* [xxxxxxxx] | +* |----------------------------|------------------------------| +* [xxxxxxxx] | +* 0 s64=[0;127] -1 +* +* Without the deduction cross sign boundary, the program is rejected due to +* the frame pointer write. +*/ +SEC("socket") +__description("bounds deduction cross sign boundary, positive overlap") +__success __log_level(2) __flag(BPF_F_TEST_REG_INVARIANTS) +__msg("3: (2d) if r0 > r1 {{.*}} R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=127,var_off=(0x0; 0x7f))") +__retval(0) +__naked void bounds_deduct_positive_overlap(void) +{ + asmvolatile (" \ +call %[bpf_get_prandom_u32]; \ +r0 = (s8)r0; \ +r1 = 0xffffffffffffff00; \ +if r0 > r1 goto l0_%=; \ +if r0 < 128 goto l0_%=; \ +r10 = 0; \ +l0_%=: r0 = 0; \ +exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +/* This test is the same as above, but the s64 and u64 ranges overlap in two +* places. At instruction 3, the ranges look as follows: +* +* 0 umin=0 umax=0xffffffffffffff80 U64_MAX +* [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] | +* |----------------------------|------------------------------| +* |xxxxxxxx] [xxxxxxxx| +* 0 smax=127 smin=-128 -1 +* +* 0xffffffffffffff80 = (u64)-128. We therefore can't deduce anything new and +* the program should fail due to the frame pointer write. +*/ +SEC("socket") +__description("bounds deduction cross sign boundary, two overlaps") +__failure __flag(BPF_F_TEST_REG_INVARIANTS) +__msg("3: (2d) if r0 > r1 {{.*}} R0_w=scalar(smin=smin32=-128,smax=smax32=127,umax=0xffffffffffffff80)") +__msg("frame pointer is read only") +__naked void bounds_deduct_two_overlaps(void) +{ + asmvolatile (" \ +call %[bpf_get_prandom_u32]; \ +r0 = (s8)r0; \ +r1 = 0xffffffffffffff80; \ +if r0 > r1 goto l0_%=; \ +if r0 < 128 goto l0_%=; \ +r10 = 0; \ +l0_%=: r0 = 0; \ +exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + char _license[] SEC("license") = "GPL";
Signature · 1 line
2.43.0
PATCH 3/6 selftests/bpf: Test invariants on JSLT crossing sign
In reply to Paul Chaignon[ Upstream commit f96841bbf4a1ee4ed0336ba192a01278fdea6383 ]
The improvement of the u64/s64 range refinement fixed the invariant violation that was happening on this test for BPF_JSLT when crossing the sign boundary.
After this patch, we have one test remaining with a known invariant violation. It's the same test as fixed here but for 32 bits ranges.
--- tools/testing/selftests/bpf/progs/verifier_bounds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/bpf/progs/verifier_bounds.c +1 -1
@@ -1028,7 +1028,7 @@ l0_%=: r0 = 0; \ SEC("xdp") __description("bound check with JMP_JSLT for crossing 64-bit signed boundary") __success __retval(0) -__flag (!BPF_F_TEST_REG_INVARIANTS )/* known invariants violation */ +__flag (BPF_F_TEST_REG_INVARIANTS )__naked voidcrossing_64_bit_signed_boundary_2 (void) { asm volatile (" \
Signature · 1 line
2.43.0
PATCH 4/6 bpf: Add third round of bounds deduction
In reply to Paul Chaignon[ Upstream commit 5dbb19b16ac498b0b7f3a8a85f9d25d6d8af397d ]
Commit d7f008738171 ("bpf: try harder to deduce register bounds from different numeric domains") added a second call to __reg_deduce_bounds in reg_bounds_sync because a single call wasn't enough to converge to a fixed point in terms of register bounds.
With patch "bpf: Improve bounds when s64 crosses sign boundary" from this series, Eduard noticed that calling __reg_deduce_bounds twice isn't enough anymore to converge. The first selftest added in "selftests/bpf:
Test cross-sign 64bits range refinement" highlights the need for a third call to __reg_deduce_bounds. After instruction 7, reg_bounds_sync performs the following bounds deduction:
reg_bounds_sync entry: scalar(smin=-655,smax=0xeffffeee,smin32=-783,smax32=-146)
__update_reg_bounds: scalar(smin=-655,smax=0xeffffeee,smin32=-783,smax32=-146)
__reg_deduce_bounds:
__reg32_deduce_bounds: scalar(smin=-655,smax=0xeffffeee,smin32=-783,smax32=-146,umin32=0xfffffcf1,umax32=0xffffff6e)
__reg64_deduce_bounds: scalar(smin=-655,smax=0xeffffeee,smin32=-783,smax32=-146,umin32=0xfffffcf1,umax32=0xffffff6e)
__reg_deduce_mixed_bounds: scalar(smin=-655,smax=0xeffffeee,umin=umin32=0xfffffcf1,umax=0xffffffffffffff6e,smin32=-783,smax32=-146,umax32=0xffffff6e)
__reg_deduce_bounds:
__reg32_deduce_bounds: scalar(smin=-655,smax=0xeffffeee,umin=umin32=0xfffffcf1,umax=0xffffffffffffff6e,smin32=-783,smax32=-146,umax32=0xffffff6e)
__reg64_deduce_bounds: scalar(smin=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,smin32=-783,umin32=0xfffffcf1,umax32=0xffffff6e)
__reg_deduce_mixed_bounds: scalar(smin=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,smin32=-783,umin32=0xfffffcf1,umax32=0xffffff6e)
__reg_bound_offset: scalar(smin=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,smin32=-783,umin32=0xfffffcf1,umax32=0xffffff6e,var_off=(0xfffffffffffffc00; 0x3ff))
__update_reg_bounds: scalar(smin=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,smin32=-783,umin32=0xfffffcf1,umax32=0xffffff6e,var_off=(0xfffffffffffffc00; 0x3ff))In particular, notice how:
1. In the first call to __reg_deduce_bounds, __reg32_deduce_bounds learns new u32 bounds.
2. __reg64_deduce_bounds is unable to improve bounds at this point.
3. __reg_deduce_mixed_bounds derives new u64 bounds from the u32 bounds.
4. In the second call to __reg_deduce_bounds, __reg64_deduce_bounds improves the smax and umin bounds thanks to patch "bpf: Improve bounds when s64 crosses sign boundary" from this series.
5. Subsequent functions are unable to improve the ranges further (only tnums). Yet, a better smin32 bound could be learned from the smin bound.
__reg32_deduce_bounds is able to improve smin32 from smin, but for that we need a third call to __reg_deduce_bounds.
As discussed in [1], there may be a better way to organize the deduction rules to learn the same information with less calls to the same functions. Such an optimization requires further analysis and is orthogonal to the present patchset.
--- kernel/bpf/verifier.c | 1 + tools/testing/selftests/bpf/progs/verifier_bounds.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
kernel/bpf/verifier.c +1 -0
@@ -2292,6 +2292,7 @@ static void reg_bounds_sync(struct bpf_reg_state *reg)/* We might have learned something about the sign bit. */ __reg_deduce_bounds (reg);__reg_deduce_bounds (reg); +__reg_deduce_bounds (reg);/* We might have learned some bits from the bounds. */ __reg_bound_offset (reg);/* Intersecting with the old var_off might have improved our bounds
tools/testing/selftests/bpf/progs/verifier_bounds.c +1 -1
@@ -1223,7 +1223,7 @@ l0_%=: r0 = 0; \ SEC("socket") __description("bounds deduction cross sign boundary, negative overlap") __success __log_level(2) __flag(BPF_F_TEST_REG_INVARIANTS) -__msg("7: (1f) r0 -= r6 {{.*}} R0=scalar(smin=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,smin32=-783,umin32=0xfffffcf1,umax32=0xffffff6e,var_off=(0xfffffffffffffc00; 0x3ff))") +__msg("7: (1f) r0 -= r6 {{.*}} R0=scalar(smin=smin32=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,umin32=0xfffffd71,umax32=0xffffff6e,var_off=(0xfffffffffffffc00; 0x3ff))") __retval(0) __naked void bounds_deduct_negative_overlap(void) {
Signature · 1 line
2.43.0
PATCH 5/6 bpf: Fix u32/s32 bounds when ranges cross min/max boundary
In reply to Paul ChaignonFrom: Eduard Zingerman <[email protected]>
[ Upstream commit fbc7aef517d8765e4c425d2792409bb9bf2e1f13 ]
Same as in __reg64_deduce_bounds(), refine s32/u32 ranges in __reg32_deduce_bounds() in the following situations:
- s32 range crosses U32_MAX/0 boundary, positive part of the s32 range overlaps with u32 range:
0 U32_MAX
| [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] | |----------------------------|----------------------------| |xxxxx s32 range xxxxxxxxx] [xxxxxxx| 0 S32_MAX S32_MIN -1
- s32 range crosses U32_MAX/0 boundary, negative part of the s32 range overlaps with u32 range:
0 U32_MAX
| [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] | |----------------------------|----------------------------| |xxxxxxxxx] [xxxxxxxxxxxx s32 range | 0 S32_MAX S32_MIN -1
- No refinement if ranges overlap in two intervals.
This helps for e.g. consider the following program:
call %[bpf_get_prandom_u32];
w0 &= 0xffffffff;
if w0 < 0x3 goto 1f; // on fall-through u32 range [3..U32_MAX] if w0 s> 0x1 goto 1f; // on fall-through s32 range [S32_MIN..1] if w0 s< 0x0 goto 1f; // range can be narrowed to [S32_MIN..-1]
r10 = 0;
1: ...;
The reg_bounds.c selftest is updated to incorporate identical logic, refinement based on non-overflowing range halves:
((x ∩ [0, smax]) ∩ (y ∩ [0, smax])) ∪
((x ∩ [smin,-1]) ∩ (y ∩ [smin,-1]))
--- kernel/bpf/verifier.c | 24 +++++++ .../selftests/bpf/prog_tests/reg_bounds.c | 62 +++++++++++++++++-- 2 files changed, 82 insertions(+), 4 deletions(-)
kernel/bpf/verifier.c +24 -0
@@ -2046,6 +2046,30 @@ static void __reg32_deduce_bounds(struct bpf_reg_state *reg)if ((u32 )reg->s32_min_value <= (u32 )reg->s32_max_value) { reg->u32_min_value =max_t (u32, reg->s32_min_value, reg->u32_min_value); reg->u32_max_value =min_t (u32, reg->s32_max_value, reg->u32_max_value); + }else { +if (reg->u32_max_value < (u32 )reg->s32_min_value) { +/* See __reg64_deduce_bounds() for detailed explanation. +* Refine ranges in the following situation: +* +* 0 U32_MAX +* | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] | +* |----------------------------|----------------------------| +* |xxxxx s32 range xxxxxxxxx] [xxxxxxx| +* 0 S32_MAX S32_MIN -1 +*/ + reg->s32_min_value = (s32 )reg->u32_min_value; + reg->u32_max_value =min_t (u32, reg->u32_max_value, reg->s32_max_value); + }else if ((u32 )reg->s32_max_value < reg->u32_min_value) { +/* +* 0 U32_MAX +* | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] | +* |----------------------------|----------------------------| +* |xxxxxxxxx] [xxxxxxxxxxxx s32 range | +* 0 S32_MAX S32_MIN -1 +*/ + reg->s32_max_value = (s32 )reg->u32_max_value; + reg->u32_min_value =max_t (u32, reg->u32_min_value, reg->s32_min_value); + } } }
tools/testing/selftests/bpf/prog_tests/reg_bounds.c +58 -4
91 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH 6/6 selftests/bpf: test refining u32/s32 bounds when ranges cross min/max boundary
In reply to Paul ChaignonFrom: Eduard Zingerman <[email protected]>
[ Upstream commit f81fdfd16771e266753146bd83f6dd23515ebee9 ]
Two test cases for signed/unsigned 32-bit bounds refinement when s32 range crosses the sign boundary:
- s32 range [S32_MIN..1] overlapping with u32 range [3..U32_MAX], s32 range tail before sign boundary overlaps with u32 range.
- s32 range [-3..5] overlapping with u32 range [0..S32_MIN+3], s32 range head after the sign boundary overlaps with u32 range.
This covers both branches added in the __reg32_deduce_bounds().
Also, crossing_32_bit_signed_boundary_2() no longer triggers invariant violations.
--- .../selftests/bpf/progs/verifier_bounds.c | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-)
tools/testing/selftests/bpf/progs/verifier_bounds.c +38 -1
@@ -1110,7 +1110,7 @@ l0_%=: r0 = 0; \ SEC("xdp") __description("bound check with JMP32_JSLT for crossing 32-bit signed boundary") __success __retval(0) -__flag (!BPF_F_TEST_REG_INVARIANTS )/* known invariants violation */ +__flag (BPF_F_TEST_REG_INVARIANTS )__naked voidcrossing_32_bit_signed_boundary_2 (void) { asm volatile (" \
@@ -1318,4 +1318,41 @@ l0_%=: r0 = 0; \ : __clobber_all); } +SEC("socket") +__success +__flag (BPF_F_TEST_REG_INVARIANTS ) +__naked voidsigned_unsigned_intersection32_case1 (void *ctx) +{ + asmvolatile (" \ +call %[bpf_get_prandom_u32]; \ +w0 &= 0xffffffff; \ +if w0 < 0x3 goto 1f; /* on fall-through u32 range [3..U32_MAX] */ \ +if w0 s> 0x1 goto 1f; /* on fall-through s32 range [S32_MIN..1] */ \ +if w0 s< 0x0 goto 1f; /* range can be narrowed to [S32_MIN..-1] */ \ +r10 = 0; /* thus predicting the jump. */ \ +1: exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + +SEC("socket") +__success +__flag (BPF_F_TEST_REG_INVARIANTS ) +__naked voidsigned_unsigned_intersection32_case2 (void *ctx) +{ + asmvolatile (" \ +call %[bpf_get_prandom_u32]; \ +w0 &= 0xffffffff; \ +if w0 > 0x80000003 goto 1f; /* on fall-through u32 range [0..S32_MIN+3] */ \ +if w0 s< -3 goto 1f; /* on fall-through s32 range [-3..S32_MAX] */ \ +if w0 s> 5 goto 1f; /* on fall-through s32 range [-3..5] */ \ +if w0 <= 5 goto 1f; /* range can be narrowed to [0..5] */ \ +r10 = 0; /* thus predicting the jump */ \ +1: exit; \ +" : + : __imm(bpf_get_prandom_u32) + : __clobber_all); +} + char _license[] SEC("license") = "GPL";
Signature · 1 line
2.43.0
Quoted 12 lines · Paul Chaignon
As discussed in [1] yesterday, this series backports two sets of fixes for BPF, with their selftests:
-00bf8d0c6c9b("bpf: Improve bounds when s64 crosses sign boundary")
-26e5e346a52c("selftests/bpf: Test cross-sign 64bits range refinement")
-f96841bbf4a1("selftests/bpf: Test invariants on JSLT crossing sign")
-5dbb19b16ac4("bpf: Add third round of bounds deduction")
-fbc7aef517d8("bpf: Fix u32/s32 bounds when ranges cross min/max boundary")
-f81fdfd16771("selftests/bpf: test refining u32/s32 bounds when ranges cross min/max boundary")
Quoted 2 lines
Using Shung-Hsi's stable CI repo [2], I verified the BPF selftests pass with these commits applied on top of v6.12.
As hinted here, the subject prefix is incorrect. This series is meant for v6.12, not v6.6. Should I resend?
Quoted 23 lines
1: https://lore.kernel.org/stable/2026040240-friday-gurgling-7088@gregkh/
2: https://github.com/pchaigno/stable-bpf-ci/actions/runs/23940850516/job/69826632354Eduard Zingerman (2):
bpf: Fix u32/s32 bounds when ranges cross min/max boundary selftests/bpf: test refining u32/s32 bounds when ranges cross min/max
boundaryPaul Chaignon (4):
bpf: Improve bounds when s64 crosses sign boundary selftests/bpf: Test cross-sign 64bits range refinement selftests/bpf: Test invariants on JSLT crossing sign
bpf: Add third round of bounds deductionkernel/bpf/verifier.c | 77 +++++++++ .../selftests/bpf/prog_tests/reg_bounds.c | 62 ++++++- .../selftests/bpf/progs/verifier_bounds.c | 159 +++++++++++++++++- 3 files changed, 292 insertions(+), 6 deletions(-)Signature · 1 line
2.43.0
Greg Kroah-Hartman
maintainerQuoted 13 lines · Paul Chaignon
Quoted 12 lines · Paul Chaignon
As discussed in [1] yesterday, this series backports two sets of fixes for BPF, with their selftests:
-00bf8d0c6c9b("bpf: Improve bounds when s64 crosses sign boundary")
-26e5e346a52c("selftests/bpf: Test cross-sign 64bits range refinement")
-f96841bbf4a1("selftests/bpf: Test invariants on JSLT crossing sign")
-5dbb19b16ac4("bpf: Add third round of bounds deduction")
-fbc7aef517d8("bpf: Fix u32/s32 bounds when ranges cross min/max boundary")
-f81fdfd16771("selftests/bpf: test refining u32/s32 bounds when ranges cross min/max boundary")
Quoted 5 lines
Quoted 2 lines
Using Shung-Hsi's stable CI repo [2], I verified the BPF selftests pass with these commits applied on top of v6.12.
As hinted here, the subject prefix is incorrect. This series is meant for v6.12, not v6.6. Should I resend?
Yes please!