File Index
Files and directories
Sign in
FILE

verifier_map_in_map.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/progs/verifier_map_in_map.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Converted from tools/testing/selftests/bpf/verifier/map_in_map.c */
  3
  4#include <linux/bpf.h>
  5#include <bpf/bpf_helpers.h>
  6#include "bpf_misc.h"
  7
  8struct {
  9	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
 10	__uint(max_entries, 1);
 11	__type(key, int);
 12	__type(value, int);
 13	__array(values, struct {
 14		__uint(type, BPF_MAP_TYPE_ARRAY);
 15		__uint(max_entries, 1);
 16		__type(key, int);
 17		__type(value, int);
 18	});
 19} map_in_map SEC(".maps");
 20
 21SEC("socket")
 22__description("map in map access")
 23__success __success_unpriv __retval(0)
 24__naked void map_in_map_access(void)
 25{
 26	asm volatile ("					\
 27	r1 = 0;						\
 28	*(u32*)(r10 - 4) = r1;				\
 29	r2 = r10;					\
 30	r2 += -4;					\
 31	r1 = %[map_in_map] ll;				\
 32	call %[bpf_map_lookup_elem];			\
 33	if r0 == 0 goto l0_%=;				\
 34	r1 = 0;						\
 35	*(u32*)(r10 - 4) = r1;				\
 36	r2 = r10;					\
 37	r2 += -4;					\
 38	r1 = r0;					\
 39	call %[bpf_map_lookup_elem];			\
 40l0_%=:	r0 = 0;						\
 41	exit;						\
 42"	:
 43	: __imm(bpf_map_lookup_elem),
 44	  __imm_addr(map_in_map)
 45	: __clobber_all);
 46}
 47
 48SEC("xdp")
 49__description("map in map state pruning")
 50__success __msg("processed 15 insns")
 51__log_level(2) __retval(0) __flag(BPF_F_TEST_STATE_FREQ)
 52__naked void map_in_map_state_pruning(void)
 53{
 54	asm volatile ("					\
 55	r1 = 0;						\
 56	*(u32*)(r10 - 4) = r1;				\
 57	r6 = r10;					\
 58	r6 += -4;					\
 59	r2 = r6;					\
 60	r1 = %[map_in_map] ll;				\
 61	call %[bpf_map_lookup_elem];			\
 62	if r0 != 0 goto l0_%=;				\
 63	exit;						\
 64l0_%=:	r2 = r6;					\
 65	r1 = r0;					\
 66	call %[bpf_map_lookup_elem];			\
 67	if r0 != 0 goto l1_%=;				\
 68	r2 = r6;					\
 69	r1 = %[map_in_map] ll;				\
 70	call %[bpf_map_lookup_elem];			\
 71	if r0 != 0 goto l2_%=;				\
 72	exit;						\
 73l2_%=:	r2 = r6;					\
 74	r1 = r0;					\
 75	call %[bpf_map_lookup_elem];			\
 76	if r0 != 0 goto l1_%=;				\
 77	exit;						\
 78l1_%=:	r0 = *(u32*)(r0 + 0);				\
 79	exit;						\
 80"	:
 81	: __imm(bpf_map_lookup_elem),
 82	  __imm_addr(map_in_map)
 83	: __clobber_all);
 84}
 85
 86SEC("socket")
 87__description("invalid inner map pointer")
 88__failure __msg("R1 pointer arithmetic on map_ptr prohibited")
 89__failure_unpriv
 90__naked void invalid_inner_map_pointer(void)
 91{
 92	asm volatile ("					\
 93	r1 = 0;						\
 94	*(u32*)(r10 - 4) = r1;				\
 95	r2 = r10;					\
 96	r2 += -4;					\
 97	r1 = %[map_in_map] ll;				\
 98	call %[bpf_map_lookup_elem];			\
 99	if r0 == 0 goto l0_%=;				\
100	r1 = 0;						\
101	*(u32*)(r10 - 4) = r1;				\
102	r2 = r10;					\
103	r2 += -4;					\
104	r1 = r0;					\
105	r1 += 8;					\
106	call %[bpf_map_lookup_elem];			\
107l0_%=:	r0 = 0;						\
108	exit;						\
109"	:
110	: __imm(bpf_map_lookup_elem),
111	  __imm_addr(map_in_map)
112	: __clobber_all);
113}
114
115SEC("socket")
116__description("forgot null checking on the inner map pointer")
117__failure __msg("R1 type=map_value_or_null expected=map_ptr")
118__failure_unpriv
119__naked void on_the_inner_map_pointer(void)
120{
121	asm volatile ("					\
122	r1 = 0;						\
123	*(u32*)(r10 - 4) = r1;				\
124	r2 = r10;					\
125	r2 += -4;					\
126	r1 = %[map_in_map] ll;				\
127	call %[bpf_map_lookup_elem];			\
128	r1 = 0;						\
129	*(u32*)(r10 - 4) = r1;				\
130	r2 = r10;					\
131	r2 += -4;					\
132	r1 = r0;					\
133	call %[bpf_map_lookup_elem];			\
134	r0 = 0;						\
135	exit;						\
136"	:
137	: __imm(bpf_map_lookup_elem),
138	  __imm_addr(map_in_map)
139	: __clobber_all);
140}
141
142SEC("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;					\
152l0_%=:	exit;						\
153"	:
154	: __imm(bpf_map_lookup_elem),
155	  __imm_addr(map_in_map)
156	: __clobber_all);
157}
158
159SEC("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;					\
174l0_%=:  exit;						\
175"	:
176	: __imm(bpf_map_lookup_elem),
177	  __imm_addr(map_in_map)
178	: __clobber_all);
179}
180
181SEC("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;						\
195l0_%=:	*(u64 *)(r10 -16) = r0;				\
196	r1 = *(u64 *)(r10 -16);				\
197	if r1 == 0 goto l1_%=;				\
198	exit;						\
199l1_%=:	r10 = 42;					\
200	exit;						\
201"	:
202	: __imm(bpf_map_lookup_elem),
203	  __imm_addr(map_in_map)
204	: __clobber_all);
205}
206
207struct {
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
218struct rb_ctx {
219	void *rb;
220	struct bpf_dynptr dptr;
221};
222
223static __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
240static __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
252SEC("socket")
253int 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
260char _license[] SEC("license") = "GPL";
~/ Read-only file preview.