1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2021 Facebook */
3 
4 #include "vmlinux.h"
5 #include <bpf/bpf_helpers.h>
6 
7 char _license[] SEC("license") = "GPL";
8 
9 struct callback_ctx {
10 	int output;
11 };
12 
13 /* These should be set by the user program */
14 u32 nested_callback_nr_loops;
15 u32 stop_index = -1;
16 u32 nr_loops;
17 int pid;
18 
19 /* Making these global variables so that the userspace program
20  * can verify the output through the skeleton
21  */
22 int nr_loops_returned;
23 int g_output;
24 int err;
25 
26 static int callback(__u32 index, void *data)
27 {
28 	struct callback_ctx *ctx = data;
29 
30 	if (index >= stop_index)
31 		return 1;
32 
33 	ctx->output += index;
34 
35 	return 0;
36 }
37 
38 static int empty_callback(__u32 index, void *data)
39 {
40 	return 0;
41 }
42 
43 static int nested_callback2(__u32 index, void *data)
44 {
45 	nr_loops_returned += bpf_loop(nested_callback_nr_loops, callback, data, 0);
46 
47 	return 0;
48 }
49 
50 static int nested_callback1(__u32 index, void *data)
51 {
52 	bpf_loop(nested_callback_nr_loops, nested_callback2, data, 0);
53 	return 0;
54 }
55 
56 SEC("fentry/__x64_sys_nanosleep")
57 int test_prog(void *ctx)
58 {
59 	struct callback_ctx data = {};
60 
61 	if (bpf_get_current_pid_tgid() >> 32 != pid)
62 		return 0;
63 
64 	nr_loops_returned = bpf_loop(nr_loops, callback, &data, 0);
65 
66 	if (nr_loops_returned < 0)
67 		err = nr_loops_returned;
68 	else
69 		g_output = data.output;
70 
71 	return 0;
72 }
73 
74 SEC("fentry/__x64_sys_nanosleep")
75 int prog_null_ctx(void *ctx)
76 {
77 	if (bpf_get_current_pid_tgid() >> 32 != pid)
78 		return 0;
79 
80 	nr_loops_returned = bpf_loop(nr_loops, empty_callback, NULL, 0);
81 
82 	return 0;
83 }
84 
85 SEC("fentry/__x64_sys_nanosleep")
86 int prog_invalid_flags(void *ctx)
87 {
88 	struct callback_ctx data = {};
89 
90 	if (bpf_get_current_pid_tgid() >> 32 != pid)
91 		return 0;
92 
93 	err = bpf_loop(nr_loops, callback, &data, 1);
94 
95 	return 0;
96 }
97 
98 SEC("fentry/__x64_sys_nanosleep")
99 int prog_nested_calls(void *ctx)
100 {
101 	struct callback_ctx data = {};
102 
103 	if (bpf_get_current_pid_tgid() >> 32 != pid)
104 		return 0;
105 
106 	nr_loops_returned = 0;
107 	bpf_loop(nr_loops, nested_callback1, &data, 0);
108 
109 	g_output = data.output;
110 
111 	return 0;
112 }
113