mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
bpf: Fix packet range of pointers sharing an id
Since commit022ac07508("bpf: use reg->var_off instead of reg->off for pointers"), find_good_pkt_pointers() sets the range of all packet pointers sharing an id from the umax of the compared pointer, and check_packet_access() requires umax + off + size <= range. That assumes the umax of two such pointers differ by exactly their constant distance. reg_bounds_sync() breaks it when var_off tightens one umax and not the other: r4 &= 0x38 if r4 > 50 goto exit ; umax 50, var_off (0x0; 0x38) r5 = pkt + r4 ; umax 50 r6 = r5 r6 += 8 ; umax 56, not 58 Comparing r6 with pkt_end sets the range to 56, and the valid 8-byte load at r5 is rejected (50 + 8 > 56). Comparing r5 sets it to 50, and the out-of-bounds 1-byte load at r6 - 7, i.e. r5 + 1, is accepted (56 - 7 + 1 <= 50). Don't call reg_bounds_sync() on a packet pointer that keeps its id (a constant was added or subtracted) or its range (an unknown non-negative value was subtracted), so that var_off cannot tighten its umax. Only update the 32-bit bounds from var_off: reg_bounds_sanity_check() wants them constant when the lower half of var_off is, e.g. for pkt + 8. This relies on nothing else changing the 64-bit bounds of a packet pointer, which holds today. var_off of such a pointer is no longer narrowed by its bounds. Adjust three verifier_align expectations; the low bits, which the alignment checks use, don't change. veristat on the selftests shows no verdict changes and +0.8% insns in test_cls_redirect_subprogs. Fixes:022ac07508("bpf: use reg->var_off instead of reg->off for pointers") Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20261001145255.855630-1-alexei.starovoitov@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
parent
564b7e8e09
commit
b88822d258
|
|
@ -14826,7 +14826,15 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, struct bpf_insn
|
||||||
"Tighten the scalar bounds before the arithmetic so the resulting pointer remains within the allowed range.");
|
"Tighten the scalar bounds before the arithmetic so the resulting pointer remains within the allowed range.");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
reg_bounds_sync(dst_reg);
|
/*
|
||||||
|
* A packet pointer that keeps its id or range is checked against a
|
||||||
|
* range set from the checked pointer's umax, so var_off must not tighten
|
||||||
|
* its umax. r32 must still match var_off for reg_bounds_sanity_check().
|
||||||
|
*/
|
||||||
|
if (reg_is_pkt_pointer(dst_reg) && (known || dst_reg->range > 0))
|
||||||
|
__update_reg32_bounds(dst_reg);
|
||||||
|
else
|
||||||
|
reg_bounds_sync(dst_reg);
|
||||||
bounds_ret = sanitize_check_bounds(env, insn, dst_reg);
|
bounds_ret = sanitize_check_bounds(env, insn, dst_reg);
|
||||||
if (bounds_ret == -EACCES)
|
if (bounds_ret == -EACCES)
|
||||||
return bounds_ret;
|
return bounds_ret;
|
||||||
|
|
|
||||||
|
|
@ -284,7 +284,7 @@ __msg("26: {{.*}} R5=pkt(r=8,imm=14)")
|
||||||
*/
|
*/
|
||||||
__msg("28: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x7fc){{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
|
__msg("28: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x7fc){{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
|
||||||
/* Constant is added to R5 again, setting reg->off to 18. */
|
/* Constant is added to R5 again, setting reg->off to 18. */
|
||||||
__msg("29: {{.*}} R5=pkt(id=3,{{[^)]*}}var_off=(0x2; 0x7fc)")
|
__msg("29: {{.*}} R5=pkt(id=3,{{[^)]*}}var_off=(0x2; 0xffc)")
|
||||||
/* And once more we add a variable; resulting {{[^)]*}}var_off
|
/* And once more we add a variable; resulting {{[^)]*}}var_off
|
||||||
* is still (4n), fixed offset is not changed.
|
* is still (4n), fixed offset is not changed.
|
||||||
* Also, we create a new reg->id.
|
* Also, we create a new reg->id.
|
||||||
|
|
@ -359,7 +359,7 @@ __msg("7: {{.*}} R6={{[^)]*}}var_off=(0x0; 0x3fc)")
|
||||||
__msg("8: {{.*}} R6={{[^)]*}}var_off=(0x2; 0x7fc)")
|
__msg("8: {{.*}} R6={{[^)]*}}var_off=(0x2; 0x7fc)")
|
||||||
/* Packet pointer has (4n+2) offset */
|
/* Packet pointer has (4n+2) offset */
|
||||||
__msg("11: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
|
__msg("11: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
|
||||||
__msg("12: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x7fc)")
|
__msg("12: {{.*}} R4={{[^)]*}}var_off=(0x2; 0xffc)")
|
||||||
/* At the time the word size load is performed from R5,
|
/* At the time the word size load is performed from R5,
|
||||||
* its total fixed offset is NET_IP_ALIGN + reg->off (0)
|
* its total fixed offset is NET_IP_ALIGN + reg->off (0)
|
||||||
* which is 2. Then the variable offset is (4n+2), so
|
* which is 2. Then the variable offset is (4n+2), so
|
||||||
|
|
@ -375,7 +375,7 @@ __msg("17: {{.*}} R6={{[^)]*}}var_off=(0x0; 0x3fc)")
|
||||||
* another (4n+2).
|
* another (4n+2).
|
||||||
*/
|
*/
|
||||||
__msg("19: {{.*}} R5={{[^)]*}}var_off=(0x2; 0xffc)")
|
__msg("19: {{.*}} R5={{[^)]*}}var_off=(0x2; 0xffc)")
|
||||||
__msg("20: {{.*}} R4={{[^)]*}}var_off=(0x2; 0xffc)")
|
__msg("20: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x1ffc)")
|
||||||
/* At the time the word size load is performed from R5,
|
/* At the time the word size load is performed from R5,
|
||||||
* its total fixed offset is NET_IP_ALIGN + reg->off (0)
|
* its total fixed offset is NET_IP_ALIGN + reg->off (0)
|
||||||
* which is 2. Then the variable offset is (4n+2), so
|
* which is 2. Then the variable offset is (4n+2), so
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user