1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3
4#include <errno.h>
5#include <string.h>
6#include <linux/bpf.h>
7#include <bpf/bpf_helpers.h>
8#include "bpf_misc.h"
9
10char _license[] SEC("license") = "GPL";
11
12#define ITER_HELPERS						\
13	  __imm(bpf_iter_num_new),				\
14	  __imm(bpf_iter_num_next),				\
15	  __imm(bpf_iter_num_destroy)
16
17SEC("?raw_tp")
18__success
19int force_clang_to_emit_btf_for_externs(void *ctx)
20{
21	/* we need this as a workaround to enforce compiler emitting BTF
22	 * information for bpf_iter_num_{new,next,destroy}() kfuncs,
23	 * as, apparently, it doesn't emit it for symbols only referenced from
24	 * assembly (or cleanup attribute, for that matter, as well)
25	 */
26	bpf_repeat(0);
27
28	return 0;
29}
30
31SEC("?raw_tp")
32__success
33int consume_first_item_only(void *ctx)
34{
35	struct bpf_iter_num iter;
36
37	asm volatile (
38		/* create iterator */
39		"r1 = %[iter];"
40		"r2 = 0;"
41		"r3 = 1000;"
42		"call %[bpf_iter_num_new];"
43
44		/* consume first item */
45		"r1 = %[iter];"
46		"call %[bpf_iter_num_next];"
47
48		"if r0 == 0 goto +1;"
49		"r0 = *(u32 *)(r0 + 0);"
50
51		/* destroy iterator */
52		"r1 = %[iter];"
53		"call %[bpf_iter_num_destroy];"
54		:
55		: __imm_ptr(iter), ITER_HELPERS
56		: __clobber_common
57	);
58
59	return 0;
60}
61
62SEC("?raw_tp")
63__failure __msg("R0 invalid mem access 'scalar'")
64int missing_null_check_fail(void *ctx)
65{
66	struct bpf_iter_num iter;
67
68	asm volatile (
69		/* create iterator */
70		"r1 = %[iter];"
71		"r2 = 0;"
72		"r3 = 1000;"
73		"call %[bpf_iter_num_new];"
74
75		/* consume first element */
76		"r1 = %[iter];"
77		"call %[bpf_iter_num_next];"
78
79		/* FAIL: deref with no NULL check */
80		"r1 = *(u32 *)(r0 + 0);"
81
82		/* destroy iterator */
83		"r1 = %[iter];"
84		"call %[bpf_iter_num_destroy];"
85		:
86		: __imm_ptr(iter), ITER_HELPERS
87		: __clobber_common
88	);
89
90	return 0;
91}
92
93SEC("?raw_tp")
94__failure
95__msg("invalid access to memory, mem_size=4 off=0 size=8")
96__msg("R0 min value is outside of the allowed memory range")
97int wrong_sized_read_fail(void *ctx)
98{
99	struct bpf_iter_num iter;
100
101	asm volatile (
102		/* create iterator */
103		"r1 = %[iter];"
104		"r2 = 0;"
105		"r3 = 1000;"
106		"call %[bpf_iter_num_new];"
107
108		/* consume first element */
109		"r1 = %[iter];"
110		"call %[bpf_iter_num_next];"
111
112		"if r0 == 0 goto +1;"
113		/* FAIL: deref more than available 4 bytes */
114		"r0 = *(u64 *)(r0 + 0);"
115
116		/* destroy iterator */
117		"r1 = %[iter];"
118		"call %[bpf_iter_num_destroy];"
119		:
120		: __imm_ptr(iter), ITER_HELPERS
121		: __clobber_common
122	);
123
124	return 0;
125}
126
127SEC("?raw_tp")
128__success __log_level(2)
129__flag(BPF_F_TEST_STATE_FREQ)
130int simplest_loop(void *ctx)
131{
132	struct bpf_iter_num iter;
133
134	asm volatile (
135		"r6 = 0;" /* init sum */
136
137		/* create iterator */
138		"r1 = %[iter];"
139		"r2 = 0;"
140		"r3 = 10;"
141		"call %[bpf_iter_num_new];"
142
143	"1:"
144		/* consume next item */
145		"r1 = %[iter];"
146		"call %[bpf_iter_num_next];"
147
148		"if r0 == 0 goto 2f;"
149		"r0 = *(u32 *)(r0 + 0);"
150		"r6 += r0;" /* accumulate sum */
151		"goto 1b;"
152
153	"2:"
154		/* destroy iterator */
155		"r1 = %[iter];"
156		"call %[bpf_iter_num_destroy];"
157		:
158		: __imm_ptr(iter), ITER_HELPERS
159		: __clobber_common, "r6"
160	);
161
162	return 0;
163}
164