]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / bpf / prog_tests / uprobe_syscall.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <test_progs.h>
4
5 #ifdef __x86_64__
6
7 #include <unistd.h>
8 #include <asm/ptrace.h>
9 #include <linux/compiler.h>
10 #include <linux/stringify.h>
11 #include <sys/wait.h>
12 #include <sys/syscall.h>
13 #include <sys/prctl.h>
14 #include <asm/prctl.h>
15 #include "uprobe_syscall.skel.h"
16 #include "uprobe_syscall_executed.skel.h"
17
18 __naked unsigned long uretprobe_regs_trigger(void)
19 {
20         asm volatile (
21                 "movq $0xdeadbeef, %rax\n"
22                 "ret\n"
23         );
24 }
25
26 __naked void uretprobe_regs(struct pt_regs *before, struct pt_regs *after)
27 {
28         asm volatile (
29                 "movq %r15,   0(%rdi)\n"
30                 "movq %r14,   8(%rdi)\n"
31                 "movq %r13,  16(%rdi)\n"
32                 "movq %r12,  24(%rdi)\n"
33                 "movq %rbp,  32(%rdi)\n"
34                 "movq %rbx,  40(%rdi)\n"
35                 "movq %r11,  48(%rdi)\n"
36                 "movq %r10,  56(%rdi)\n"
37                 "movq  %r9,  64(%rdi)\n"
38                 "movq  %r8,  72(%rdi)\n"
39                 "movq %rax,  80(%rdi)\n"
40                 "movq %rcx,  88(%rdi)\n"
41                 "movq %rdx,  96(%rdi)\n"
42                 "movq %rsi, 104(%rdi)\n"
43                 "movq %rdi, 112(%rdi)\n"
44                 "movq   $0, 120(%rdi)\n" /* orig_rax */
45                 "movq   $0, 128(%rdi)\n" /* rip      */
46                 "movq   $0, 136(%rdi)\n" /* cs       */
47                 "pushf\n"
48                 "pop %rax\n"
49                 "movq %rax, 144(%rdi)\n" /* eflags   */
50                 "movq %rsp, 152(%rdi)\n" /* rsp      */
51                 "movq   $0, 160(%rdi)\n" /* ss       */
52
53                 /* save 2nd argument */
54                 "pushq %rsi\n"
55                 "call uretprobe_regs_trigger\n"
56
57                 /* save  return value and load 2nd argument pointer to rax */
58                 "pushq %rax\n"
59                 "movq 8(%rsp), %rax\n"
60
61                 "movq %r15,   0(%rax)\n"
62                 "movq %r14,   8(%rax)\n"
63                 "movq %r13,  16(%rax)\n"
64                 "movq %r12,  24(%rax)\n"
65                 "movq %rbp,  32(%rax)\n"
66                 "movq %rbx,  40(%rax)\n"
67                 "movq %r11,  48(%rax)\n"
68                 "movq %r10,  56(%rax)\n"
69                 "movq  %r9,  64(%rax)\n"
70                 "movq  %r8,  72(%rax)\n"
71                 "movq %rcx,  88(%rax)\n"
72                 "movq %rdx,  96(%rax)\n"
73                 "movq %rsi, 104(%rax)\n"
74                 "movq %rdi, 112(%rax)\n"
75                 "movq   $0, 120(%rax)\n" /* orig_rax */
76                 "movq   $0, 128(%rax)\n" /* rip      */
77                 "movq   $0, 136(%rax)\n" /* cs       */
78
79                 /* restore return value and 2nd argument */
80                 "pop %rax\n"
81                 "pop %rsi\n"
82
83                 "movq %rax,  80(%rsi)\n"
84
85                 "pushf\n"
86                 "pop %rax\n"
87
88                 "movq %rax, 144(%rsi)\n" /* eflags   */
89                 "movq %rsp, 152(%rsi)\n" /* rsp      */
90                 "movq   $0, 160(%rsi)\n" /* ss       */
91                 "ret\n"
92 );
93 }
94
95 static void test_uretprobe_regs_equal(void)
96 {
97         struct uprobe_syscall *skel = NULL;
98         struct pt_regs before = {}, after = {};
99         unsigned long *pb = (unsigned long *) &before;
100         unsigned long *pa = (unsigned long *) &after;
101         unsigned long *pp;
102         unsigned int i, cnt;
103         int err;
104
105         skel = uprobe_syscall__open_and_load();
106         if (!ASSERT_OK_PTR(skel, "uprobe_syscall__open_and_load"))
107                 goto cleanup;
108
109         err = uprobe_syscall__attach(skel);
110         if (!ASSERT_OK(err, "uprobe_syscall__attach"))
111                 goto cleanup;
112
113         uretprobe_regs(&before, &after);
114
115         pp = (unsigned long *) &skel->bss->regs;
116         cnt = sizeof(before)/sizeof(*pb);
117
118         for (i = 0; i < cnt; i++) {
119                 unsigned int offset = i * sizeof(unsigned long);
120
121                 /*
122                  * Check register before and after uretprobe_regs_trigger call
123                  * that triggers the uretprobe.
124                  */
125                 switch (offset) {
126                 case offsetof(struct pt_regs, rax):
127                         ASSERT_EQ(pa[i], 0xdeadbeef, "return value");
128                         break;
129                 default:
130                         if (!ASSERT_EQ(pb[i], pa[i], "register before-after value check"))
131                                 fprintf(stdout, "failed register offset %u\n", offset);
132                 }
133
134                 /*
135                  * Check register seen from bpf program and register after
136                  * uretprobe_regs_trigger call
137                  */
138                 switch (offset) {
139                 /*
140                  * These values will be different (not set in uretprobe_regs),
141                  * we don't care.
142                  */
143                 case offsetof(struct pt_regs, orig_rax):
144                 case offsetof(struct pt_regs, rip):
145                 case offsetof(struct pt_regs, cs):
146                 case offsetof(struct pt_regs, rsp):
147                 case offsetof(struct pt_regs, ss):
148                         break;
149                 default:
150                         if (!ASSERT_EQ(pp[i], pa[i], "register prog-after value check"))
151                                 fprintf(stdout, "failed register offset %u\n", offset);
152                 }
153         }
154
155 cleanup:
156         uprobe_syscall__destroy(skel);
157 }
158
159 #define BPF_TESTMOD_UPROBE_TEST_FILE "/sys/kernel/bpf_testmod_uprobe"
160
161 static int write_bpf_testmod_uprobe(unsigned long offset)
162 {
163         size_t n, ret;
164         char buf[30];
165         int fd;
166
167         n = sprintf(buf, "%lu", offset);
168
169         fd = open(BPF_TESTMOD_UPROBE_TEST_FILE, O_WRONLY);
170         if (fd < 0)
171                 return -errno;
172
173         ret = write(fd, buf, n);
174         close(fd);
175         return ret != n ? (int) ret : 0;
176 }
177
178 static void test_uretprobe_regs_change(void)
179 {
180         struct pt_regs before = {}, after = {};
181         unsigned long *pb = (unsigned long *) &before;
182         unsigned long *pa = (unsigned long *) &after;
183         unsigned long cnt = sizeof(before)/sizeof(*pb);
184         unsigned int i, err, offset;
185
186         offset = get_uprobe_offset(uretprobe_regs_trigger);
187
188         err = write_bpf_testmod_uprobe(offset);
189         if (!ASSERT_OK(err, "register_uprobe"))
190                 return;
191
192         uretprobe_regs(&before, &after);
193
194         err = write_bpf_testmod_uprobe(0);
195         if (!ASSERT_OK(err, "unregister_uprobe"))
196                 return;
197
198         for (i = 0; i < cnt; i++) {
199                 unsigned int offset = i * sizeof(unsigned long);
200
201                 switch (offset) {
202                 case offsetof(struct pt_regs, rax):
203                         ASSERT_EQ(pa[i], 0x12345678deadbeef, "rax");
204                         break;
205                 case offsetof(struct pt_regs, rcx):
206                         ASSERT_EQ(pa[i], 0x87654321feebdaed, "rcx");
207                         break;
208                 case offsetof(struct pt_regs, r11):
209                         ASSERT_EQ(pa[i], (__u64) -1, "r11");
210                         break;
211                 default:
212                         if (!ASSERT_EQ(pa[i], pb[i], "register before-after value check"))
213                                 fprintf(stdout, "failed register offset %u\n", offset);
214                 }
215         }
216 }
217
218 #ifndef __NR_uretprobe
219 #define __NR_uretprobe 335
220 #endif
221
222 __naked unsigned long uretprobe_syscall_call_1(void)
223 {
224         /*
225          * Pretend we are uretprobe trampoline to trigger the return
226          * probe invocation in order to verify we get SIGILL.
227          */
228         asm volatile (
229                 "pushq %rax\n"
230                 "pushq %rcx\n"
231                 "pushq %r11\n"
232                 "movq $" __stringify(__NR_uretprobe) ", %rax\n"
233                 "syscall\n"
234                 "popq %r11\n"
235                 "popq %rcx\n"
236                 "retq\n"
237         );
238 }
239
240 __naked unsigned long uretprobe_syscall_call(void)
241 {
242         asm volatile (
243                 "call uretprobe_syscall_call_1\n"
244                 "retq\n"
245         );
246 }
247
248 static void test_uretprobe_syscall_call(void)
249 {
250         LIBBPF_OPTS(bpf_uprobe_multi_opts, opts,
251                 .retprobe = true,
252         );
253         struct uprobe_syscall_executed *skel;
254         int pid, status, err, go[2], c;
255
256         if (!ASSERT_OK(pipe(go), "pipe"))
257                 return;
258
259         skel = uprobe_syscall_executed__open_and_load();
260         if (!ASSERT_OK_PTR(skel, "uprobe_syscall_executed__open_and_load"))
261                 goto cleanup;
262
263         pid = fork();
264         if (!ASSERT_GE(pid, 0, "fork"))
265                 goto cleanup;
266
267         /* child */
268         if (pid == 0) {
269                 close(go[1]);
270
271                 /* wait for parent's kick */
272                 err = read(go[0], &c, 1);
273                 if (err != 1)
274                         exit(-1);
275
276                 uretprobe_syscall_call();
277                 _exit(0);
278         }
279
280         skel->links.test = bpf_program__attach_uprobe_multi(skel->progs.test, pid,
281                                                             "/proc/self/exe",
282                                                             "uretprobe_syscall_call", &opts);
283         if (!ASSERT_OK_PTR(skel->links.test, "bpf_program__attach_uprobe_multi"))
284                 goto cleanup;
285
286         /* kick the child */
287         write(go[1], &c, 1);
288         err = waitpid(pid, &status, 0);
289         ASSERT_EQ(err, pid, "waitpid");
290
291         /* verify the child got killed with SIGILL */
292         ASSERT_EQ(WIFSIGNALED(status), 1, "WIFSIGNALED");
293         ASSERT_EQ(WTERMSIG(status), SIGILL, "WTERMSIG");
294
295         /* verify the uretprobe program wasn't called */
296         ASSERT_EQ(skel->bss->executed, 0, "executed");
297
298 cleanup:
299         uprobe_syscall_executed__destroy(skel);
300         close(go[1]);
301         close(go[0]);
302 }
303
304 /*
305  * Borrowed from tools/testing/selftests/x86/test_shadow_stack.c.
306  *
307  * For use in inline enablement of shadow stack.
308  *
309  * The program can't return from the point where shadow stack gets enabled
310  * because there will be no address on the shadow stack. So it can't use
311  * syscall() for enablement, since it is a function.
312  *
313  * Based on code from nolibc.h. Keep a copy here because this can't pull
314  * in all of nolibc.h.
315  */
316 #define ARCH_PRCTL(arg1, arg2)                                  \
317 ({                                                              \
318         long _ret;                                              \
319         register long _num  asm("eax") = __NR_arch_prctl;       \
320         register long _arg1 asm("rdi") = (long)(arg1);          \
321         register long _arg2 asm("rsi") = (long)(arg2);          \
322                                                                 \
323         asm volatile (                                          \
324                 "syscall\n"                                     \
325                 : "=a"(_ret)                                    \
326                 : "r"(_arg1), "r"(_arg2),                       \
327                   "0"(_num)                                     \
328                 : "rcx", "r11", "memory", "cc"                  \
329         );                                                      \
330         _ret;                                                   \
331 })
332
333 #ifndef ARCH_SHSTK_ENABLE
334 #define ARCH_SHSTK_ENABLE       0x5001
335 #define ARCH_SHSTK_DISABLE      0x5002
336 #define ARCH_SHSTK_SHSTK        (1ULL <<  0)
337 #endif
338
339 static void test_uretprobe_shadow_stack(void)
340 {
341         if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {
342                 test__skip();
343                 return;
344         }
345
346         /* Run all of the uretprobe tests. */
347         test_uretprobe_regs_equal();
348         test_uretprobe_regs_change();
349         test_uretprobe_syscall_call();
350
351         ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
352 }
353 #else
354 static void test_uretprobe_regs_equal(void)
355 {
356         test__skip();
357 }
358
359 static void test_uretprobe_regs_change(void)
360 {
361         test__skip();
362 }
363
364 static void test_uretprobe_syscall_call(void)
365 {
366         test__skip();
367 }
368
369 static void test_uretprobe_shadow_stack(void)
370 {
371         test__skip();
372 }
373 #endif
374
375 void test_uprobe_syscall(void)
376 {
377         if (test__start_subtest("uretprobe_regs_equal"))
378                 test_uretprobe_regs_equal();
379         if (test__start_subtest("uretprobe_regs_change"))
380                 test_uretprobe_regs_change();
381         if (test__start_subtest("uretprobe_syscall_call"))
382                 test_uretprobe_syscall_call();
383         if (test__start_subtest("uretprobe_shadow_stack"))
384                 test_uretprobe_shadow_stack();
385 }
This page took 0.051119 seconds and 4 git commands to generate.