1*d3305286SEduard Zingerman // SPDX-License-Identifier: GPL-2.0
2*d3305286SEduard Zingerman /* Converted from tools/testing/selftests/bpf/verifier/value_or_null.c */
3*d3305286SEduard Zingerman
4*d3305286SEduard Zingerman #include <linux/bpf.h>
5*d3305286SEduard Zingerman #include <bpf/bpf_helpers.h>
6*d3305286SEduard Zingerman #include "bpf_misc.h"
7*d3305286SEduard Zingerman
8*d3305286SEduard Zingerman #define MAX_ENTRIES 11
9*d3305286SEduard Zingerman
10*d3305286SEduard Zingerman struct test_val {
11*d3305286SEduard Zingerman unsigned int index;
12*d3305286SEduard Zingerman int foo[MAX_ENTRIES];
13*d3305286SEduard Zingerman };
14*d3305286SEduard Zingerman
15*d3305286SEduard Zingerman struct {
16*d3305286SEduard Zingerman __uint(type, BPF_MAP_TYPE_HASH);
17*d3305286SEduard Zingerman __uint(max_entries, 1);
18*d3305286SEduard Zingerman __type(key, long long);
19*d3305286SEduard Zingerman __type(value, struct test_val);
20*d3305286SEduard Zingerman } map_hash_48b SEC(".maps");
21*d3305286SEduard Zingerman
22*d3305286SEduard Zingerman struct {
23*d3305286SEduard Zingerman __uint(type, BPF_MAP_TYPE_HASH);
24*d3305286SEduard Zingerman __uint(max_entries, 1);
25*d3305286SEduard Zingerman __type(key, long long);
26*d3305286SEduard Zingerman __type(value, long long);
27*d3305286SEduard Zingerman } map_hash_8b SEC(".maps");
28*d3305286SEduard Zingerman
29*d3305286SEduard Zingerman SEC("tc")
30*d3305286SEduard Zingerman __description("multiple registers share map_lookup_elem result")
31*d3305286SEduard Zingerman __success __retval(0)
share_map_lookup_elem_result(void)32*d3305286SEduard Zingerman __naked void share_map_lookup_elem_result(void)
33*d3305286SEduard Zingerman {
34*d3305286SEduard Zingerman asm volatile (" \
35*d3305286SEduard Zingerman r1 = 10; \
36*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
37*d3305286SEduard Zingerman r2 = r10; \
38*d3305286SEduard Zingerman r2 += -8; \
39*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
40*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
41*d3305286SEduard Zingerman r4 = r0; \
42*d3305286SEduard Zingerman if r0 == 0 goto l0_%=; \
43*d3305286SEduard Zingerman r1 = 0; \
44*d3305286SEduard Zingerman *(u64*)(r4 + 0) = r1; \
45*d3305286SEduard Zingerman l0_%=: exit; \
46*d3305286SEduard Zingerman " :
47*d3305286SEduard Zingerman : __imm(bpf_map_lookup_elem),
48*d3305286SEduard Zingerman __imm_addr(map_hash_8b)
49*d3305286SEduard Zingerman : __clobber_all);
50*d3305286SEduard Zingerman }
51*d3305286SEduard Zingerman
52*d3305286SEduard Zingerman SEC("tc")
53*d3305286SEduard Zingerman __description("alu ops on ptr_to_map_value_or_null, 1")
54*d3305286SEduard Zingerman __failure __msg("R4 pointer arithmetic on map_value_or_null")
map_value_or_null_1(void)55*d3305286SEduard Zingerman __naked void map_value_or_null_1(void)
56*d3305286SEduard Zingerman {
57*d3305286SEduard Zingerman asm volatile (" \
58*d3305286SEduard Zingerman r1 = 10; \
59*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
60*d3305286SEduard Zingerman r2 = r10; \
61*d3305286SEduard Zingerman r2 += -8; \
62*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
63*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
64*d3305286SEduard Zingerman r4 = r0; \
65*d3305286SEduard Zingerman r4 += -2; \
66*d3305286SEduard Zingerman r4 += 2; \
67*d3305286SEduard Zingerman if r0 == 0 goto l0_%=; \
68*d3305286SEduard Zingerman r1 = 0; \
69*d3305286SEduard Zingerman *(u64*)(r4 + 0) = r1; \
70*d3305286SEduard Zingerman l0_%=: exit; \
71*d3305286SEduard Zingerman " :
72*d3305286SEduard Zingerman : __imm(bpf_map_lookup_elem),
73*d3305286SEduard Zingerman __imm_addr(map_hash_8b)
74*d3305286SEduard Zingerman : __clobber_all);
75*d3305286SEduard Zingerman }
76*d3305286SEduard Zingerman
77*d3305286SEduard Zingerman SEC("tc")
78*d3305286SEduard Zingerman __description("alu ops on ptr_to_map_value_or_null, 2")
79*d3305286SEduard Zingerman __failure __msg("R4 pointer arithmetic on map_value_or_null")
map_value_or_null_2(void)80*d3305286SEduard Zingerman __naked void map_value_or_null_2(void)
81*d3305286SEduard Zingerman {
82*d3305286SEduard Zingerman asm volatile (" \
83*d3305286SEduard Zingerman r1 = 10; \
84*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
85*d3305286SEduard Zingerman r2 = r10; \
86*d3305286SEduard Zingerman r2 += -8; \
87*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
88*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
89*d3305286SEduard Zingerman r4 = r0; \
90*d3305286SEduard Zingerman r4 &= -1; \
91*d3305286SEduard Zingerman if r0 == 0 goto l0_%=; \
92*d3305286SEduard Zingerman r1 = 0; \
93*d3305286SEduard Zingerman *(u64*)(r4 + 0) = r1; \
94*d3305286SEduard Zingerman l0_%=: exit; \
95*d3305286SEduard Zingerman " :
96*d3305286SEduard Zingerman : __imm(bpf_map_lookup_elem),
97*d3305286SEduard Zingerman __imm_addr(map_hash_8b)
98*d3305286SEduard Zingerman : __clobber_all);
99*d3305286SEduard Zingerman }
100*d3305286SEduard Zingerman
101*d3305286SEduard Zingerman SEC("tc")
102*d3305286SEduard Zingerman __description("alu ops on ptr_to_map_value_or_null, 3")
103*d3305286SEduard Zingerman __failure __msg("R4 pointer arithmetic on map_value_or_null")
map_value_or_null_3(void)104*d3305286SEduard Zingerman __naked void map_value_or_null_3(void)
105*d3305286SEduard Zingerman {
106*d3305286SEduard Zingerman asm volatile (" \
107*d3305286SEduard Zingerman r1 = 10; \
108*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
109*d3305286SEduard Zingerman r2 = r10; \
110*d3305286SEduard Zingerman r2 += -8; \
111*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
112*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
113*d3305286SEduard Zingerman r4 = r0; \
114*d3305286SEduard Zingerman r4 <<= 1; \
115*d3305286SEduard Zingerman if r0 == 0 goto l0_%=; \
116*d3305286SEduard Zingerman r1 = 0; \
117*d3305286SEduard Zingerman *(u64*)(r4 + 0) = r1; \
118*d3305286SEduard Zingerman l0_%=: exit; \
119*d3305286SEduard Zingerman " :
120*d3305286SEduard Zingerman : __imm(bpf_map_lookup_elem),
121*d3305286SEduard Zingerman __imm_addr(map_hash_8b)
122*d3305286SEduard Zingerman : __clobber_all);
123*d3305286SEduard Zingerman }
124*d3305286SEduard Zingerman
125*d3305286SEduard Zingerman SEC("tc")
126*d3305286SEduard Zingerman __description("invalid memory access with multiple map_lookup_elem calls")
127*d3305286SEduard Zingerman __failure __msg("R4 !read_ok")
multiple_map_lookup_elem_calls(void)128*d3305286SEduard Zingerman __naked void multiple_map_lookup_elem_calls(void)
129*d3305286SEduard Zingerman {
130*d3305286SEduard Zingerman asm volatile (" \
131*d3305286SEduard Zingerman r1 = 10; \
132*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
133*d3305286SEduard Zingerman r2 = r10; \
134*d3305286SEduard Zingerman r2 += -8; \
135*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
136*d3305286SEduard Zingerman r8 = r1; \
137*d3305286SEduard Zingerman r7 = r2; \
138*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
139*d3305286SEduard Zingerman r4 = r0; \
140*d3305286SEduard Zingerman r1 = r8; \
141*d3305286SEduard Zingerman r2 = r7; \
142*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
143*d3305286SEduard Zingerman if r0 == 0 goto l0_%=; \
144*d3305286SEduard Zingerman r1 = 0; \
145*d3305286SEduard Zingerman *(u64*)(r4 + 0) = r1; \
146*d3305286SEduard Zingerman l0_%=: exit; \
147*d3305286SEduard Zingerman " :
148*d3305286SEduard Zingerman : __imm(bpf_map_lookup_elem),
149*d3305286SEduard Zingerman __imm_addr(map_hash_8b)
150*d3305286SEduard Zingerman : __clobber_all);
151*d3305286SEduard Zingerman }
152*d3305286SEduard Zingerman
153*d3305286SEduard Zingerman SEC("tc")
154*d3305286SEduard Zingerman __description("valid indirect map_lookup_elem access with 2nd lookup in branch")
155*d3305286SEduard Zingerman __success __retval(0)
with_2nd_lookup_in_branch(void)156*d3305286SEduard Zingerman __naked void with_2nd_lookup_in_branch(void)
157*d3305286SEduard Zingerman {
158*d3305286SEduard Zingerman asm volatile (" \
159*d3305286SEduard Zingerman r1 = 10; \
160*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
161*d3305286SEduard Zingerman r2 = r10; \
162*d3305286SEduard Zingerman r2 += -8; \
163*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
164*d3305286SEduard Zingerman r8 = r1; \
165*d3305286SEduard Zingerman r7 = r2; \
166*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
167*d3305286SEduard Zingerman r2 = 10; \
168*d3305286SEduard Zingerman if r2 != 0 goto l0_%=; \
169*d3305286SEduard Zingerman r1 = r8; \
170*d3305286SEduard Zingerman r2 = r7; \
171*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
172*d3305286SEduard Zingerman l0_%=: r4 = r0; \
173*d3305286SEduard Zingerman if r0 == 0 goto l1_%=; \
174*d3305286SEduard Zingerman r1 = 0; \
175*d3305286SEduard Zingerman *(u64*)(r4 + 0) = r1; \
176*d3305286SEduard Zingerman l1_%=: exit; \
177*d3305286SEduard Zingerman " :
178*d3305286SEduard Zingerman : __imm(bpf_map_lookup_elem),
179*d3305286SEduard Zingerman __imm_addr(map_hash_8b)
180*d3305286SEduard Zingerman : __clobber_all);
181*d3305286SEduard Zingerman }
182*d3305286SEduard Zingerman
183*d3305286SEduard Zingerman SEC("socket")
184*d3305286SEduard Zingerman __description("invalid map access from else condition")
185*d3305286SEduard Zingerman __failure __msg("R0 unbounded memory access")
186*d3305286SEduard Zingerman __failure_unpriv __msg_unpriv("R0 leaks addr")
__flag(BPF_F_ANY_ALIGNMENT)187*d3305286SEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
188*d3305286SEduard Zingerman __naked void map_access_from_else_condition(void)
189*d3305286SEduard Zingerman {
190*d3305286SEduard Zingerman asm volatile (" \
191*d3305286SEduard Zingerman r1 = 0; \
192*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
193*d3305286SEduard Zingerman r2 = r10; \
194*d3305286SEduard Zingerman r2 += -8; \
195*d3305286SEduard Zingerman r1 = %[map_hash_48b] ll; \
196*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
197*d3305286SEduard Zingerman if r0 == 0 goto l0_%=; \
198*d3305286SEduard Zingerman r1 = *(u32*)(r0 + 0); \
199*d3305286SEduard Zingerman if r1 >= %[__imm_0] goto l1_%=; \
200*d3305286SEduard Zingerman r1 += 1; \
201*d3305286SEduard Zingerman l1_%=: r1 <<= 2; \
202*d3305286SEduard Zingerman r0 += r1; \
203*d3305286SEduard Zingerman r1 = %[test_val_foo]; \
204*d3305286SEduard Zingerman *(u64*)(r0 + 0) = r1; \
205*d3305286SEduard Zingerman l0_%=: exit; \
206*d3305286SEduard Zingerman " :
207*d3305286SEduard Zingerman : __imm(bpf_map_lookup_elem),
208*d3305286SEduard Zingerman __imm_addr(map_hash_48b),
209*d3305286SEduard Zingerman __imm_const(__imm_0, MAX_ENTRIES-1),
210*d3305286SEduard Zingerman __imm_const(test_val_foo, offsetof(struct test_val, foo))
211*d3305286SEduard Zingerman : __clobber_all);
212*d3305286SEduard Zingerman }
213*d3305286SEduard Zingerman
214*d3305286SEduard Zingerman SEC("tc")
215*d3305286SEduard Zingerman __description("map lookup and null branch prediction")
216*d3305286SEduard Zingerman __success __retval(0)
lookup_and_null_branch_prediction(void)217*d3305286SEduard Zingerman __naked void lookup_and_null_branch_prediction(void)
218*d3305286SEduard Zingerman {
219*d3305286SEduard Zingerman asm volatile (" \
220*d3305286SEduard Zingerman r1 = 10; \
221*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
222*d3305286SEduard Zingerman r2 = r10; \
223*d3305286SEduard Zingerman r2 += -8; \
224*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
225*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
226*d3305286SEduard Zingerman r6 = r0; \
227*d3305286SEduard Zingerman if r6 == 0 goto l0_%=; \
228*d3305286SEduard Zingerman if r6 != 0 goto l0_%=; \
229*d3305286SEduard Zingerman r10 += 10; \
230*d3305286SEduard Zingerman l0_%=: exit; \
231*d3305286SEduard Zingerman " :
232*d3305286SEduard Zingerman : __imm(bpf_map_lookup_elem),
233*d3305286SEduard Zingerman __imm_addr(map_hash_8b)
234*d3305286SEduard Zingerman : __clobber_all);
235*d3305286SEduard Zingerman }
236*d3305286SEduard Zingerman
237*d3305286SEduard Zingerman SEC("cgroup/skb")
238*d3305286SEduard Zingerman __description("MAP_VALUE_OR_NULL check_ids() in regsafe()")
239*d3305286SEduard Zingerman __failure __msg("R8 invalid mem access 'map_value_or_null'")
240*d3305286SEduard Zingerman __failure_unpriv __msg_unpriv("")
__flag(BPF_F_TEST_STATE_FREQ)241*d3305286SEduard Zingerman __flag(BPF_F_TEST_STATE_FREQ)
242*d3305286SEduard Zingerman __naked void null_check_ids_in_regsafe(void)
243*d3305286SEduard Zingerman {
244*d3305286SEduard Zingerman asm volatile (" \
245*d3305286SEduard Zingerman r1 = 0; \
246*d3305286SEduard Zingerman *(u64*)(r10 - 8) = r1; \
247*d3305286SEduard Zingerman /* r9 = map_lookup_elem(...) */ \
248*d3305286SEduard Zingerman r2 = r10; \
249*d3305286SEduard Zingerman r2 += -8; \
250*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
251*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
252*d3305286SEduard Zingerman r9 = r0; \
253*d3305286SEduard Zingerman /* r8 = map_lookup_elem(...) */ \
254*d3305286SEduard Zingerman r2 = r10; \
255*d3305286SEduard Zingerman r2 += -8; \
256*d3305286SEduard Zingerman r1 = %[map_hash_8b] ll; \
257*d3305286SEduard Zingerman call %[bpf_map_lookup_elem]; \
258*d3305286SEduard Zingerman r8 = r0; \
259*d3305286SEduard Zingerman /* r7 = ktime_get_ns() */ \
260*d3305286SEduard Zingerman call %[bpf_ktime_get_ns]; \
261*d3305286SEduard Zingerman r7 = r0; \
262*d3305286SEduard Zingerman /* r6 = ktime_get_ns() */ \
263*d3305286SEduard Zingerman call %[bpf_ktime_get_ns]; \
264*d3305286SEduard Zingerman r6 = r0; \
265*d3305286SEduard Zingerman /* if r6 > r7 goto +1 ; no new information about the state is derived from\
266*d3305286SEduard Zingerman * ; this check, thus produced verifier states differ\
267*d3305286SEduard Zingerman * ; only in 'insn_idx' \
268*d3305286SEduard Zingerman * r9 = r8 ; optionally share ID between r9 and r8\
269*d3305286SEduard Zingerman */ \
270*d3305286SEduard Zingerman if r6 > r7 goto l0_%=; \
271*d3305286SEduard Zingerman r9 = r8; \
272*d3305286SEduard Zingerman l0_%=: /* if r9 == 0 goto <exit> */ \
273*d3305286SEduard Zingerman if r9 == 0 goto l1_%=; \
274*d3305286SEduard Zingerman /* read map value via r8, this is not always \
275*d3305286SEduard Zingerman * safe because r8 might be not equal to r9. \
276*d3305286SEduard Zingerman */ \
277*d3305286SEduard Zingerman r0 = *(u64*)(r8 + 0); \
278*d3305286SEduard Zingerman l1_%=: /* exit 0 */ \
279*d3305286SEduard Zingerman r0 = 0; \
280*d3305286SEduard Zingerman exit; \
281*d3305286SEduard Zingerman " :
282*d3305286SEduard Zingerman : __imm(bpf_ktime_get_ns),
283*d3305286SEduard Zingerman __imm(bpf_map_lookup_elem),
284*d3305286SEduard Zingerman __imm_addr(map_hash_8b)
285*d3305286SEduard Zingerman : __clobber_all);
286*d3305286SEduard Zingerman }
287*d3305286SEduard Zingerman
288*d3305286SEduard Zingerman char _license[] SEC("license") = "GPL";
289