xref: /linux/tools/testing/selftests/bpf/progs/kfunc_call_test.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2021 Facebook */
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include "bpf_misc.h"
6 #include "../test_kmods/bpf_testmod_kfunc.h"
7 
8 static struct bpf_spin_lock kfunc_call_lock SEC(".data.A");
9 
10 SEC("tc")
kfunc_call_test_spin_lock_safe(struct __sk_buff * skb)11 int kfunc_call_test_spin_lock_safe(struct __sk_buff *skb)
12 {
13 	bpf_spin_lock(&kfunc_call_lock);
14 	bpf_testmod_test_mod_kfunc(42);
15 	bpf_spin_unlock(&kfunc_call_lock);
16 
17 	return 0;
18 }
19 
20 SEC("tc")
kfunc_call_test5(struct __sk_buff * skb)21 int kfunc_call_test5(struct __sk_buff *skb)
22 {
23 	struct bpf_sock *sk = skb->sk;
24 	int ret;
25 	u32 val32;
26 	u16 val16;
27 	u8 val8;
28 
29 	if (!sk)
30 		return -1;
31 
32 	sk = bpf_sk_fullsock(sk);
33 	if (!sk)
34 		return -1;
35 
36 	/*
37 	 * Test with constant values to verify zero-extension.
38 	 * ISA-dependent BPF asm:
39 	 *   With ALU32:    w1 = 0xFF; w2 = 0xFFFF; w3 = 0xFFFFffff
40 	 *   Without ALU32: r1 = 0xFF; r2 = 0xFFFF; r3 = 0xFFFFffff
41 	 * Both zero-extend to 64-bit before the kfunc call.
42 	 */
43 	ret = bpf_kfunc_call_test5(0xFF, 0xFFFF, 0xFFFFffffULL);
44 	if (ret)
45 		return ret;
46 
47 	val32 = bpf_get_prandom_u32();
48 	val16 = val32 & 0xFFFF;
49 	val8 = val32 & 0xFF;
50 	ret = bpf_kfunc_call_test5(val8, val16, val32);
51 	if (ret)
52 		return ret;
53 
54 	/*
55 	 * Test multiplication with different operand sizes:
56 	 *
57 	 * val8 * 0xFF:
58 	 *   - Both operands promote to int (32-bit signed)
59 	 *   - Result: 32-bit multiplication, truncated to u8, then zero-extended
60 	 *
61 	 * val16 * 0xFFFF:
62 	 *   - Both operands promote to int (32-bit signed)
63 	 *   - Result: 32-bit multiplication, truncated to u16, then zero-extended
64 	 *
65 	 * val32 * 0xFFFFffffULL:
66 	 *   - val32 (u32) promotes to unsigned long long (due to ULL suffix)
67 	 *   - Result: 64-bit unsigned multiplication, truncated to u32, then zero-extended
68 	 */
69 	ret = bpf_kfunc_call_test5(val8 * 0xFF, val16 * 0xFFFF, val32 * 0xFFFFffffULL);
70 	if (ret)
71 		return ret;
72 
73 	return 0;
74 }
75 
76 /*
77  * Assembly version testing the multiplication edge case explicitly.
78  * This ensures consistent testing across different ISA versions.
79  */
80 SEC("tc")
kfunc_call_test5_asm(void)81 __naked int kfunc_call_test5_asm(void)
82 {
83 	asm volatile (
84 		/* Get a random u32 value */
85 		"call %[bpf_get_prandom_u32];"
86 		"r6 = r0;"              /* Save val32 in r6 */
87 
88 		/* Prepare first argument: val8 * 0xFF */
89 		"r1 = r6;"
90 		"r1 &= 0xFF;"           /* val8 = val32 & 0xFF */
91 		"r7 = 0xFF;"
92 		"r1 *= r7;"             /* 64-bit mult: r1 = r1 * r7 */
93 
94 		/* Prepare second argument: val16 * 0xFFFF */
95 		"r2 = r6;"
96 		"r2 &= 0xFFFF;"         /* val16 = val32 & 0xFFFF */
97 		"r7 = 0xFFFF;"
98 		"r2 *= r7;"             /* 64-bit mult: r2 = r2 * r7 */
99 
100 		/* Prepare third argument: val32 * 0xFFFFffff */
101 		"r3 = r6;"              /* val32 */
102 		"r7 = 0xFFFFffff;"
103 		"r3 *= r7;"             /* 64-bit mult: r3 = r3 * r7 */
104 
105 		/* Call kfunc with multiplication results */
106 		"call bpf_kfunc_call_test5;"
107 
108 		/* Check return value */
109 		"if r0 != 0 goto exit_%=;"
110 		"r0 = 0;"
111 		"exit_%=: exit;"
112 		:
113 		: __imm(bpf_get_prandom_u32)
114 		: __clobber_all);
115 }
116 
117 SEC("tc")
kfunc_call_test4(struct __sk_buff * skb)118 int kfunc_call_test4(struct __sk_buff *skb)
119 {
120 	struct bpf_sock *sk = skb->sk;
121 	long tmp;
122 
123 	if (!sk)
124 		return -1;
125 
126 	sk = bpf_sk_fullsock(sk);
127 	if (!sk)
128 		return -1;
129 
130 	tmp = bpf_kfunc_call_test4(-3, -30, -200, -1000);
131 	return (tmp >> 32) + tmp;
132 }
133 
134 SEC("tc")
kfunc_call_test2(struct __sk_buff * skb)135 int kfunc_call_test2(struct __sk_buff *skb)
136 {
137 	struct bpf_sock *sk = skb->sk;
138 
139 	if (!sk)
140 		return -1;
141 
142 	sk = bpf_sk_fullsock(sk);
143 	if (!sk)
144 		return -1;
145 
146 	return bpf_kfunc_call_test2((struct sock *)sk, 1, 2);
147 }
148 
149 SEC("tc")
kfunc_call_test1(struct __sk_buff * skb)150 int kfunc_call_test1(struct __sk_buff *skb)
151 {
152 	struct bpf_sock *sk = skb->sk;
153 	__u64 a = 1ULL << 32;
154 	__u32 ret;
155 
156 	if (!sk)
157 		return -1;
158 
159 	sk = bpf_sk_fullsock(sk);
160 	if (!sk)
161 		return -1;
162 
163 	a = bpf_kfunc_call_test1((struct sock *)sk, 1, a | 2, 3, a | 4);
164 	ret = a >> 32;   /* ret should be 2 */
165 	ret += (__u32)a; /* ret should be 12 */
166 
167 	return ret;
168 }
169 
170 SEC("tc")
kfunc_call_test_ref_btf_id(struct __sk_buff * skb)171 int kfunc_call_test_ref_btf_id(struct __sk_buff *skb)
172 {
173 	struct prog_test_ref_kfunc *pt;
174 	unsigned long s = 0;
175 	int ret = 0;
176 
177 	pt = bpf_kfunc_call_test_acquire(&s);
178 	if (pt) {
179 		if (pt->a != 42 || pt->b != 108)
180 			ret = -1;
181 		bpf_kfunc_call_test_release(pt);
182 	}
183 	return ret;
184 }
185 
186 SEC("tc")
kfunc_call_test_pass(struct __sk_buff * skb)187 int kfunc_call_test_pass(struct __sk_buff *skb)
188 {
189 	struct prog_test_pass1 p1 = {};
190 	struct prog_test_pass2 p2 = {};
191 	short a = 0;
192 	__u64 b = 0;
193 	long c = 0;
194 	char d = 0;
195 	int e = 0;
196 
197 	bpf_kfunc_call_test_pass_ctx(skb);
198 	bpf_kfunc_call_test_pass1(&p1);
199 	bpf_kfunc_call_test_pass2(&p2);
200 
201 	bpf_kfunc_call_test_mem_len_pass1(&a, sizeof(a));
202 	bpf_kfunc_call_test_mem_len_pass1(&b, sizeof(b));
203 	bpf_kfunc_call_test_mem_len_pass1(&c, sizeof(c));
204 	bpf_kfunc_call_test_mem_len_pass1(&d, sizeof(d));
205 	bpf_kfunc_call_test_mem_len_pass1(&e, sizeof(e));
206 	bpf_kfunc_call_test_mem_len_fail2(&b, -1);
207 
208 	return 0;
209 }
210 
211 struct syscall_test_args {
212 	__u8 data[16];
213 	size_t size;
214 };
215 
216 SEC("syscall")
kfunc_syscall_test(struct syscall_test_args * args)217 int kfunc_syscall_test(struct syscall_test_args *args)
218 {
219 	const long size = args->size;
220 
221 	if (size > sizeof(args->data))
222 		return -7; /* -E2BIG */
223 
224 	bpf_kfunc_call_test_mem_len_pass1(&args->data, sizeof(args->data));
225 	bpf_kfunc_call_test_mem_len_pass1(&args->data, sizeof(*args));
226 	bpf_kfunc_call_test_mem_len_pass1(&args->data, size);
227 
228 	return 0;
229 }
230 
231 SEC("syscall")
kfunc_syscall_test_null(struct syscall_test_args * args)232 int kfunc_syscall_test_null(struct syscall_test_args *args)
233 {
234 	/* Must be called with args as a NULL pointer
235 	 * we do not check for it to have the verifier consider that
236 	 * the pointer might not be null, and so we can load it.
237 	 *
238 	 * So the following can not be added:
239 	 *
240 	 * if (args)
241 	 *      return -22;
242 	 */
243 
244 	bpf_kfunc_call_test_mem_len_pass1(args, 0);
245 
246 	return 0;
247 }
248 
249 SEC("tc")
kfunc_call_test_get_mem(struct __sk_buff * skb)250 int kfunc_call_test_get_mem(struct __sk_buff *skb)
251 {
252 	struct prog_test_ref_kfunc *pt;
253 	unsigned long s = 0;
254 	int *p = NULL;
255 	int ret = 0;
256 
257 	pt = bpf_kfunc_call_test_acquire(&s);
258 	if (pt) {
259 		p = bpf_kfunc_call_test_get_rdwr_mem(pt, 2 * sizeof(int));
260 		if (p) {
261 			p[0] = 42;
262 			ret = p[1]; /* 108 */
263 		} else {
264 			ret = -1;
265 		}
266 
267 		if (ret >= 0) {
268 			p = bpf_kfunc_call_test_get_rdonly_mem(pt, 2 * sizeof(int));
269 			if (p)
270 				ret = p[0]; /* 42 */
271 			else
272 				ret = -1;
273 		}
274 
275 		bpf_kfunc_call_test_release(pt);
276 	}
277 	return ret;
278 }
279 
280 SEC("tc")
kfunc_call_test_static_unused_arg(struct __sk_buff * skb)281 int kfunc_call_test_static_unused_arg(struct __sk_buff *skb)
282 {
283 
284 	u32 expected = 5, actual;
285 
286 	actual = bpf_kfunc_call_test_static_unused_arg(expected, 0xdeadbeef);
287 	return actual != expected ? -1 : 0;
288 }
289 
290 struct ctx_val {
291 	struct bpf_testmod_ctx __kptr *ctx;
292 };
293 
294 struct {
295 	__uint(type, BPF_MAP_TYPE_ARRAY);
296 	__uint(max_entries, 1);
297 	__type(key, int);
298 	__type(value, struct ctx_val);
299 } ctx_map SEC(".maps");
300 
301 SEC("tc")
kfunc_call_ctx(struct __sk_buff * skb)302 int kfunc_call_ctx(struct __sk_buff *skb)
303 {
304 	struct bpf_testmod_ctx *ctx;
305 	int err = 0;
306 
307 	ctx = bpf_testmod_ctx_create(&err);
308 	if (!ctx && !err)
309 		err = -1;
310 	if (ctx) {
311 		int key = 0;
312 		struct ctx_val *ctx_val = bpf_map_lookup_elem(&ctx_map, &key);
313 
314 		/* Transfer ctx to map to be freed via implicit dtor call
315 		 * on cleanup.
316 		 */
317 		if (ctx_val)
318 			ctx = bpf_kptr_xchg(&ctx_val->ctx, ctx);
319 		if (ctx) {
320 			bpf_testmod_ctx_release(ctx);
321 			err = -1;
322 		}
323 	}
324 	return err;
325 }
326 
327 char _license[] SEC("license") = "GPL";
328