Skip to content

Commit 9c9d9f6

Browse files
committed
Merge branch 'bpf-simplify-checking-size-of-helper-accesses'
Andrei Matei says: ==================== bpf: Simplify checking size of helper accesses v3->v4: - kept only the minimal change, undoing debatable changes (Andrii) - dropped the second patch from before, with changes to the error message (Andrii) - extracted the new test into a separate patch (Andrii) - added Acked by Andrii v2->v3: - split the error-logging function to a separate patch (Andrii) - make the error buffers smaller (Andrii) - include size of memory region for PTR_TO_MEM (Andrii) - nits from Andrii and Eduard v1->v2: - make the error message include more info about the context of the zero-sized access (Andrii) ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Andrii Nakryiko <[email protected]>
2 parents 5abde62 + faf05f4 commit 9c9d9f6

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-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: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,14 @@ l0_%=: exit; \
8989
: __clobber_all);
9090
}
9191

92+
/* Call a function taking a pointer and a size which doesn't allow the size to
93+
* be zero (i.e. bpf_trace_printk() declares the second argument to be
94+
* ARG_CONST_SIZE, not ARG_CONST_SIZE_OR_ZERO). We attempt to pass zero for the
95+
* size and expect to fail.
96+
*/
9297
SEC("tracepoint")
9398
__description("helper access to map: empty range")
94-
__failure __msg("invalid access to map value, value_size=48 off=0 size=0")
99+
__failure __msg("R2 invalid zero-sized read: u64=[0,0]")
95100
__naked void access_to_map_empty_range(void)
96101
{
97102
asm volatile (" \
@@ -113,6 +118,38 @@ l0_%=: exit; \
113118
: __clobber_all);
114119
}
115120

121+
/* Like the test above, but this time the size register is not known to be zero;
122+
* its lower-bound is zero though, which is still unacceptable.
123+
*/
124+
SEC("tracepoint")
125+
__description("helper access to map: possibly-empty ange")
126+
__failure __msg("R2 invalid zero-sized read: u64=[0,4]")
127+
__naked void access_to_map_possibly_empty_range(void)
128+
{
129+
asm volatile (" \
130+
r2 = r10; \
131+
r2 += -8; \
132+
r1 = 0; \
133+
*(u64*)(r2 + 0) = r1; \
134+
r1 = %[map_hash_48b] ll; \
135+
call %[bpf_map_lookup_elem]; \
136+
if r0 == 0 goto l0_%=; \
137+
r1 = r0; \
138+
/* Read an unknown value */ \
139+
r7 = *(u64*)(r0 + 0); \
140+
/* Make it small and positive, to avoid other errors */ \
141+
r7 &= 4; \
142+
r2 = 0; \
143+
r2 += r7; \
144+
call %[bpf_trace_printk]; \
145+
l0_%=: exit; \
146+
" :
147+
: __imm(bpf_map_lookup_elem),
148+
__imm(bpf_trace_printk),
149+
__imm_addr(map_hash_48b)
150+
: __clobber_all);
151+
}
152+
116153
SEC("tracepoint")
117154
__description("helper access to map: out-of-bound range")
118155
__failure __msg("invalid access to map value, value_size=48 off=0 size=56")
@@ -221,7 +258,7 @@ l0_%=: exit; \
221258

222259
SEC("tracepoint")
223260
__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")
261+
__failure __msg("R2 invalid zero-sized read")
225262
__naked void via_const_imm_empty_range(void)
226263
{
227264
asm volatile (" \
@@ -386,7 +423,7 @@ l0_%=: exit; \
386423

387424
SEC("tracepoint")
388425
__description("helper access to adjusted map (via const reg): empty range")
389-
__failure __msg("R1 min value is outside of the allowed memory range")
426+
__failure __msg("R2 invalid zero-sized read")
390427
__naked void via_const_reg_empty_range(void)
391428
{
392429
asm volatile (" \
@@ -556,7 +593,7 @@ l0_%=: exit; \
556593

557594
SEC("tracepoint")
558595
__description("helper access to adjusted map (via variable): empty range")
559-
__failure __msg("R1 min value is outside of the allowed memory range")
596+
__failure __msg("R2 invalid zero-sized read")
560597
__naked void map_via_variable_empty_range(void)
561598
{
562599
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)