Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  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
 95static 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
155cleanup:
156	uprobe_syscall__destroy(skel);
157}
158
159#define BPF_TESTMOD_UPROBE_TEST_FILE "/sys/kernel/bpf_testmod_uprobe"
160
161static 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
178static 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
248static 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
298cleanup:
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
339static 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
354static void test_uretprobe_regs_equal(void)
355{
356	test__skip();
357}
358
359static void test_uretprobe_regs_change(void)
360{
361	test__skip();
362}
363
364static void test_uretprobe_syscall_call(void)
365{
366	test__skip();
367}
368
369static void test_uretprobe_shadow_stack(void)
370{
371	test__skip();
372}
373#endif
374
375void 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}