1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2024 Yafang Shao <laoar.shao@gmail.com> */
3 
4 #include "vmlinux.h"
5 #include <bpf/bpf_helpers.h>
6 #include <bpf/bpf_tracing.h>
7 
8 #include "bpf_misc.h"
9 #include "task_kfunc_common.h"
10 
11 char _license[] SEC("license") = "GPL";
12 
13 int bpf_iter_bits_new(struct bpf_iter_bits *it, const u64 *unsafe_ptr__ign,
14 		      u32 nr_bits) __ksym __weak;
15 int *bpf_iter_bits_next(struct bpf_iter_bits *it) __ksym __weak;
16 void bpf_iter_bits_destroy(struct bpf_iter_bits *it) __ksym __weak;
17 
18 u64 bits_array[511] = {};
19 
20 SEC("iter.s/cgroup")
21 __description("bits iter without destroy")
22 __failure __msg("Unreleased reference")
BPF_PROG(no_destroy,struct bpf_iter_meta * meta,struct cgroup * cgrp)23 int BPF_PROG(no_destroy, struct bpf_iter_meta *meta, struct cgroup *cgrp)
24 {
25 	struct bpf_iter_bits it;
26 	u64 data = 1;
27 
28 	bpf_iter_bits_new(&it, &data, 1);
29 	bpf_iter_bits_next(&it);
30 	return 0;
31 }
32 
33 SEC("iter/cgroup")
34 __description("uninitialized iter in ->next()")
35 __failure __msg("expected an initialized iter_bits as arg #1")
BPF_PROG(next_uninit,struct bpf_iter_meta * meta,struct cgroup * cgrp)36 int BPF_PROG(next_uninit, struct bpf_iter_meta *meta, struct cgroup *cgrp)
37 {
38 	struct bpf_iter_bits *it = NULL;
39 
40 	bpf_iter_bits_next(it);
41 	return 0;
42 }
43 
44 SEC("iter/cgroup")
45 __description("uninitialized iter in ->destroy()")
46 __failure __msg("expected an initialized iter_bits as arg #1")
BPF_PROG(destroy_uninit,struct bpf_iter_meta * meta,struct cgroup * cgrp)47 int BPF_PROG(destroy_uninit, struct bpf_iter_meta *meta, struct cgroup *cgrp)
48 {
49 	struct bpf_iter_bits it = {};
50 
51 	bpf_iter_bits_destroy(&it);
52 	return 0;
53 }
54 
55 SEC("syscall")
56 __description("null pointer")
57 __success __retval(0)
null_pointer(void)58 int null_pointer(void)
59 {
60 	struct bpf_iter_bits iter;
61 	int err, nr = 0;
62 	int *bit;
63 
64 	err = bpf_iter_bits_new(&iter, NULL, 1);
65 	bpf_iter_bits_destroy(&iter);
66 	if (err != -EINVAL)
67 		return 1;
68 
69 	bpf_for_each(bits, bit, NULL, 1)
70 		nr++;
71 	return nr;
72 }
73 
74 SEC("syscall")
75 __description("bits copy")
76 __success __retval(10)
bits_copy(void)77 int bits_copy(void)
78 {
79 	u64 data = 0xf7310UL; /* 4 + 3 + 2 + 1 + 0*/
80 	int nr = 0;
81 	int *bit;
82 
83 	bpf_for_each(bits, bit, &data, 1)
84 		nr++;
85 	return nr;
86 }
87 
88 SEC("syscall")
89 __description("bits memalloc")
90 __success __retval(64)
bits_memalloc(void)91 int bits_memalloc(void)
92 {
93 	u64 data[2];
94 	int nr = 0;
95 	int *bit;
96 
97 	__builtin_memset(&data, 0xf0, sizeof(data)); /* 4 * 16 */
98 	bpf_for_each(bits, bit, &data[0], ARRAY_SIZE(data))
99 		nr++;
100 	return nr;
101 }
102 
103 SEC("syscall")
104 __description("bit index")
105 __success __retval(8)
bit_index(void)106 int bit_index(void)
107 {
108 	u64 data = 0x100;
109 	int bit_idx = 0;
110 	int *bit;
111 
112 	bpf_for_each(bits, bit, &data, 1) {
113 		if (*bit == 0)
114 			continue;
115 		bit_idx = *bit;
116 	}
117 	return bit_idx;
118 }
119 
120 SEC("syscall")
121 __description("bits too big")
122 __success __retval(0)
bits_too_big(void)123 int bits_too_big(void)
124 {
125 	u64 data[4];
126 	int nr = 0;
127 	int *bit;
128 
129 	__builtin_memset(&data, 0xff, sizeof(data));
130 	bpf_for_each(bits, bit, &data[0], 512) /* Be greater than 511 */
131 		nr++;
132 	return nr;
133 }
134 
135 SEC("syscall")
136 __description("fewer words")
137 __success __retval(1)
fewer_words(void)138 int fewer_words(void)
139 {
140 	u64 data[2] = {0x1, 0xff};
141 	int nr = 0;
142 	int *bit;
143 
144 	bpf_for_each(bits, bit, &data[0], 1)
145 		nr++;
146 	return nr;
147 }
148 
149 SEC("syscall")
150 __description("zero words")
151 __success __retval(0)
zero_words(void)152 int zero_words(void)
153 {
154 	u64 data[2] = {0x1, 0xff};
155 	int nr = 0;
156 	int *bit;
157 
158 	bpf_for_each(bits, bit, &data[0], 0)
159 		nr++;
160 	return nr;
161 }
162 
163 SEC("syscall")
164 __description("huge words")
165 __success __retval(0)
huge_words(void)166 int huge_words(void)
167 {
168 	u64 data[8] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1};
169 	int nr = 0;
170 	int *bit;
171 
172 	bpf_for_each(bits, bit, &data[0], 67108865)
173 		nr++;
174 	return nr;
175 }
176 
177 SEC("syscall")
178 __description("max words")
179 __success __retval(4)
max_words(void)180 int max_words(void)
181 {
182 	volatile int nr = 0;
183 	int *bit;
184 
185 	bits_array[0] = (1ULL << 63) | 1U;
186 	bits_array[510] = (1ULL << 33) | (1ULL << 32);
187 
188 	bpf_for_each(bits, bit, bits_array, 511) {
189 		if (nr == 0 && *bit != 0)
190 			break;
191 		if (nr == 2 && *bit != 32672)
192 			break;
193 		nr++;
194 	}
195 	return nr;
196 }
197 
198 SEC("syscall")
199 __description("bad words")
200 __success __retval(0)
bad_words(void)201 int bad_words(void)
202 {
203 	void *bad_addr = (void *)-4095;
204 	struct bpf_iter_bits iter;
205 	volatile int nr;
206 	int *bit;
207 	int err;
208 
209 	err = bpf_iter_bits_new(&iter, bad_addr, 1);
210 	bpf_iter_bits_destroy(&iter);
211 	if (err != -EFAULT)
212 		return 1;
213 
214 	nr = 0;
215 	bpf_for_each(bits, bit, bad_addr, 1)
216 		nr++;
217 	if (nr != 0)
218 		return 2;
219 
220 	err = bpf_iter_bits_new(&iter, bad_addr, 4);
221 	bpf_iter_bits_destroy(&iter);
222 	if (err != -EFAULT)
223 		return 3;
224 
225 	nr = 0;
226 	bpf_for_each(bits, bit, bad_addr, 4)
227 		nr++;
228 	if (nr != 0)
229 		return 4;
230 
231 	return 0;
232 }
233