File Index
Files and directories
Sign in
FILE

uprobe.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/prog_tests/uprobe.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2023 Hengqi Chen */
  3
  4#include <test_progs.h>
  5#include <asm/ptrace.h>
  6#include "test_uprobe.skel.h"
  7
  8static FILE *urand_spawn(int *pid)
  9{
 10	FILE *f;
 11
 12	/* urandom_read's stdout is wired into f */
 13	f = popen("./urandom_read 1 report-pid", "r");
 14	if (!f)
 15		return NULL;
 16
 17	if (fscanf(f, "%d", pid) != 1) {
 18		pclose(f);
 19		errno = EINVAL;
 20		return NULL;
 21	}
 22
 23	return f;
 24}
 25
 26static int urand_trigger(FILE **urand_pipe)
 27{
 28	int exit_code;
 29
 30	/* pclose() waits for child process to exit and returns their exit code */
 31	exit_code = pclose(*urand_pipe);
 32	*urand_pipe = NULL;
 33
 34	return exit_code;
 35}
 36
 37static void test_uprobe_attach(void)
 38{
 39	LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
 40	struct test_uprobe *skel;
 41	FILE *urand_pipe = NULL;
 42	int urand_pid = 0, err;
 43
 44	skel = test_uprobe__open_and_load();
 45	if (!ASSERT_OK_PTR(skel, "skel_open"))
 46		return;
 47
 48	urand_pipe = urand_spawn(&urand_pid);
 49	if (!ASSERT_OK_PTR(urand_pipe, "urand_spawn"))
 50		goto cleanup;
 51
 52	skel->bss->my_pid = urand_pid;
 53
 54	/* Manual attach uprobe to urandlib_api
 55	 * There are two `urandlib_api` symbols in .dynsym section:
 56	 *   - urandlib_api@LIBURANDOM_READ_1.0.0
 57	 *   - urandlib_api@@LIBURANDOM_READ_2.0.0
 58	 * Both are global bind and would cause a conflict if user
 59	 * specify the symbol name without a version suffix
 60	 */
 61	uprobe_opts.func_name = "urandlib_api";
 62	skel->links.test4 = bpf_program__attach_uprobe_opts(skel->progs.test4,
 63							    urand_pid,
 64							    "./liburandom_read.so",
 65							    0 /* offset */,
 66							    &uprobe_opts);
 67	if (!ASSERT_ERR_PTR(skel->links.test4, "urandlib_api_attach_conflict"))
 68		goto cleanup;
 69
 70	uprobe_opts.func_name = "urandlib_api@LIBURANDOM_READ_1.0.0";
 71	skel->links.test4 = bpf_program__attach_uprobe_opts(skel->progs.test4,
 72							    urand_pid,
 73							    "./liburandom_read.so",
 74							    0 /* offset */,
 75							    &uprobe_opts);
 76	if (!ASSERT_OK_PTR(skel->links.test4, "urandlib_api_attach_ok"))
 77		goto cleanup;
 78
 79	/* Auto attach 3 u[ret]probes to urandlib_api_sameoffset */
 80	err = test_uprobe__attach(skel);
 81	if (!ASSERT_OK(err, "skel_attach"))
 82		goto cleanup;
 83
 84	/* trigger urandom_read */
 85	ASSERT_OK(urand_trigger(&urand_pipe), "urand_exit_code");
 86
 87	ASSERT_EQ(skel->bss->test1_result, 1, "urandlib_api_sameoffset");
 88	ASSERT_EQ(skel->bss->test2_result, 1, "urandlib_api_sameoffset@v1");
 89	ASSERT_EQ(skel->bss->test3_result, 3, "urandlib_api_sameoffset@@v2");
 90	ASSERT_EQ(skel->bss->test4_result, 1, "urandlib_api");
 91
 92cleanup:
 93	if (urand_pipe)
 94		pclose(urand_pipe);
 95	test_uprobe__destroy(skel);
 96}
 97
 98#ifdef __x86_64__
 99__naked __maybe_unused unsigned long uprobe_regs_change_trigger(void)
100{
101	asm volatile (
102		"ret\n"
103	);
104}
105
106static __naked void uprobe_regs_change(struct pt_regs *before, struct pt_regs *after)
107{
108	asm volatile (
109		"movq %r11,  48(%rdi)\n"
110		"movq %r10,  56(%rdi)\n"
111		"movq  %r9,  64(%rdi)\n"
112		"movq  %r8,  72(%rdi)\n"
113		"movq %rax,  80(%rdi)\n"
114		"movq %rcx,  88(%rdi)\n"
115		"movq %rdx,  96(%rdi)\n"
116		"movq %rsi, 104(%rdi)\n"
117		"movq %rdi, 112(%rdi)\n"
118
119		/* save 2nd argument */
120		"pushq %rsi\n"
121		"call uprobe_regs_change_trigger\n"
122
123		/* save  return value and load 2nd argument pointer to rax */
124		"pushq %rax\n"
125		"movq 8(%rsp), %rax\n"
126
127		"movq %r11,  48(%rax)\n"
128		"movq %r10,  56(%rax)\n"
129		"movq  %r9,  64(%rax)\n"
130		"movq  %r8,  72(%rax)\n"
131		"movq %rcx,  88(%rax)\n"
132		"movq %rdx,  96(%rax)\n"
133		"movq %rsi, 104(%rax)\n"
134		"movq %rdi, 112(%rax)\n"
135
136		/* restore return value and 2nd argument */
137		"pop %rax\n"
138		"pop %rsi\n"
139
140		"movq %rax,  80(%rsi)\n"
141		"ret\n"
142	);
143}
144
145static void regs_common(void)
146{
147	struct pt_regs before = {}, after = {}, expected = {
148		.rax = 0xc0ffe,
149		.rcx = 0xbad,
150		.rdx = 0xdead,
151		.r8  = 0x8,
152		.r9  = 0x9,
153		.r10 = 0x10,
154		.r11 = 0x11,
155		.rdi = 0x12,
156		.rsi = 0x13,
157	};
158	LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
159	struct test_uprobe *skel;
160
161	skel = test_uprobe__open_and_load();
162	if (!ASSERT_OK_PTR(skel, "skel_open"))
163		return;
164
165	skel->bss->my_pid = getpid();
166	skel->bss->regs = expected;
167
168	uprobe_opts.func_name = "uprobe_regs_change_trigger";
169	skel->links.test_regs_change = bpf_program__attach_uprobe_opts(skel->progs.test_regs_change,
170							    -1,
171							    "/proc/self/exe",
172							    0 /* offset */,
173							    &uprobe_opts);
174	if (!ASSERT_OK_PTR(skel->links.test_regs_change, "bpf_program__attach_uprobe_opts"))
175		goto cleanup;
176
177	uprobe_regs_change(&before, &after);
178
179	ASSERT_EQ(after.rax, expected.rax, "ax");
180	ASSERT_EQ(after.rcx, expected.rcx, "cx");
181	ASSERT_EQ(after.rdx, expected.rdx, "dx");
182	ASSERT_EQ(after.r8,  expected.r8,  "r8");
183	ASSERT_EQ(after.r9,  expected.r9,  "r9");
184	ASSERT_EQ(after.r10, expected.r10, "r10");
185	ASSERT_EQ(after.r11, expected.r11, "r11");
186	ASSERT_EQ(after.rdi, expected.rdi, "rdi");
187	ASSERT_EQ(after.rsi, expected.rsi, "rsi");
188
189cleanup:
190	test_uprobe__destroy(skel);
191}
192
193static noinline unsigned long uprobe_regs_change_ip_1(void)
194{
195	return 0xc0ffee;
196}
197
198static noinline unsigned long uprobe_regs_change_ip_2(void)
199{
200	return 0xdeadbeef;
201}
202
203static void regs_ip(void)
204{
205	LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
206	struct test_uprobe *skel;
207	unsigned long ret;
208
209	skel = test_uprobe__open_and_load();
210	if (!ASSERT_OK_PTR(skel, "skel_open"))
211		return;
212
213	skel->bss->my_pid = getpid();
214	skel->bss->ip = (unsigned long) uprobe_regs_change_ip_2;
215
216	uprobe_opts.func_name = "uprobe_regs_change_ip_1";
217	skel->links.test_regs_change_ip = bpf_program__attach_uprobe_opts(
218						skel->progs.test_regs_change_ip,
219						-1,
220						"/proc/self/exe",
221						0 /* offset */,
222						&uprobe_opts);
223	if (!ASSERT_OK_PTR(skel->links.test_regs_change_ip, "bpf_program__attach_uprobe_opts"))
224		goto cleanup;
225
226	ret = uprobe_regs_change_ip_1();
227	ASSERT_EQ(ret, 0xdeadbeef, "ret");
228
229cleanup:
230	test_uprobe__destroy(skel);
231}
232
233static void test_uprobe_regs_change(void)
234{
235	if (test__start_subtest("regs_change_common"))
236		regs_common();
237	if (test__start_subtest("regs_change_ip"))
238		regs_ip();
239}
240#else
241static void test_uprobe_regs_change(void) { }
242#endif
243
244void test_uprobe(void)
245{
246	if (test__start_subtest("attach"))
247		test_uprobe_attach();
248	test_uprobe_regs_change();
249}
~/ Read-only file preview.