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