BPF List
 help / color / mirror / Atom feed
From: Jiri Olsa <jolsa@kernel.org>
To: Oleg Nesterov <oleg@redhat.com>,
	Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>
Cc: bpf@vger.kernel.org, Song Liu <songliubraving@fb.com>,
	Yonghong Song <yhs@fb.com>,
	John Fastabend <john.fastabend@gmail.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	"Borislav Petkov (AMD)" <bp@alien8.de>,
	x86@kernel.org
Subject: [PATCH RFC bpf-next 2/3] selftests/bpf: Add uretprobe syscall test
Date: Mon, 18 Mar 2024 10:31:37 +0100	[thread overview]
Message-ID: <20240318093139.293497-3-jolsa@kernel.org> (raw)
In-Reply-To: <20240318093139.293497-1-jolsa@kernel.org>

Add uretprobe syscall test and compare register values before
and after the uretprobe is hit. Also compare the register values
seen from attached bpf program.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/testing/selftests/bpf/Makefile          | 13 ++-
 .../bpf/prog_tests/arch/x86/uprobe_syscall.S  | 89 +++++++++++++++++++
 .../selftests/bpf/prog_tests/uprobe_syscall.c | 84 +++++++++++++++++
 .../selftests/bpf/progs/uprobe_syscall.c      | 15 ++++
 4 files changed, 200 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/arch/x86/uprobe_syscall.S
 create mode 100644 tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
 create mode 100644 tools/testing/selftests/bpf/progs/uprobe_syscall.c

diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 3b9eb40d6343..e425a946276b 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -490,6 +490,9 @@ TRUNNER_TEST_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.test.o,	\
 				 $$(notdir $$(wildcard $(TRUNNER_TESTS_DIR)/*.c)))
 TRUNNER_EXTRA_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o,		\
 				 $$(filter %.c,$(TRUNNER_EXTRA_SOURCES)))
+TRUNNER_ASM_OBJS := $$(patsubst %.S,$$(TRUNNER_OUTPUT)/%.arch.o,	\
+				 $$(notdir $$(wildcard $(TRUNNER_TESTS_DIR)/arch/$(SRCARCH)/*.S)))
+
 TRUNNER_EXTRA_HDRS := $$(filter %.h,$(TRUNNER_EXTRA_SOURCES))
 TRUNNER_TESTS_HDR := $(TRUNNER_TESTS_DIR)/tests.h
 TRUNNER_BPF_SRCS := $$(notdir $$(wildcard $(TRUNNER_BPF_PROGS_DIR)/*.c))
@@ -597,6 +600,13 @@ $(TRUNNER_EXTRA_OBJS): $(TRUNNER_OUTPUT)/%.o:				\
 	$$(call msg,EXT-OBJ,$(TRUNNER_BINARY),$$@)
 	$(Q)$$(CC) $$(CFLAGS) -c $$< $$(LDLIBS) -o $$@
 
+$(TRUNNER_ASM_OBJS): $(TRUNNER_OUTPUT)/%.arch.o:			\
+		       $(TRUNNER_TESTS_DIR)/arch/$(SRCARCH)/%.S		\
+		       $(TRUNNER_TESTS_HDR)				\
+		       $$(BPFOBJ) | $(TRUNNER_OUTPUT)
+	$$(call msg,ASM-OBJ,$(TRUNNER_BINARY),$$@)
+	$(Q)$$(CC) $$(CFLAGS) -c $$< $$(LDLIBS) -o $$@
+
 # non-flavored in-srctree builds receive special treatment, in particular, we
 # do not need to copy extra resources (see e.g. test_btf_dump_case())
 $(TRUNNER_BINARY)-extras: $(TRUNNER_EXTRA_FILES) | $(TRUNNER_OUTPUT)
@@ -606,7 +616,8 @@ ifneq ($2:$(OUTPUT),:$(shell pwd))
 endif
 
 $(OUTPUT)/$(TRUNNER_BINARY): $(TRUNNER_TEST_OBJS)			\
-			     $(TRUNNER_EXTRA_OBJS) $$(BPFOBJ)		\
+			     $(TRUNNER_EXTRA_OBJS) $(TRUNNER_ASM_OBJS)	\
+			     $$(BPFOBJ)					\
 			     $(RESOLVE_BTFIDS)				\
 			     $(TRUNNER_BPFTOOL)				\
 			     | $(TRUNNER_BINARY)-extras
diff --git a/tools/testing/selftests/bpf/prog_tests/arch/x86/uprobe_syscall.S b/tools/testing/selftests/bpf/prog_tests/arch/x86/uprobe_syscall.S
new file mode 100644
index 000000000000..bcbad218c4d6
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/arch/x86/uprobe_syscall.S
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef ASM_NL
+#define ASM_NL	 ;
+#endif
+
+#define SYM_ENTRY(name)			\
+	.globl name ASM_NL		\
+	name:
+
+#define SYM_END(name)			\
+	.type name STT_FUNC ASM_NL	\
+	.size name, .-name ASM_NL
+
+.code64
+.section .text, "ax"
+
+SYM_ENTRY(uprobe_syscall_arch_test)
+	movq $0xdeadbeef, %rax
+	ret
+SYM_END(uprobe_syscall_arch_test)
+
+.globl uprobe_syscall_arch
+uprobe_syscall_arch:
+	movq %r15,   0(%rdi)
+	movq %r14,   8(%rdi)
+	movq %r13,  16(%rdi)
+	movq %r12,  24(%rdi)
+	movq %rbp,  32(%rdi)
+	movq %rbx,  40(%rdi)
+	movq %r11,  48(%rdi)
+	movq %r10,  56(%rdi)
+	movq  %r9,  64(%rdi)
+	movq  %r8,  72(%rdi)
+	movq %rax,  80(%rdi)
+	movq %rcx,  88(%rdi)
+	movq %rdx,  96(%rdi)
+	movq %rsi, 104(%rdi)
+	movq %rdi, 112(%rdi)
+	movq   $0, 120(%rdi) /* orig_rax */
+	movq   $0, 128(%rdi) /* rip      */
+	movq   $0, 136(%rdi) /* cs       */
+
+	pushf
+	pop %rax
+
+	movq %rax, 144(%rdi) /* eflags   */
+	movq %rsp, 152(%rdi) /* rsp      */
+	movq   $0, 160(%rdi) /* ss       */
+
+	pushq %rsi
+	call uprobe_syscall_arch_test
+
+	/* store return value and get second argument pointer  to rax */
+	pushq %rax
+	movq 8(%rsp), %rax
+
+	movq %r15,   0(%rax)
+	movq %r14,   8(%rax)
+	movq %r13,  16(%rax)
+	movq %r12,  24(%rax)
+	movq %rbp,  32(%rax)
+	movq %rbx,  40(%rax)
+	movq %r11,  48(%rax)
+	movq %r10,  56(%rax)
+	movq  %r9,  64(%rax)
+	movq  %r8,  72(%rax)
+	movq %rcx,  88(%rax)
+	movq %rdx,  96(%rax)
+	movq %rsi, 104(%rax)
+	movq %rdi, 112(%rax)
+	movq   $0, 120(%rax) /* orig_rax */
+	movq   $0, 128(%rax) /* rip      */
+	movq   $0, 136(%rax) /* cs       */
+
+	pop %rax
+	pop %rsi
+	movq %rax,  80(%rsi)
+
+	pushf
+	pop %rax
+
+	movq %rax, 144(%rsi) /* eflags   */
+	movq %rsp, 152(%rsi) /* rsp      */
+	movq   $0, 160(%rsi) /* ss       */
+
+	ret
+
+.section .note.GNU-stack,"",@progbits
diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
new file mode 100644
index 000000000000..0df205fea957
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/uprobe_syscall.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+
+#ifdef __x86_64__
+
+#include <unistd.h>
+#include <asm/ptrace.h>
+#include "uprobe_syscall.skel.h"
+
+extern int uprobe_syscall_arch(struct pt_regs *before, struct pt_regs *after);
+
+static void test_uretprobe(void)
+{
+	struct pt_regs before = {}, after = {};
+	unsigned long *pb = (unsigned long *) &before;
+	unsigned long *pa = (unsigned long *) &after;
+	unsigned long *prog_regs;
+	struct uprobe_syscall *skel = NULL;
+	unsigned int i, cnt;
+	int err;
+
+	skel = uprobe_syscall__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "uprobe_syscall__open_and_load"))
+		goto cleanup;
+
+	err = uprobe_syscall__attach(skel);
+	if (!ASSERT_OK(err, "uprobe_syscall__attach"))
+		goto cleanup;
+
+	uprobe_syscall_arch(&before, &after);
+
+	prog_regs = (unsigned long *) &skel->bss->regs;
+	cnt = sizeof(before)/sizeof(*pb);
+
+	for (i = 0; i < cnt; i++) {
+		unsigned int offset = i * sizeof(unsigned long);
+
+		/*
+		 * Check register before and after uprobe_syscall_arch_test call
+		 * that triggers the uretprobe.
+		 */
+		switch (offset) {
+		case offsetof(struct pt_regs, rax):
+			ASSERT_EQ(pa[i], 0xdeadbeef, "return value");
+			break;
+		default:
+			if (!ASSERT_EQ(pb[i], pa[i], "register before-after value check"))
+				fprintf(stdout, "failed register offset %u\n", offset);
+		}
+
+		/*
+		 * Check register seen from bpf program and register after
+		 * uprobe_syscall_arch_test call
+		 */
+		switch (offset) {
+		/*
+		 * These will be different (not set in uprobe_syscall_arch),
+		 * we don't care.
+		 */
+		case offsetof(struct pt_regs, orig_rax):
+		case offsetof(struct pt_regs, rip):
+		case offsetof(struct pt_regs, cs):
+		case offsetof(struct pt_regs, rsp):
+		case offsetof(struct pt_regs, ss):
+			break;
+		default:
+			if (!ASSERT_EQ(prog_regs[i], pa[i], "register prog-after value check"))
+				fprintf(stdout, "failed register offset %u\n", offset);
+		}
+	}
+
+cleanup:
+	uprobe_syscall__destroy(skel);
+}
+#else
+static void test_uretprobe(void) { }
+#endif
+
+void test_uprobe_syscall(void)
+{
+	if (test__start_subtest("uretprobe"))
+		test_uretprobe();
+}
diff --git a/tools/testing/selftests/bpf/progs/uprobe_syscall.c b/tools/testing/selftests/bpf/progs/uprobe_syscall.c
new file mode 100644
index 000000000000..0cc7e8761410
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/uprobe_syscall.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <string.h>
+
+struct pt_regs regs;
+
+char _license[] SEC("license") = "GPL";
+
+SEC("uretprobe//proc/self/exe:uprobe_syscall_arch_test")
+int uretprobe(struct pt_regs *ctx)
+{
+	memcpy(&regs, ctx, sizeof(regs));
+	return 0;
+}
-- 
2.44.0


  parent reply	other threads:[~2024-03-18  9:32 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-18  9:31 [PATCH RFC bpf-next 0/3] uprobe: uretprobe speed up Jiri Olsa
2024-03-18  9:31 ` [PATCH RFC bpf-next 1/3] uprobe: Add uretprobe syscall to speed up return probe Jiri Olsa
2024-03-18 14:22   ` Oleg Nesterov
2024-03-19  1:11   ` Andrii Nakryiko
2024-03-19  6:32     ` Oleg Nesterov
2024-03-19 16:20       ` Andrii Nakryiko
2024-03-19 10:54     ` Jiri Olsa
2024-03-18  9:31 ` Jiri Olsa [this message]
2024-03-19  1:16   ` [PATCH RFC bpf-next 2/3] selftests/bpf: Add uretprobe syscall test Andrii Nakryiko
2024-03-19 11:09     ` Jiri Olsa
2024-03-18  9:31 ` [PATCH RFC bpf-next 3/3] selftests/bpf: Mark uprobe trigger functions with nocf_check attribute Jiri Olsa
2024-03-19  1:22   ` Andrii Nakryiko
2024-03-19 11:11     ` Jiri Olsa
2024-03-22 13:40       ` Jiri Olsa
2024-03-19 10:25 ` [PATCH RFC bpf-next 4/3] uprobe: ensure sys_uretprobe uses sysret Oleg Nesterov
2024-03-19 11:08   ` Jiri Olsa
2024-03-19 16:25     ` Andrii Nakryiko
2024-03-19 16:38       ` Oleg Nesterov
2024-03-19 19:35       ` Jiri Olsa
2024-03-19 19:31     ` Jiri Olsa
2024-03-19 20:13       ` Andrii Nakryiko
2024-03-20 11:04       ` Jiri Olsa
2024-03-20 14:37         ` Oleg Nesterov
2024-03-20 15:28           ` Oleg Nesterov
2024-03-20 17:44             ` Andrii Nakryiko
2024-03-20 19:08               ` Jiri Olsa
2024-03-21 10:10                 ` Oleg Nesterov
2024-03-21  9:59             ` Jiri Olsa
2024-03-21 10:17               ` Oleg Nesterov
2024-03-21 10:52                 ` Jiri Olsa
2024-03-21 12:14                   ` Oleg Nesterov
2024-03-21 20:29                     ` Jiri Olsa
2024-03-22  8:48                       ` Oleg Nesterov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240318093139.293497-3-jolsa@kernel.org \
    --to=jolsa@kernel.org \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bp@alien8.de \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=john.fastabend@gmail.com \
    --cc=oleg@redhat.com \
    --cc=peterz@infradead.org \
    --cc=songliubraving@fb.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox