Skip to content

Commit 260b862

Browse files
theihoranakryiko
authored andcommitted
selftests/bpf: Add test cases with CONST_PTR_TO_MAP null checks
A test requires the following to happen: * CONST_PTR_TO_MAP value is checked for null * the code in the null branch fails verification Add test cases: * direct global map_ptr comparison to null * lookup inner map, then two checks (the first transforms map_value_or_null into map_ptr) * lookup inner map, spill-fill it, then check for null * use an array of ringbufs to recreate a common coding pattern [1] [1] https://lore.kernel.org/bpf/CAEf4BzZNU0gX_sQ8k8JaLe1e+Veth3Rk=4x7MDhv=hQxvO8EDw@mail.gmail.com/ Suggested-by: Andrii Nakryiko <[email protected]> Signed-off-by: Ihor Solodrai <[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 eb6c992 commit 260b862

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

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

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,122 @@ __naked void on_the_inner_map_pointer(void)
139139
: __clobber_all);
140140
}
141141

142+
SEC("socket")
143+
__description("map_ptr is never null")
144+
__success
145+
__naked void map_ptr_is_never_null(void)
146+
{
147+
asm volatile (" \
148+
r0 = 0; \
149+
r1 = %[map_in_map] ll; \
150+
if r1 != 0 goto l0_%=; \
151+
r10 = 42; \
152+
l0_%=: exit; \
153+
" :
154+
: __imm(bpf_map_lookup_elem),
155+
__imm_addr(map_in_map)
156+
: __clobber_all);
157+
}
158+
159+
SEC("socket")
160+
__description("map_ptr is never null inner")
161+
__success
162+
__naked void map_ptr_is_never_null_inner(void)
163+
{
164+
asm volatile (" \
165+
r1 = 0; \
166+
*(u32*)(r10 - 4) = r1; \
167+
r2 = r10; \
168+
r2 += -4; \
169+
r1 = %[map_in_map] ll; \
170+
call %[bpf_map_lookup_elem]; \
171+
if r0 == 0 goto l0_%=; \
172+
if r0 != 0 goto l0_%=; \
173+
r10 = 42; \
174+
l0_%=: exit; \
175+
" :
176+
: __imm(bpf_map_lookup_elem),
177+
__imm_addr(map_in_map)
178+
: __clobber_all);
179+
}
180+
181+
SEC("socket")
182+
__description("map_ptr is never null inner spill fill")
183+
__success
184+
__naked void map_ptr_is_never_null_inner_spill_fill(void)
185+
{
186+
asm volatile (" \
187+
r1 = 0; \
188+
*(u32*)(r10 - 4) = r1; \
189+
r2 = r10; \
190+
r2 += -4; \
191+
r1 = %[map_in_map] ll; \
192+
call %[bpf_map_lookup_elem]; \
193+
if r0 != 0 goto l0_%=; \
194+
exit; \
195+
l0_%=: *(u64 *)(r10 -16) = r0; \
196+
r1 = *(u64 *)(r10 -16); \
197+
if r1 == 0 goto l1_%=; \
198+
exit; \
199+
l1_%=: r10 = 42; \
200+
exit; \
201+
" :
202+
: __imm(bpf_map_lookup_elem),
203+
__imm_addr(map_in_map)
204+
: __clobber_all);
205+
}
206+
207+
struct {
208+
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
209+
__uint(max_entries, 1);
210+
__type(key, int);
211+
__type(value, int);
212+
__array(values, struct {
213+
__uint(type, BPF_MAP_TYPE_RINGBUF);
214+
__uint(max_entries, 64 * 1024);
215+
});
216+
} rb_in_map SEC(".maps");
217+
218+
struct rb_ctx {
219+
void *rb;
220+
struct bpf_dynptr dptr;
221+
};
222+
223+
static __always_inline struct rb_ctx __rb_event_reserve(__u32 sz)
224+
{
225+
struct rb_ctx rb_ctx = {};
226+
void *rb;
227+
__u32 cpu = bpf_get_smp_processor_id();
228+
__u32 rb_slot = cpu & 1;
229+
230+
rb = bpf_map_lookup_elem(&rb_in_map, &rb_slot);
231+
if (!rb)
232+
return rb_ctx;
233+
234+
rb_ctx.rb = rb;
235+
bpf_ringbuf_reserve_dynptr(rb, sz, 0, &rb_ctx.dptr);
236+
237+
return rb_ctx;
238+
}
239+
240+
static __noinline void __rb_event_submit(struct rb_ctx *ctx)
241+
{
242+
if (!ctx->rb)
243+
return;
244+
245+
/* If the verifier (incorrectly) concludes that ctx->rb can be
246+
* NULL at this point, we'll get "BPF_EXIT instruction in main
247+
* prog would lead to reference leak" error
248+
*/
249+
bpf_ringbuf_submit_dynptr(&ctx->dptr, 0);
250+
}
251+
252+
SEC("socket")
253+
int map_ptr_is_never_null_rb(void *ctx)
254+
{
255+
struct rb_ctx event_ctx = __rb_event_reserve(256);
256+
__rb_event_submit(&event_ctx);
257+
return 0;
258+
}
259+
142260
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)