1// SPDX-License-Identifier: GPL-2.0
2/* Converted from tools/testing/selftests/bpf/verifier/map_ptr_mixing.c */
3
4#include <linux/bpf.h>
5#include <bpf/bpf_helpers.h>
6#include "bpf_misc.h"
7
8#define MAX_ENTRIES 11
9
10struct test_val {
11 unsigned int index;
12 int foo[MAX_ENTRIES];
13};
14
15struct {
16 __uint(type, BPF_MAP_TYPE_ARRAY);
17 __uint(max_entries, 1);
18 __type(key, int);
19 __type(value, struct test_val);
20} map_array_48b SEC(".maps");
21
22struct {
23 __uint(type, BPF_MAP_TYPE_HASH);
24 __uint(max_entries, 1);
25 __type(key, long long);
26 __type(value, struct test_val);
27} map_hash_48b SEC(".maps");
28
29struct {
30 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
31 __uint(max_entries, 1);
32 __type(key, int);
33 __type(value, int);
34 __array(values, struct {
35 __uint(type, BPF_MAP_TYPE_ARRAY);
36 __uint(max_entries, 1);
37 __type(key, int);
38 __type(value, int);
39 });
40} map_in_map SEC(".maps");
41
42void dummy_prog_42_socket(void);
43void dummy_prog_24_socket(void);
44void dummy_prog_loop1_socket(void);
45void dummy_prog_loop2_socket(void);
46
47struct {
48 __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
49 __uint(max_entries, 4);
50 __uint(key_size, sizeof(int));
51 __array(values, void (void));
52} map_prog1_socket SEC(".maps") = {
53 .values = {
54 [0] = (void *)&dummy_prog_42_socket,
55 [1] = (void *)&dummy_prog_loop1_socket,
56 [2] = (void *)&dummy_prog_24_socket,
57 },
58};
59
60struct {
61 __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
62 __uint(max_entries, 8);
63 __uint(key_size, sizeof(int));
64 __array(values, void (void));
65} map_prog2_socket SEC(".maps") = {
66 .values = {
67 [1] = (void *)&dummy_prog_loop2_socket,
68 [2] = (void *)&dummy_prog_24_socket,
69 [7] = (void *)&dummy_prog_42_socket,
70 },
71};
72
73SEC("socket")
74__auxiliary __auxiliary_unpriv
75__naked void dummy_prog_42_socket(void)
76{
77 asm volatile ("r0 = 42; exit;");
78}
79
80SEC("socket")
81__auxiliary __auxiliary_unpriv
82__naked void dummy_prog_24_socket(void)
83{
84 asm volatile ("r0 = 24; exit;");
85}
86
87SEC("socket")
88__auxiliary __auxiliary_unpriv
89__naked void dummy_prog_loop1_socket(void)
90{
91 asm volatile (" \
92 r3 = 1; \
93 r2 = %[map_prog1_socket] ll; \
94 call %[bpf_tail_call]; \
95 r0 = 41; \
96 exit; \
97" :
98 : __imm(bpf_tail_call),
99 __imm_addr(map_prog1_socket)
100 : __clobber_all);
101}
102
103SEC("socket")
104__auxiliary __auxiliary_unpriv
105__naked void dummy_prog_loop2_socket(void)
106{
107 asm volatile (" \
108 r3 = 1; \
109 r2 = %[map_prog2_socket] ll; \
110 call %[bpf_tail_call]; \
111 r0 = 41; \
112 exit; \
113" :
114 : __imm(bpf_tail_call),
115 __imm_addr(map_prog2_socket)
116 : __clobber_all);
117}
118
119SEC("tc")
120__description("calls: two calls returning different map pointers for lookup (hash, array)")
121__success __retval(1)
122__naked void pointers_for_lookup_hash_array(void)
123{
124 asm volatile (" \
125 /* main prog */ \
126 if r1 != 0 goto l0_%=; \
127 call pointers_for_lookup_hash_array__1; \
128 goto l1_%=; \
129l0_%=: call pointers_for_lookup_hash_array__2; \
130l1_%=: r1 = r0; \
131 r2 = 0; \
132 *(u64*)(r10 - 8) = r2; \
133 r2 = r10; \
134 r2 += -8; \
135 call %[bpf_map_lookup_elem]; \
136 if r0 == 0 goto l2_%=; \
137 r1 = %[test_val_foo]; \
138 *(u64*)(r0 + 0) = r1; \
139 r0 = 1; \
140l2_%=: exit; \
141" :
142 : __imm(bpf_map_lookup_elem),
143 __imm_const(test_val_foo, offsetof(struct test_val, foo))
144 : __clobber_all);
145}
146
147static __naked __noinline __attribute__((used))
148void pointers_for_lookup_hash_array__1(void)
149{
150 asm volatile (" \
151 r0 = %[map_hash_48b] ll; \
152 exit; \
153" :
154 : __imm_addr(map_hash_48b)
155 : __clobber_all);
156}
157
158static __naked __noinline __attribute__((used))
159void pointers_for_lookup_hash_array__2(void)
160{
161 asm volatile (" \
162 r0 = %[map_array_48b] ll; \
163 exit; \
164" :
165 : __imm_addr(map_array_48b)
166 : __clobber_all);
167}
168
169SEC("tc")
170__description("calls: two calls returning different map pointers for lookup (hash, map in map)")
171__failure __msg("only read from bpf_array is supported")
172__naked void lookup_hash_map_in_map(void)
173{
174 asm volatile (" \
175 /* main prog */ \
176 if r1 != 0 goto l0_%=; \
177 call lookup_hash_map_in_map__1; \
178 goto l1_%=; \
179l0_%=: call lookup_hash_map_in_map__2; \
180l1_%=: r1 = r0; \
181 r2 = 0; \
182 *(u64*)(r10 - 8) = r2; \
183 r2 = r10; \
184 r2 += -8; \
185 call %[bpf_map_lookup_elem]; \
186 if r0 == 0 goto l2_%=; \
187 r1 = %[test_val_foo]; \
188 *(u64*)(r0 + 0) = r1; \
189 r0 = 1; \
190l2_%=: exit; \
191" :
192 : __imm(bpf_map_lookup_elem),
193 __imm_const(test_val_foo, offsetof(struct test_val, foo))
194 : __clobber_all);
195}
196
197static __naked __noinline __attribute__((used))
198void lookup_hash_map_in_map__1(void)
199{
200 asm volatile (" \
201 r0 = %[map_array_48b] ll; \
202 exit; \
203" :
204 : __imm_addr(map_array_48b)
205 : __clobber_all);
206}
207
208static __naked __noinline __attribute__((used))
209void lookup_hash_map_in_map__2(void)
210{
211 asm volatile (" \
212 r0 = %[map_in_map] ll; \
213 exit; \
214" :
215 : __imm_addr(map_in_map)
216 : __clobber_all);
217}
218
219SEC("socket")
220__description("cond: two branches returning different map pointers for lookup (tail, tail)")
221__success __failure_unpriv __msg_unpriv("tail_call abusing map_ptr")
222__retval(42)
223__naked void pointers_for_lookup_tail_tail_1(void)
224{
225 asm volatile (" \
226 r6 = *(u32*)(r1 + %[__sk_buff_mark]); \
227 if r6 != 0 goto l0_%=; \
228 r2 = %[map_prog2_socket] ll; \
229 goto l1_%=; \
230l0_%=: r2 = %[map_prog1_socket] ll; \
231l1_%=: r3 = 7; \
232 call %[bpf_tail_call]; \
233 r0 = 1; \
234 exit; \
235" :
236 : __imm(bpf_tail_call),
237 __imm_addr(map_prog1_socket),
238 __imm_addr(map_prog2_socket),
239 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
240 : __clobber_all);
241}
242
243SEC("socket")
244__description("cond: two branches returning same map pointers for lookup (tail, tail)")
245__success __success_unpriv __retval(42)
246__naked void pointers_for_lookup_tail_tail_2(void)
247{
248 asm volatile (" \
249 r6 = *(u32*)(r1 + %[__sk_buff_mark]); \
250 if r6 == 0 goto l0_%=; \
251 r2 = %[map_prog2_socket] ll; \
252 goto l1_%=; \
253l0_%=: r2 = %[map_prog2_socket] ll; \
254l1_%=: r3 = 7; \
255 call %[bpf_tail_call]; \
256 r0 = 1; \
257 exit; \
258" :
259 : __imm(bpf_tail_call),
260 __imm_addr(map_prog2_socket),
261 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
262 : __clobber_all);
263}
264
265char _license[] SEC("license") = "GPL";
266

source code of linux/tools/testing/selftests/bpf/progs/verifier_map_ptr_mixing.c