xref: /linux/tools/testing/selftests/bpf/progs/get_func_args_test.c (revision a8471eb0747f083ae5bde949e667d3d799d65cf7)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <vmlinux.h>
3 #include <bpf/bpf_helpers.h>
4 #include <bpf/bpf_tracing.h>
5 #include <errno.h>
6 
7 char _license[] SEC("license") = "GPL";
8 
9 /* Keep the upper index bits: the inlined expansion must truncate them. */
10 static long (*bpf_get_func_arg_wide)(void *ctx, __u64 n, __u64 *value) =
11 	(void *)BPF_FUNC_get_func_arg;
12 
13 /* Both traced functions are called with arguments 2 and 3. */
14 static __always_inline int check_wide_index(void *ctx)
15 {
16 	__u64 a = 0, z = 0xdeadbeefdeadbeefULL;
17 	__s64 err;
18 	int ok = 1;
19 
20 	/* The index is truncated to u32, so these select arguments 0 and 1. */
21 	err = bpf_get_func_arg_wide(ctx, 1ULL << 32, &a);
22 	ok &= err == 0 && ((int)a == 2);
23 	err = bpf_get_func_arg_wide(ctx, (1ULL << 32) | 1, &a);
24 	ok &= err == 0 && a == 3;
25 	err = bpf_get_func_arg_wide(ctx, 1ULL << 59, &a);
26 	ok &= err == 0 && ((int)a == 2);
27 	err = bpf_get_func_arg_wide(ctx, (1ULL << 59) | 1, &a);
28 	ok &= err == 0 && a == 3;
29 
30 	/* Out of range: -EINVAL and no store into the destination. */
31 	err = bpf_get_func_arg_wide(ctx, (1ULL << 32) | 2, &z);
32 	ok &= err == -EINVAL && z == 0xdeadbeefdeadbeefULL;
33 	err = bpf_get_func_arg_wide(ctx, (1ULL << 32) | 0xffffffffULL, &z);
34 	ok &= err == -EINVAL && z == 0xdeadbeefdeadbeefULL;
35 	err = bpf_get_func_arg_wide(ctx, (1ULL << 59) | 2, &z);
36 	ok &= err == -EINVAL && z == 0xdeadbeefdeadbeefULL;
37 	err = bpf_get_func_arg_wide(ctx, (1ULL << 59) | 0xffffffffULL, &z);
38 	ok &= err == -EINVAL && z == 0xdeadbeefdeadbeefULL;
39 
40 	return ok;
41 }
42 
43 __u64 test1_result = 0;
44 SEC("fentry/bpf_fentry_test1")
45 int BPF_PROG(test1)
46 {
47 	__u64 cnt = bpf_get_func_arg_cnt(ctx);
48 	__u64 a = 0, z = 0, ret = 0;
49 	__s64 err;
50 
51 	test1_result = cnt == 1;
52 
53 	/* valid arguments */
54 	err = bpf_get_func_arg(ctx, 0, &a);
55 
56 	/* We need to cast access to traced function argument values with
57 	 * proper type cast, because trampoline uses type specific instruction
58 	 * to save it, like for 'int a' with 32-bit mov like:
59 	 *
60 	 *   mov %edi,-0x8(%rbp)
61 	 *
62 	 * so the upper 4 bytes are not zeroed.
63 	 */
64 	test1_result &= err == 0 && ((int) a == 1);
65 
66 	/* not valid argument */
67 	err = bpf_get_func_arg(ctx, 1, &z);
68 	test1_result &= err == -EINVAL;
69 
70 	/* return value fails in fentry */
71 	err = bpf_get_func_ret(ctx, &ret);
72 	test1_result &= err == -EOPNOTSUPP;
73 	return 0;
74 }
75 
76 __u64 test2_result = 0;
77 SEC("fexit/bpf_fentry_test2")
78 int BPF_PROG(test2)
79 {
80 	__u64 cnt = bpf_get_func_arg_cnt(ctx);
81 	__u64 a = 0, b = 0, z = 0, ret = 0;
82 	__s64 err;
83 
84 	test2_result = cnt == 2;
85 
86 	/* valid arguments */
87 	err = bpf_get_func_arg(ctx, 0, &a);
88 	test2_result &= err == 0 && (int) a == 2;
89 
90 	err = bpf_get_func_arg(ctx, 1, &b);
91 	test2_result &= err == 0 && b == 3;
92 
93 	/* not valid argument */
94 	err = bpf_get_func_arg(ctx, 2, &z);
95 	test2_result &= err == -EINVAL;
96 
97 	/* return value */
98 	err = bpf_get_func_ret(ctx, &ret);
99 	test2_result &= err == 0 && ret == 5;
100 	test2_result &= check_wide_index(ctx);
101 	return 0;
102 }
103 
104 __u64 test3_result = 0;
105 SEC("fmod_ret/bpf_modify_return_test")
106 int BPF_PROG(fmod_ret_test, int _a, int *_b, int _ret)
107 {
108 	__u64 cnt = bpf_get_func_arg_cnt(ctx);
109 	__u64 a = 0, b = 0, z = 0, ret = 0;
110 	__s64 err;
111 
112 	test3_result = cnt == 2;
113 
114 	/* valid arguments */
115 	err = bpf_get_func_arg(ctx, 0, &a);
116 	test3_result &= err == 0 && ((int) a == 1);
117 
118 	err = bpf_get_func_arg(ctx, 1, &b);
119 	test3_result &= err == 0 && ((int *) b == _b);
120 
121 	/* not valid argument */
122 	err = bpf_get_func_arg(ctx, 2, &z);
123 	test3_result &= err == -EINVAL;
124 
125 	/* return value */
126 	err = bpf_get_func_ret(ctx, &ret);
127 	test3_result &= err == 0 && ret == 0;
128 
129 	/* change return value, it's checked in fexit_test program */
130 	return 1234;
131 }
132 
133 __u64 test4_result = 0;
134 SEC("fexit/bpf_modify_return_test")
135 int BPF_PROG(fexit_test, int _a, int *_b, int _ret)
136 {
137 	__u64 cnt = bpf_get_func_arg_cnt(ctx);
138 	__u64 a = 0, b = 0, z = 0, ret = 0;
139 	__s64 err;
140 
141 	test4_result = cnt == 2;
142 
143 	/* valid arguments */
144 	err = bpf_get_func_arg(ctx, 0, &a);
145 	test4_result &= err == 0 && ((int) a == 1);
146 
147 	err = bpf_get_func_arg(ctx, 1, &b);
148 	test4_result &= err == 0 && ((int *) b == _b);
149 
150 	/* not valid argument */
151 	err = bpf_get_func_arg(ctx, 2, &z);
152 	test4_result &= err == -EINVAL;
153 
154 	/* return value */
155 	err = bpf_get_func_ret(ctx, &ret);
156 	test4_result &= err == 0 && ret == 1234;
157 	return 0;
158 }
159 
160 __u64 test5_result = 0;
161 SEC("tp_btf/bpf_testmod_fentry_test1_tp")
162 int BPF_PROG(tp_test1)
163 {
164 	__u64 cnt = bpf_get_func_arg_cnt(ctx);
165 	__u64 a = 0, z = 0;
166 	__s64 err;
167 
168 	test5_result = cnt == 1;
169 
170 	err = bpf_get_func_arg(ctx, 0, &a);
171 	test5_result &= err == 0 && ((int) a == 1);
172 
173 	/* not valid argument */
174 	err = bpf_get_func_arg(ctx, 1, &z);
175 	test5_result &= err == -EINVAL;
176 
177 	return 0;
178 }
179 
180 __u64 test6_result = 0;
181 SEC("tp_btf/bpf_testmod_fentry_test2_tp")
182 int BPF_PROG(tp_test2)
183 {
184 	__u64 cnt = bpf_get_func_arg_cnt(ctx);
185 	__u64 a = 0, b = 0, z = 0;
186 	__s64 err;
187 
188 	test6_result = cnt == 2;
189 
190 	/* valid arguments */
191 	err = bpf_get_func_arg(ctx, 0, &a);
192 	test6_result &= err == 0 && (int) a == 2;
193 
194 	err = bpf_get_func_arg(ctx, 1, &b);
195 	test6_result &= err == 0 && b == 3;
196 
197 	/* not valid argument */
198 	err = bpf_get_func_arg(ctx, 2, &z);
199 	test6_result &= err == -EINVAL;
200 	test6_result &= check_wide_index(ctx);
201 
202 	return 0;
203 }
204