Skip to content

Commit 8a021e7

Browse files
andreimateianakryiko
authored andcommitted
bpf: Simplify checking size of helper accesses
This patch simplifies the verification of size arguments associated to pointer arguments to helpers and kfuncs. Many helpers take a pointer argument followed by the size of the memory access performed to be performed through that pointer. Before this patch, the handling of the size argument in check_mem_size_reg() was confusing and wasteful: if the size register's lower bound was 0, then the verification was done twice: once considering the size of the access to be the lower-bound of the respective argument, and once considering the upper bound (even if the two are the same). The upper bound checking is a super-set of the lower-bound checking(*), except: the only point of the lower-bound check is to handle the case where zero-sized-accesses are explicitly not allowed and the lower-bound is zero. This static condition is now checked explicitly, replacing a much more complex, expensive and confusing verification call to check_helper_mem_access(). Error messages change in this patch. Before, messages about illegal zero-size accesses depended on the type of the pointer and on other conditions, and sometimes the message was plain wrong: in some tests that changed you'll see that the old message was something like "R1 min value is outside of the allowed memory range", where R1 is the pointer register; the error was wrongly claiming that the pointer was bad instead of the size being bad. Other times the information that the size came for a register with a possible range of values was wrong, and the error presented the size as a fixed zero. Now the errors refer to the right register. However, the old error messages did contain useful information about the pointer register which is now lost; recovering this information was deemed not important enough. (*) Besides standing to reason that the checks for a bigger size access are a super-set of the checks for a smaller size access, I have also mechanically verified this by reading the code for all types of pointers. I could convince myself that it's true for all but PTR_TO_BTF_ID (check_ptr_to_btf_access). There, simply looking line-by-line does not immediately prove what we want. If anyone has any qualms, let me know. Signed-off-by: Andrei Matei <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 2ab1efa commit 8a021e7

File tree

3 files changed

+9
-11
lines changed

3 files changed

+9
-11
lines changed

kernel/bpf/verifier.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7279,12 +7279,10 @@ static int check_mem_size_reg(struct bpf_verifier_env *env,
72797279
return -EACCES;
72807280
}
72817281

7282-
if (reg->umin_value == 0) {
7283-
err = check_helper_mem_access(env, regno - 1, 0,
7284-
zero_size_allowed,
7285-
meta);
7286-
if (err)
7287-
return err;
7282+
if (reg->umin_value == 0 && !zero_size_allowed) {
7283+
verbose(env, "R%d invalid zero-sized read: u64=[%lld,%lld]\n",
7284+
regno, reg->umin_value, reg->umax_value);
7285+
return -EACCES;
72887286
}
72897287

72907288
if (reg->umax_value >= BPF_MAX_VAR_SIZ) {

tools/testing/selftests/bpf/progs/verifier_helper_value_access.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ l0_%=: exit; \
9191

9292
SEC("tracepoint")
9393
__description("helper access to map: empty range")
94-
__failure __msg("invalid access to map value, value_size=48 off=0 size=0")
94+
__failure __msg("R2 invalid zero-sized read")
9595
__naked void access_to_map_empty_range(void)
9696
{
9797
asm volatile (" \
@@ -221,7 +221,7 @@ l0_%=: exit; \
221221

222222
SEC("tracepoint")
223223
__description("helper access to adjusted map (via const imm): empty range")
224-
__failure __msg("invalid access to map value, value_size=48 off=4 size=0")
224+
__failure __msg("R2 invalid zero-sized read")
225225
__naked void via_const_imm_empty_range(void)
226226
{
227227
asm volatile (" \
@@ -386,7 +386,7 @@ l0_%=: exit; \
386386

387387
SEC("tracepoint")
388388
__description("helper access to adjusted map (via const reg): empty range")
389-
__failure __msg("R1 min value is outside of the allowed memory range")
389+
__failure __msg("R2 invalid zero-sized read")
390390
__naked void via_const_reg_empty_range(void)
391391
{
392392
asm volatile (" \
@@ -556,7 +556,7 @@ l0_%=: exit; \
556556

557557
SEC("tracepoint")
558558
__description("helper access to adjusted map (via variable): empty range")
559-
__failure __msg("R1 min value is outside of the allowed memory range")
559+
__failure __msg("R2 invalid zero-sized read")
560560
__naked void map_via_variable_empty_range(void)
561561
{
562562
asm volatile (" \

tools/testing/selftests/bpf/progs/verifier_raw_stack.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ __naked void load_bytes_negative_len_2(void)
6464

6565
SEC("tc")
6666
__description("raw_stack: skb_load_bytes, zero len")
67-
__failure __msg("invalid zero-sized read")
67+
__failure __msg("R4 invalid zero-sized read: u64=[0,0]")
6868
__naked void skb_load_bytes_zero_len(void)
6969
{
7070
asm volatile (" \

0 commit comments

Comments
 (0)