diff mbox series

[bpf-next,2/2] selftests/bpf: uprobe tests should verify param/return values

Message ID 1649195156-9465-3-git-send-email-alan.maguire@oracle.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series libbpf: uprobe name-based attach followups | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-VM_Test-1 success Logs for Kernel LATEST on ubuntu-latest + selftests
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Kernel LATEST on z15 + selftests
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 2 maintainers not CCed: linux-kselftest@vger.kernel.org shuah@kernel.org
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning CHECK: No space is necessary after a cast
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Alan Maguire April 5, 2022, 9:45 p.m. UTC
uprobe/uretprobe tests don't do any validation of arguments/return values,
and without this we can't be sure we are attached to the right function,
or that we are indeed attached to a uprobe or uretprobe.  To fix this
validate argument and return value for auto-attached functions.

Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
 .../selftests/bpf/prog_tests/uprobe_autoattach.c   | 16 ++++++++++----
 .../selftests/bpf/progs/test_uprobe_autoattach.c   | 25 +++++++++++++++-------
 2 files changed, 29 insertions(+), 12 deletions(-)

Comments

Andrii Nakryiko April 6, 2022, 12:14 a.m. UTC | #1
On Tue, Apr 5, 2022 at 2:46 PM Alan Maguire <alan.maguire@oracle.com> wrote:
>
> uprobe/uretprobe tests don't do any validation of arguments/return values,
> and without this we can't be sure we are attached to the right function,
> or that we are indeed attached to a uprobe or uretprobe.  To fix this
> validate argument and return value for auto-attached functions.
>
> Suggested-by: Andrii Nakryiko <andrii@kernel.org>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
>  .../selftests/bpf/prog_tests/uprobe_autoattach.c   | 16 ++++++++++----
>  .../selftests/bpf/progs/test_uprobe_autoattach.c   | 25 +++++++++++++++-------
>  2 files changed, 29 insertions(+), 12 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c b/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c
> index 03b15d6..ff85f1f 100644
> --- a/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c
> +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c
> @@ -5,14 +5,16 @@
>  #include "test_uprobe_autoattach.skel.h"
>
>  /* uprobe attach point */
> -static void autoattach_trigger_func(void)
> +static noinline int autoattach_trigger_func(int arg)
>  {
> -       asm volatile ("");

don't remove asm volatile, with static functions compiler can still do
function transformations and stuff. From GCC documentation for
noinline attribute ([0]):

  noinline

      This function attribute prevents a function from being
considered for inlining. If the function does not have side effects,
there are optimizations other than inlining that cause function calls
to be optimized away, although the function call is live. To keep such
calls from being optimized away, put

      asm ("");

  [0] https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

So I suppose noinline + asm volatile is the most safe combination :)
for static functions

> +       return arg + 1;
>  }
>
>  void test_uprobe_autoattach(void)
>  {
>         struct test_uprobe_autoattach *skel;
> +       int trigger_val = 100;
> +       size_t malloc_sz = 1;
>         char *mem;
>
>         skel = test_uprobe_autoattach__open_and_load();

[...]

>
> -SEC("uretprobe/libc.so.6:free")
> +SEC("uretprobe/libc.so.6:getpid")
>  int handle_uretprobe_byname2(struct pt_regs *ctx)
>  {
> -       uretprobe_byname2_res = 4;
> +       if (PT_REGS_RC_CORE(ctx) == uretprobe_byname2_rc)
> +               uretprobe_byname2_res = 4;

Instead of checking equality on BPF side, it's more convenient to
record the actual captured value into global variable and let
user-space part check and log it properly. So if something goes wrong,
we don't just have matched/not matched flag, but we see an actual
value captured.


With that, let's better switch uretprobe from free to malloc (we
additionally check that uprobe and uretprobe can coexist properly on
the same function) and capture returned pointer from malloc(). We can
then compare that pointer to the mem variable. How cool is that? :)

>         return 0;
>  }
>
> --
> 1.8.3.1
>
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c b/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c
index 03b15d6..ff85f1f 100644
--- a/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c
+++ b/tools/testing/selftests/bpf/prog_tests/uprobe_autoattach.c
@@ -5,14 +5,16 @@ 
 #include "test_uprobe_autoattach.skel.h"
 
 /* uprobe attach point */
-static void autoattach_trigger_func(void)
+static noinline int autoattach_trigger_func(int arg)
 {
-	asm volatile ("");
+	return arg + 1;
 }
 
 void test_uprobe_autoattach(void)
 {
 	struct test_uprobe_autoattach *skel;
+	int trigger_val = 100;
+	size_t malloc_sz = 1;
 	char *mem;
 
 	skel = test_uprobe_autoattach__open_and_load();
@@ -22,12 +24,18 @@  void test_uprobe_autoattach(void)
 	if (!ASSERT_OK(test_uprobe_autoattach__attach(skel), "skel_attach"))
 		goto cleanup;
 
+	skel->bss->uprobe_byname_parm1 = trigger_val;
+	skel->bss->uretprobe_byname_rc  = trigger_val + 1;
+	skel->bss->uprobe_byname2_parm1 = malloc_sz;
+	skel->bss->uretprobe_byname2_rc = getpid();
+
 	/* trigger & validate uprobe & uretprobe */
-	autoattach_trigger_func();
+	(void) autoattach_trigger_func(trigger_val);
 
 	/* trigger & validate shared library u[ret]probes attached by name */
-	mem = malloc(1);
+	mem = malloc(malloc_sz);
 	free(mem);
+	(void) getpid();
 
 	ASSERT_EQ(skel->bss->uprobe_byname_res, 1, "check_uprobe_byname_res");
 	ASSERT_EQ(skel->bss->uretprobe_byname_res, 2, "check_uretprobe_byname_res");
diff --git a/tools/testing/selftests/bpf/progs/test_uprobe_autoattach.c b/tools/testing/selftests/bpf/progs/test_uprobe_autoattach.c
index b442fb5..db104bd 100644
--- a/tools/testing/selftests/bpf/progs/test_uprobe_autoattach.c
+++ b/tools/testing/selftests/bpf/progs/test_uprobe_autoattach.c
@@ -1,15 +1,20 @@ 
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright (c) 2022, Oracle and/or its affiliates. */
 
-#include <linux/ptrace.h>
-#include <linux/bpf.h>
+#include "vmlinux.h"
+
+#include <bpf/bpf_core_read.h>
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
 
+int uprobe_byname_parm1 = 0;
 int uprobe_byname_res = 0;
+int uretprobe_byname_rc = 0;
 int uretprobe_byname_res = 0;
+size_t uprobe_byname2_parm1 = 0;
 int uprobe_byname2_res = 0;
-int uretprobe_byname2_res = 0;
+int uretprobe_byname2_rc = 0;
+pid_t uretprobe_byname2_res = 0;
 
 /* This program cannot auto-attach, but that should not stop other
  * programs from attaching.
@@ -23,14 +28,16 @@  int handle_uprobe_noautoattach(struct pt_regs *ctx)
 SEC("uprobe//proc/self/exe:autoattach_trigger_func")
 int handle_uprobe_byname(struct pt_regs *ctx)
 {
-	uprobe_byname_res = 1;
+	if (PT_REGS_PARM1_CORE(ctx) == uprobe_byname_parm1)
+		uprobe_byname_res = 1;
 	return 0;
 }
 
 SEC("uretprobe//proc/self/exe:autoattach_trigger_func")
 int handle_uretprobe_byname(struct pt_regs *ctx)
 {
-	uretprobe_byname_res = 2;
+	if (PT_REGS_RC_CORE(ctx) == uretprobe_byname_rc)
+		uretprobe_byname_res = 2;
 	return 0;
 }
 
@@ -38,14 +45,16 @@  int handle_uretprobe_byname(struct pt_regs *ctx)
 SEC("uprobe/libc.so.6:malloc")
 int handle_uprobe_byname2(struct pt_regs *ctx)
 {
-	uprobe_byname2_res = 3;
+	if (PT_REGS_PARM1_CORE(ctx) == uprobe_byname2_parm1)
+		uprobe_byname2_res = 3;
 	return 0;
 }
 
-SEC("uretprobe/libc.so.6:free")
+SEC("uretprobe/libc.so.6:getpid")
 int handle_uretprobe_byname2(struct pt_regs *ctx)
 {
-	uretprobe_byname2_res = 4;
+	if (PT_REGS_RC_CORE(ctx) == uretprobe_byname2_rc)
+		uretprobe_byname2_res = 4;
 	return 0;
 }