1*57400dccSAndrii Nakryiko // SPDX-License-Identifier: GPL-2.0
2*57400dccSAndrii Nakryiko /* Copyright (c) 2022 Facebook */
3*57400dccSAndrii Nakryiko
4*57400dccSAndrii Nakryiko #include <errno.h>
5*57400dccSAndrii Nakryiko #include <string.h>
6*57400dccSAndrii Nakryiko #include <linux/bpf.h>
7*57400dccSAndrii Nakryiko #include <bpf/bpf_helpers.h>
8*57400dccSAndrii Nakryiko #include "bpf_misc.h"
9*57400dccSAndrii Nakryiko
10*57400dccSAndrii Nakryiko char _license[] SEC("license") = "GPL";
11*57400dccSAndrii Nakryiko
12*57400dccSAndrii Nakryiko #define ITER_HELPERS \
13*57400dccSAndrii Nakryiko __imm(bpf_iter_num_new), \
14*57400dccSAndrii Nakryiko __imm(bpf_iter_num_next), \
15*57400dccSAndrii Nakryiko __imm(bpf_iter_num_destroy)
16*57400dccSAndrii Nakryiko
17*57400dccSAndrii Nakryiko SEC("?raw_tp")
18*57400dccSAndrii Nakryiko __success
force_clang_to_emit_btf_for_externs(void * ctx)19*57400dccSAndrii Nakryiko int force_clang_to_emit_btf_for_externs(void *ctx)
20*57400dccSAndrii Nakryiko {
21*57400dccSAndrii Nakryiko /* we need this as a workaround to enforce compiler emitting BTF
22*57400dccSAndrii Nakryiko * information for bpf_iter_num_{new,next,destroy}() kfuncs,
23*57400dccSAndrii Nakryiko * as, apparently, it doesn't emit it for symbols only referenced from
24*57400dccSAndrii Nakryiko * assembly (or cleanup attribute, for that matter, as well)
25*57400dccSAndrii Nakryiko */
26*57400dccSAndrii Nakryiko bpf_repeat(0);
27*57400dccSAndrii Nakryiko
28*57400dccSAndrii Nakryiko return 0;
29*57400dccSAndrii Nakryiko }
30*57400dccSAndrii Nakryiko
31*57400dccSAndrii Nakryiko SEC("?raw_tp")
32*57400dccSAndrii Nakryiko __success __log_level(2)
33*57400dccSAndrii Nakryiko __msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")
create_and_destroy(void * ctx)34*57400dccSAndrii Nakryiko int create_and_destroy(void *ctx)
35*57400dccSAndrii Nakryiko {
36*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
37*57400dccSAndrii Nakryiko
38*57400dccSAndrii Nakryiko asm volatile (
39*57400dccSAndrii Nakryiko /* create iterator */
40*57400dccSAndrii Nakryiko "r1 = %[iter];"
41*57400dccSAndrii Nakryiko "r2 = 0;"
42*57400dccSAndrii Nakryiko "r3 = 1000;"
43*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
44*57400dccSAndrii Nakryiko /* destroy iterator */
45*57400dccSAndrii Nakryiko "r1 = %[iter];"
46*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
47*57400dccSAndrii Nakryiko :
48*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
49*57400dccSAndrii Nakryiko : __clobber_common
50*57400dccSAndrii Nakryiko );
51*57400dccSAndrii Nakryiko
52*57400dccSAndrii Nakryiko return 0;
53*57400dccSAndrii Nakryiko }
54*57400dccSAndrii Nakryiko
55*57400dccSAndrii Nakryiko SEC("?raw_tp")
56*57400dccSAndrii Nakryiko __failure __msg("Unreleased reference id=1")
create_and_forget_to_destroy_fail(void * ctx)57*57400dccSAndrii Nakryiko int create_and_forget_to_destroy_fail(void *ctx)
58*57400dccSAndrii Nakryiko {
59*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
60*57400dccSAndrii Nakryiko
61*57400dccSAndrii Nakryiko asm volatile (
62*57400dccSAndrii Nakryiko /* create iterator */
63*57400dccSAndrii Nakryiko "r1 = %[iter];"
64*57400dccSAndrii Nakryiko "r2 = 0;"
65*57400dccSAndrii Nakryiko "r3 = 1000;"
66*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
67*57400dccSAndrii Nakryiko :
68*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
69*57400dccSAndrii Nakryiko : __clobber_common
70*57400dccSAndrii Nakryiko );
71*57400dccSAndrii Nakryiko
72*57400dccSAndrii Nakryiko return 0;
73*57400dccSAndrii Nakryiko }
74*57400dccSAndrii Nakryiko
75*57400dccSAndrii Nakryiko SEC("?raw_tp")
76*57400dccSAndrii Nakryiko __failure __msg("expected an initialized iter_num as arg #1")
destroy_without_creating_fail(void * ctx)77*57400dccSAndrii Nakryiko int destroy_without_creating_fail(void *ctx)
78*57400dccSAndrii Nakryiko {
79*57400dccSAndrii Nakryiko /* init with zeros to stop verifier complaining about uninit stack */
80*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
81*57400dccSAndrii Nakryiko
82*57400dccSAndrii Nakryiko asm volatile (
83*57400dccSAndrii Nakryiko "r1 = %[iter];"
84*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
85*57400dccSAndrii Nakryiko :
86*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
87*57400dccSAndrii Nakryiko : __clobber_common
88*57400dccSAndrii Nakryiko );
89*57400dccSAndrii Nakryiko
90*57400dccSAndrii Nakryiko return 0;
91*57400dccSAndrii Nakryiko }
92*57400dccSAndrii Nakryiko
93*57400dccSAndrii Nakryiko SEC("?raw_tp")
94*57400dccSAndrii Nakryiko __failure __msg("expected an initialized iter_num as arg #1")
compromise_iter_w_direct_write_fail(void * ctx)95*57400dccSAndrii Nakryiko int compromise_iter_w_direct_write_fail(void *ctx)
96*57400dccSAndrii Nakryiko {
97*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
98*57400dccSAndrii Nakryiko
99*57400dccSAndrii Nakryiko asm volatile (
100*57400dccSAndrii Nakryiko /* create iterator */
101*57400dccSAndrii Nakryiko "r1 = %[iter];"
102*57400dccSAndrii Nakryiko "r2 = 0;"
103*57400dccSAndrii Nakryiko "r3 = 1000;"
104*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
105*57400dccSAndrii Nakryiko
106*57400dccSAndrii Nakryiko /* directly write over first half of iter state */
107*57400dccSAndrii Nakryiko "*(u64 *)(%[iter] + 0) = r0;"
108*57400dccSAndrii Nakryiko
109*57400dccSAndrii Nakryiko /* (attempt to) destroy iterator */
110*57400dccSAndrii Nakryiko "r1 = %[iter];"
111*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
112*57400dccSAndrii Nakryiko :
113*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
114*57400dccSAndrii Nakryiko : __clobber_common
115*57400dccSAndrii Nakryiko );
116*57400dccSAndrii Nakryiko
117*57400dccSAndrii Nakryiko return 0;
118*57400dccSAndrii Nakryiko }
119*57400dccSAndrii Nakryiko
120*57400dccSAndrii Nakryiko SEC("?raw_tp")
121*57400dccSAndrii Nakryiko __failure __msg("Unreleased reference id=1")
compromise_iter_w_direct_write_and_skip_destroy_fail(void * ctx)122*57400dccSAndrii Nakryiko int compromise_iter_w_direct_write_and_skip_destroy_fail(void *ctx)
123*57400dccSAndrii Nakryiko {
124*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
125*57400dccSAndrii Nakryiko
126*57400dccSAndrii Nakryiko asm volatile (
127*57400dccSAndrii Nakryiko /* create iterator */
128*57400dccSAndrii Nakryiko "r1 = %[iter];"
129*57400dccSAndrii Nakryiko "r2 = 0;"
130*57400dccSAndrii Nakryiko "r3 = 1000;"
131*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
132*57400dccSAndrii Nakryiko
133*57400dccSAndrii Nakryiko /* directly write over first half of iter state */
134*57400dccSAndrii Nakryiko "*(u64 *)(%[iter] + 0) = r0;"
135*57400dccSAndrii Nakryiko
136*57400dccSAndrii Nakryiko /* don't destroy iter, leaking ref, which should fail */
137*57400dccSAndrii Nakryiko :
138*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
139*57400dccSAndrii Nakryiko : __clobber_common
140*57400dccSAndrii Nakryiko );
141*57400dccSAndrii Nakryiko
142*57400dccSAndrii Nakryiko return 0;
143*57400dccSAndrii Nakryiko }
144*57400dccSAndrii Nakryiko
145*57400dccSAndrii Nakryiko SEC("?raw_tp")
146*57400dccSAndrii Nakryiko __failure __msg("expected an initialized iter_num as arg #1")
compromise_iter_w_helper_write_fail(void * ctx)147*57400dccSAndrii Nakryiko int compromise_iter_w_helper_write_fail(void *ctx)
148*57400dccSAndrii Nakryiko {
149*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
150*57400dccSAndrii Nakryiko
151*57400dccSAndrii Nakryiko asm volatile (
152*57400dccSAndrii Nakryiko /* create iterator */
153*57400dccSAndrii Nakryiko "r1 = %[iter];"
154*57400dccSAndrii Nakryiko "r2 = 0;"
155*57400dccSAndrii Nakryiko "r3 = 1000;"
156*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
157*57400dccSAndrii Nakryiko
158*57400dccSAndrii Nakryiko /* overwrite 8th byte with bpf_probe_read_kernel() */
159*57400dccSAndrii Nakryiko "r1 = %[iter];"
160*57400dccSAndrii Nakryiko "r1 += 7;"
161*57400dccSAndrii Nakryiko "r2 = 1;"
162*57400dccSAndrii Nakryiko "r3 = 0;" /* NULL */
163*57400dccSAndrii Nakryiko "call %[bpf_probe_read_kernel];"
164*57400dccSAndrii Nakryiko
165*57400dccSAndrii Nakryiko /* (attempt to) destroy iterator */
166*57400dccSAndrii Nakryiko "r1 = %[iter];"
167*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
168*57400dccSAndrii Nakryiko :
169*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS, __imm(bpf_probe_read_kernel)
170*57400dccSAndrii Nakryiko : __clobber_common
171*57400dccSAndrii Nakryiko );
172*57400dccSAndrii Nakryiko
173*57400dccSAndrii Nakryiko return 0;
174*57400dccSAndrii Nakryiko }
175*57400dccSAndrii Nakryiko
subprog_with_iter(void)176*57400dccSAndrii Nakryiko static __noinline void subprog_with_iter(void)
177*57400dccSAndrii Nakryiko {
178*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
179*57400dccSAndrii Nakryiko
180*57400dccSAndrii Nakryiko bpf_iter_num_new(&iter, 0, 1);
181*57400dccSAndrii Nakryiko
182*57400dccSAndrii Nakryiko return;
183*57400dccSAndrii Nakryiko }
184*57400dccSAndrii Nakryiko
185*57400dccSAndrii Nakryiko SEC("?raw_tp")
186*57400dccSAndrii Nakryiko __failure
187*57400dccSAndrii Nakryiko /* ensure there was a call to subprog, which might happen without __noinline */
188*57400dccSAndrii Nakryiko __msg("returning from callee:")
189*57400dccSAndrii Nakryiko __msg("Unreleased reference id=1")
leak_iter_from_subprog_fail(void * ctx)190*57400dccSAndrii Nakryiko int leak_iter_from_subprog_fail(void *ctx)
191*57400dccSAndrii Nakryiko {
192*57400dccSAndrii Nakryiko subprog_with_iter();
193*57400dccSAndrii Nakryiko
194*57400dccSAndrii Nakryiko return 0;
195*57400dccSAndrii Nakryiko }
196*57400dccSAndrii Nakryiko
197*57400dccSAndrii Nakryiko SEC("?raw_tp")
198*57400dccSAndrii Nakryiko __success __log_level(2)
199*57400dccSAndrii Nakryiko __msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)")
valid_stack_reuse(void * ctx)200*57400dccSAndrii Nakryiko int valid_stack_reuse(void *ctx)
201*57400dccSAndrii Nakryiko {
202*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
203*57400dccSAndrii Nakryiko
204*57400dccSAndrii Nakryiko asm volatile (
205*57400dccSAndrii Nakryiko /* create iterator */
206*57400dccSAndrii Nakryiko "r1 = %[iter];"
207*57400dccSAndrii Nakryiko "r2 = 0;"
208*57400dccSAndrii Nakryiko "r3 = 1000;"
209*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
210*57400dccSAndrii Nakryiko /* destroy iterator */
211*57400dccSAndrii Nakryiko "r1 = %[iter];"
212*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
213*57400dccSAndrii Nakryiko
214*57400dccSAndrii Nakryiko /* now reuse same stack slots */
215*57400dccSAndrii Nakryiko
216*57400dccSAndrii Nakryiko /* create iterator */
217*57400dccSAndrii Nakryiko "r1 = %[iter];"
218*57400dccSAndrii Nakryiko "r2 = 0;"
219*57400dccSAndrii Nakryiko "r3 = 1000;"
220*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
221*57400dccSAndrii Nakryiko /* destroy iterator */
222*57400dccSAndrii Nakryiko "r1 = %[iter];"
223*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
224*57400dccSAndrii Nakryiko :
225*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
226*57400dccSAndrii Nakryiko : __clobber_common
227*57400dccSAndrii Nakryiko );
228*57400dccSAndrii Nakryiko
229*57400dccSAndrii Nakryiko return 0;
230*57400dccSAndrii Nakryiko }
231*57400dccSAndrii Nakryiko
232*57400dccSAndrii Nakryiko SEC("?raw_tp")
233*57400dccSAndrii Nakryiko __failure __msg("expected uninitialized iter_num as arg #1")
double_create_fail(void * ctx)234*57400dccSAndrii Nakryiko int double_create_fail(void *ctx)
235*57400dccSAndrii Nakryiko {
236*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
237*57400dccSAndrii Nakryiko
238*57400dccSAndrii Nakryiko asm volatile (
239*57400dccSAndrii Nakryiko /* create iterator */
240*57400dccSAndrii Nakryiko "r1 = %[iter];"
241*57400dccSAndrii Nakryiko "r2 = 0;"
242*57400dccSAndrii Nakryiko "r3 = 1000;"
243*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
244*57400dccSAndrii Nakryiko /* (attempt to) create iterator again */
245*57400dccSAndrii Nakryiko "r1 = %[iter];"
246*57400dccSAndrii Nakryiko "r2 = 0;"
247*57400dccSAndrii Nakryiko "r3 = 1000;"
248*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
249*57400dccSAndrii Nakryiko /* destroy iterator */
250*57400dccSAndrii Nakryiko "r1 = %[iter];"
251*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
252*57400dccSAndrii Nakryiko :
253*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
254*57400dccSAndrii Nakryiko : __clobber_common
255*57400dccSAndrii Nakryiko );
256*57400dccSAndrii Nakryiko
257*57400dccSAndrii Nakryiko return 0;
258*57400dccSAndrii Nakryiko }
259*57400dccSAndrii Nakryiko
260*57400dccSAndrii Nakryiko SEC("?raw_tp")
261*57400dccSAndrii Nakryiko __failure __msg("expected an initialized iter_num as arg #1")
double_destroy_fail(void * ctx)262*57400dccSAndrii Nakryiko int double_destroy_fail(void *ctx)
263*57400dccSAndrii Nakryiko {
264*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
265*57400dccSAndrii Nakryiko
266*57400dccSAndrii Nakryiko asm volatile (
267*57400dccSAndrii Nakryiko /* create iterator */
268*57400dccSAndrii Nakryiko "r1 = %[iter];"
269*57400dccSAndrii Nakryiko "r2 = 0;"
270*57400dccSAndrii Nakryiko "r3 = 1000;"
271*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
272*57400dccSAndrii Nakryiko /* destroy iterator */
273*57400dccSAndrii Nakryiko "r1 = %[iter];"
274*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
275*57400dccSAndrii Nakryiko /* (attempt to) destroy iterator again */
276*57400dccSAndrii Nakryiko "r1 = %[iter];"
277*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
278*57400dccSAndrii Nakryiko :
279*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
280*57400dccSAndrii Nakryiko : __clobber_common
281*57400dccSAndrii Nakryiko );
282*57400dccSAndrii Nakryiko
283*57400dccSAndrii Nakryiko return 0;
284*57400dccSAndrii Nakryiko }
285*57400dccSAndrii Nakryiko
286*57400dccSAndrii Nakryiko SEC("?raw_tp")
287*57400dccSAndrii Nakryiko __failure __msg("expected an initialized iter_num as arg #1")
next_without_new_fail(void * ctx)288*57400dccSAndrii Nakryiko int next_without_new_fail(void *ctx)
289*57400dccSAndrii Nakryiko {
290*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
291*57400dccSAndrii Nakryiko
292*57400dccSAndrii Nakryiko asm volatile (
293*57400dccSAndrii Nakryiko /* don't create iterator and try to iterate*/
294*57400dccSAndrii Nakryiko "r1 = %[iter];"
295*57400dccSAndrii Nakryiko "call %[bpf_iter_num_next];"
296*57400dccSAndrii Nakryiko /* destroy iterator */
297*57400dccSAndrii Nakryiko "r1 = %[iter];"
298*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
299*57400dccSAndrii Nakryiko :
300*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
301*57400dccSAndrii Nakryiko : __clobber_common
302*57400dccSAndrii Nakryiko );
303*57400dccSAndrii Nakryiko
304*57400dccSAndrii Nakryiko return 0;
305*57400dccSAndrii Nakryiko }
306*57400dccSAndrii Nakryiko
307*57400dccSAndrii Nakryiko SEC("?raw_tp")
308*57400dccSAndrii Nakryiko __failure __msg("expected an initialized iter_num as arg #1")
next_after_destroy_fail(void * ctx)309*57400dccSAndrii Nakryiko int next_after_destroy_fail(void *ctx)
310*57400dccSAndrii Nakryiko {
311*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
312*57400dccSAndrii Nakryiko
313*57400dccSAndrii Nakryiko asm volatile (
314*57400dccSAndrii Nakryiko /* create iterator */
315*57400dccSAndrii Nakryiko "r1 = %[iter];"
316*57400dccSAndrii Nakryiko "r2 = 0;"
317*57400dccSAndrii Nakryiko "r3 = 1000;"
318*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
319*57400dccSAndrii Nakryiko /* destroy iterator */
320*57400dccSAndrii Nakryiko "r1 = %[iter];"
321*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
322*57400dccSAndrii Nakryiko /* don't create iterator and try to iterate*/
323*57400dccSAndrii Nakryiko "r1 = %[iter];"
324*57400dccSAndrii Nakryiko "call %[bpf_iter_num_next];"
325*57400dccSAndrii Nakryiko :
326*57400dccSAndrii Nakryiko : __imm_ptr(iter), ITER_HELPERS
327*57400dccSAndrii Nakryiko : __clobber_common
328*57400dccSAndrii Nakryiko );
329*57400dccSAndrii Nakryiko
330*57400dccSAndrii Nakryiko return 0;
331*57400dccSAndrii Nakryiko }
332*57400dccSAndrii Nakryiko
333*57400dccSAndrii Nakryiko SEC("?raw_tp")
334*57400dccSAndrii Nakryiko __failure __msg("invalid read from stack")
read_from_iter_slot_fail(void)335*57400dccSAndrii Nakryiko int __naked read_from_iter_slot_fail(void)
336*57400dccSAndrii Nakryiko {
337*57400dccSAndrii Nakryiko asm volatile (
338*57400dccSAndrii Nakryiko /* r6 points to struct bpf_iter_num on the stack */
339*57400dccSAndrii Nakryiko "r6 = r10;"
340*57400dccSAndrii Nakryiko "r6 += -24;"
341*57400dccSAndrii Nakryiko
342*57400dccSAndrii Nakryiko /* create iterator */
343*57400dccSAndrii Nakryiko "r1 = r6;"
344*57400dccSAndrii Nakryiko "r2 = 0;"
345*57400dccSAndrii Nakryiko "r3 = 1000;"
346*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
347*57400dccSAndrii Nakryiko
348*57400dccSAndrii Nakryiko /* attemp to leak bpf_iter_num state */
349*57400dccSAndrii Nakryiko "r7 = *(u64 *)(r6 + 0);"
350*57400dccSAndrii Nakryiko "r8 = *(u64 *)(r6 + 8);"
351*57400dccSAndrii Nakryiko
352*57400dccSAndrii Nakryiko /* destroy iterator */
353*57400dccSAndrii Nakryiko "r1 = r6;"
354*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];"
355*57400dccSAndrii Nakryiko
356*57400dccSAndrii Nakryiko /* leak bpf_iter_num state */
357*57400dccSAndrii Nakryiko "r0 = r7;"
358*57400dccSAndrii Nakryiko "if r7 > r8 goto +1;"
359*57400dccSAndrii Nakryiko "r0 = r8;"
360*57400dccSAndrii Nakryiko "exit;"
361*57400dccSAndrii Nakryiko :
362*57400dccSAndrii Nakryiko : ITER_HELPERS
363*57400dccSAndrii Nakryiko : __clobber_common, "r6", "r7", "r8"
364*57400dccSAndrii Nakryiko );
365*57400dccSAndrii Nakryiko }
366*57400dccSAndrii Nakryiko
367*57400dccSAndrii Nakryiko int zero;
368*57400dccSAndrii Nakryiko
369*57400dccSAndrii Nakryiko SEC("?raw_tp")
370*57400dccSAndrii Nakryiko __failure
__flag(BPF_F_TEST_STATE_FREQ)371*57400dccSAndrii Nakryiko __flag(BPF_F_TEST_STATE_FREQ)
372*57400dccSAndrii Nakryiko __msg("Unreleased reference")
373*57400dccSAndrii Nakryiko int stacksafe_should_not_conflate_stack_spill_and_iter(void *ctx)
374*57400dccSAndrii Nakryiko {
375*57400dccSAndrii Nakryiko struct bpf_iter_num iter;
376*57400dccSAndrii Nakryiko
377*57400dccSAndrii Nakryiko asm volatile (
378*57400dccSAndrii Nakryiko /* Create a fork in logic, with general setup as follows:
379*57400dccSAndrii Nakryiko * - fallthrough (first) path is valid;
380*57400dccSAndrii Nakryiko * - branch (second) path is invalid.
381*57400dccSAndrii Nakryiko * Then depending on what we do in fallthrough vs branch path,
382*57400dccSAndrii Nakryiko * we try to detect bugs in func_states_equal(), regsafe(),
383*57400dccSAndrii Nakryiko * refsafe(), stack_safe(), and similar by tricking verifier
384*57400dccSAndrii Nakryiko * into believing that branch state is a valid subset of
385*57400dccSAndrii Nakryiko * a fallthrough state. Verifier should reject overall
386*57400dccSAndrii Nakryiko * validation, unless there is a bug somewhere in verifier
387*57400dccSAndrii Nakryiko * logic.
388*57400dccSAndrii Nakryiko */
389*57400dccSAndrii Nakryiko "call %[bpf_get_prandom_u32];"
390*57400dccSAndrii Nakryiko "r6 = r0;"
391*57400dccSAndrii Nakryiko "call %[bpf_get_prandom_u32];"
392*57400dccSAndrii Nakryiko "r7 = r0;"
393*57400dccSAndrii Nakryiko
394*57400dccSAndrii Nakryiko "if r6 > r7 goto bad;" /* fork */
395*57400dccSAndrii Nakryiko
396*57400dccSAndrii Nakryiko /* spill r6 into stack slot of bpf_iter_num var */
397*57400dccSAndrii Nakryiko "*(u64 *)(%[iter] + 0) = r6;"
398*57400dccSAndrii Nakryiko
399*57400dccSAndrii Nakryiko "goto skip_bad;"
400*57400dccSAndrii Nakryiko
401*57400dccSAndrii Nakryiko "bad:"
402*57400dccSAndrii Nakryiko /* create iterator in the same stack slot */
403*57400dccSAndrii Nakryiko "r1 = %[iter];"
404*57400dccSAndrii Nakryiko "r2 = 0;"
405*57400dccSAndrii Nakryiko "r3 = 1000;"
406*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];"
407*57400dccSAndrii Nakryiko
408*57400dccSAndrii Nakryiko /* but then forget about it and overwrite it back to r6 spill */
409*57400dccSAndrii Nakryiko "*(u64 *)(%[iter] + 0) = r6;"
410*57400dccSAndrii Nakryiko
411*57400dccSAndrii Nakryiko "skip_bad:"
412*57400dccSAndrii Nakryiko "goto +0;" /* force checkpoint */
413*57400dccSAndrii Nakryiko
414*57400dccSAndrii Nakryiko /* corrupt stack slots, if they are really dynptr */
415*57400dccSAndrii Nakryiko "*(u64 *)(%[iter] + 0) = r6;"
416*57400dccSAndrii Nakryiko :
417*57400dccSAndrii Nakryiko : __imm_ptr(iter),
418*57400dccSAndrii Nakryiko __imm_addr(zero),
419*57400dccSAndrii Nakryiko __imm(bpf_get_prandom_u32),
420*57400dccSAndrii Nakryiko __imm(bpf_dynptr_from_mem),
421*57400dccSAndrii Nakryiko ITER_HELPERS
422*57400dccSAndrii Nakryiko : __clobber_common, "r6", "r7"
423*57400dccSAndrii Nakryiko );
424*57400dccSAndrii Nakryiko
425*57400dccSAndrii Nakryiko return 0;
426*57400dccSAndrii Nakryiko }
427