File Index
Files and directories
Sign in
FILE

bpf_gotox.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/progs/bpf_gotox.c C
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#include "vmlinux.h"
  4#include <bpf/bpf_helpers.h>
  5#include <bpf/bpf_tracing.h>
  6#include <bpf/bpf_core_read.h>
  7#include "bpf_misc.h"
  8
  9__u64 in_user;
 10__u64 ret_user;
 11
 12int pid;
 13
 14/*
 15 * Skip all the tests if compiler doesn't support indirect jumps.
 16 *
 17 * If tests are skipped, then all functions below are compiled as
 18 * dummy, such that the skeleton looks the same, and the userspace
 19 * program can avoid any checks rather than if data->skip is set.
 20 */
 21#ifdef __BPF_FEATURE_GOTOX
 22__u64 skip SEC(".data") = 0;
 23#else
 24__u64 skip = 1;
 25#endif
 26
 27struct simple_ctx {
 28	__u64 x;
 29};
 30
 31#ifdef __BPF_FEATURE_GOTOX
 32__u64 some_var;
 33
 34/*
 35 * This function adds code which will be replaced by a different
 36 * number of instructions by the verifier. This adds additional
 37 * stress on testing the insn_array maps corresponding to indirect jumps.
 38 */
 39static __always_inline void adjust_insns(__u64 x)
 40{
 41	some_var ^= x + bpf_jiffies64();
 42}
 43
 44SEC("syscall")
 45int one_switch(struct simple_ctx *ctx)
 46{
 47	switch (ctx->x) {
 48	case 0:
 49		adjust_insns(ctx->x + 1);
 50		ret_user = 2;
 51		break;
 52	case 1:
 53		adjust_insns(ctx->x + 7);
 54		ret_user = 3;
 55		break;
 56	case 2:
 57		adjust_insns(ctx->x + 9);
 58		ret_user = 4;
 59		break;
 60	case 3:
 61		adjust_insns(ctx->x + 11);
 62		ret_user = 5;
 63		break;
 64	case 4:
 65		adjust_insns(ctx->x + 17);
 66		ret_user = 7;
 67		break;
 68	default:
 69		adjust_insns(ctx->x + 177);
 70		ret_user = 19;
 71		break;
 72	}
 73
 74	return 0;
 75}
 76
 77SEC("syscall")
 78int one_switch_non_zero_sec_off(struct simple_ctx *ctx)
 79{
 80	switch (ctx->x) {
 81	case 0:
 82		adjust_insns(ctx->x + 1);
 83		ret_user = 2;
 84		break;
 85	case 1:
 86		adjust_insns(ctx->x + 7);
 87		ret_user = 3;
 88		break;
 89	case 2:
 90		adjust_insns(ctx->x + 9);
 91		ret_user = 4;
 92		break;
 93	case 3:
 94		adjust_insns(ctx->x + 11);
 95		ret_user = 5;
 96		break;
 97	case 4:
 98		adjust_insns(ctx->x + 17);
 99		ret_user = 7;
100		break;
101	default:
102		adjust_insns(ctx->x + 177);
103		ret_user = 19;
104		break;
105	}
106
107	return 0;
108}
109
110SEC("fentry/" SYS_PREFIX "sys_nanosleep")
111int simple_test_other_sec(struct pt_regs *ctx)
112{
113	__u64 x = in_user;
114
115	if (bpf_get_current_pid_tgid() >> 32 != pid)
116		return 0;
117
118	switch (x) {
119	case 0:
120		adjust_insns(x + 1);
121		ret_user = 2;
122		break;
123	case 1:
124		adjust_insns(x + 7);
125		ret_user = 3;
126		break;
127	case 2:
128		adjust_insns(x + 9);
129		ret_user = 4;
130		break;
131	case 3:
132		adjust_insns(x + 11);
133		ret_user = 5;
134		break;
135	case 4:
136		adjust_insns(x + 17);
137		ret_user = 7;
138		break;
139	default:
140		adjust_insns(x + 177);
141		ret_user = 19;
142		break;
143	}
144
145	return 0;
146}
147
148SEC("syscall")
149int two_switches(struct simple_ctx *ctx)
150{
151	switch (ctx->x) {
152	case 0:
153		adjust_insns(ctx->x + 1);
154		ret_user = 2;
155		break;
156	case 1:
157		adjust_insns(ctx->x + 7);
158		ret_user = 3;
159		break;
160	case 2:
161		adjust_insns(ctx->x + 9);
162		ret_user = 4;
163		break;
164	case 3:
165		adjust_insns(ctx->x + 11);
166		ret_user = 5;
167		break;
168	case 4:
169		adjust_insns(ctx->x + 17);
170		ret_user = 7;
171		break;
172	default:
173		adjust_insns(ctx->x + 177);
174		ret_user = 19;
175		break;
176	}
177
178	switch (ctx->x + !!ret_user) {
179	case 1:
180		adjust_insns(ctx->x + 7);
181		ret_user = 103;
182		break;
183	case 2:
184		adjust_insns(ctx->x + 9);
185		ret_user = 104;
186		break;
187	case 3:
188		adjust_insns(ctx->x + 11);
189		ret_user = 107;
190		break;
191	case 4:
192		adjust_insns(ctx->x + 11);
193		ret_user = 205;
194		break;
195	case 5:
196		adjust_insns(ctx->x + 11);
197		ret_user = 115;
198		break;
199	default:
200		adjust_insns(ctx->x + 177);
201		ret_user = 1019;
202		break;
203	}
204
205	return 0;
206}
207
208SEC("syscall")
209int big_jump_table(struct simple_ctx *ctx __attribute__((unused)))
210{
211	const void *const jt[256] = {
212		[0 ... 255] = &&default_label,
213		[0] = &&l0,
214		[11] = &&l11,
215		[27] = &&l27,
216		[31] = &&l31,
217	};
218
219	goto *jt[ctx->x & 0xff];
220
221l0:
222	adjust_insns(ctx->x + 1);
223	ret_user = 2;
224	return 0;
225
226l11:
227	adjust_insns(ctx->x + 7);
228	ret_user = 3;
229	return 0;
230
231l27:
232	adjust_insns(ctx->x + 9);
233	ret_user = 4;
234	return 0;
235
236l31:
237	adjust_insns(ctx->x + 11);
238	ret_user = 5;
239	return 0;
240
241default_label:
242	adjust_insns(ctx->x + 177);
243	ret_user = 19;
244	return 0;
245}
246
247SEC("syscall")
248int one_jump_two_maps(struct simple_ctx *ctx __attribute__((unused)))
249{
250	__label__ l1, l2, l3, l4;
251	void *jt1[2] = { &&l1, &&l2 };
252	void *jt2[2] = { &&l3, &&l4 };
253	unsigned int a = ctx->x % 2;
254	unsigned int b = (ctx->x / 2) % 2;
255	volatile int ret = 0;
256
257	if (!(a < 2 && b < 2))
258		return 19;
259
260	if (ctx->x % 2)
261		goto *jt1[a];
262	else
263		goto *jt2[b];
264
265	l1: ret += 1;
266	l2: ret += 3;
267	l3: ret += 5;
268	l4: ret += 7;
269
270	ret_user = ret;
271	return ret;
272}
273
274SEC("syscall")
275int one_map_two_jumps(struct simple_ctx *ctx __attribute__((unused)))
276{
277	__label__ l1, l2, l3;
278	void *jt[3] = { &&l1, &&l2, &&l3 };
279	unsigned int a = (ctx->x >> 2) & 1;
280	unsigned int b = (ctx->x >> 3) & 1;
281	volatile int ret = 0;
282
283	if (ctx->x % 2)
284		goto *jt[a];
285
286	if (ctx->x % 3)
287		goto *jt[a + b];
288
289	l1: ret += 3;
290	l2: ret += 5;
291	l3: ret += 7;
292
293	ret_user = ret;
294	return ret;
295}
296
297/* Just to introduce some non-zero offsets in .text */
298static __noinline int f0(volatile struct simple_ctx *ctx __arg_ctx)
299{
300	if (ctx)
301		return 1;
302	else
303		return 13;
304}
305
306SEC("syscall") int f1(struct simple_ctx *ctx)
307{
308	ret_user = 0;
309	return f0(ctx);
310}
311
312static __noinline int __static_global(__u64 x)
313{
314	switch (x) {
315	case 0:
316		adjust_insns(x + 1);
317		ret_user = 2;
318		break;
319	case 1:
320		adjust_insns(x + 7);
321		ret_user = 3;
322		break;
323	case 2:
324		adjust_insns(x + 9);
325		ret_user = 4;
326		break;
327	case 3:
328		adjust_insns(x + 11);
329		ret_user = 5;
330		break;
331	case 4:
332		adjust_insns(x + 17);
333		ret_user = 7;
334		break;
335	default:
336		adjust_insns(x + 177);
337		ret_user = 19;
338		break;
339	}
340
341	return 0;
342}
343
344SEC("syscall")
345int use_static_global1(struct simple_ctx *ctx)
346{
347	ret_user = 0;
348	return __static_global(ctx->x);
349}
350
351SEC("syscall")
352int use_static_global2(struct simple_ctx *ctx)
353{
354	ret_user = 0;
355	adjust_insns(ctx->x + 1);
356	return __static_global(ctx->x);
357}
358
359SEC("fentry/" SYS_PREFIX "sys_nanosleep")
360int use_static_global_other_sec(void *ctx)
361{
362	if (bpf_get_current_pid_tgid() >> 32 != pid)
363		return 0;
364
365	return __static_global(in_user);
366}
367
368__noinline int __nonstatic_global(__u64 x)
369{
370	switch (x) {
371	case 0:
372		adjust_insns(x + 1);
373		ret_user = 2;
374		break;
375	case 1:
376		adjust_insns(x + 7);
377		ret_user = 3;
378		break;
379	case 2:
380		adjust_insns(x + 9);
381		ret_user = 4;
382		break;
383	case 3:
384		adjust_insns(x + 11);
385		ret_user = 5;
386		break;
387	case 4:
388		adjust_insns(x + 17);
389		ret_user = 7;
390		break;
391	default:
392		adjust_insns(x + 177);
393		ret_user = 19;
394		break;
395	}
396
397	return 0;
398}
399
400SEC("syscall")
401int use_nonstatic_global1(struct simple_ctx *ctx)
402{
403	ret_user = 0;
404	return __nonstatic_global(ctx->x);
405}
406
407SEC("syscall")
408int use_nonstatic_global2(struct simple_ctx *ctx)
409{
410	ret_user = 0;
411	adjust_insns(ctx->x + 1);
412	return __nonstatic_global(ctx->x);
413}
414
415SEC("fentry/" SYS_PREFIX "sys_nanosleep")
416int use_nonstatic_global_other_sec(void *ctx)
417{
418	if (bpf_get_current_pid_tgid() >> 32 != pid)
419		return 0;
420
421	return __nonstatic_global(in_user);
422}
423
424#else /* __BPF_FEATURE_GOTOX */
425
426#define SKIP_TEST(TEST_NAME)				\
427	SEC("syscall") int TEST_NAME(void *ctx)		\
428	{						\
429		return 0;				\
430	}
431
432SKIP_TEST(one_switch);
433SKIP_TEST(one_switch_non_zero_sec_off);
434SKIP_TEST(simple_test_other_sec);
435SKIP_TEST(two_switches);
436SKIP_TEST(big_jump_table);
437SKIP_TEST(one_jump_two_maps);
438SKIP_TEST(one_map_two_jumps);
439SKIP_TEST(use_static_global1);
440SKIP_TEST(use_static_global2);
441SKIP_TEST(use_static_global_other_sec);
442SKIP_TEST(use_nonstatic_global1);
443SKIP_TEST(use_nonstatic_global2);
444SKIP_TEST(use_nonstatic_global_other_sec);
445
446#endif /* __BPF_FEATURE_GOTOX */
447
448char _license[] SEC("license") = "GPL";
~/ Read-only file preview.