All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor
@ 2026-06-09 10:42 Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 10:42 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	Oleg Nesterov, Masami Hiramatsu

hi,
we'd like to be able to open uprobe_multi link on top of binary identified
by file descriptor. This allows us to avoid the race where the binary is
replaced between path resolution and attachment, ensuring we monitor the
intended binary.

thanks,
jirka


---
Jiri Olsa (6):
      bpf: Use user_path_at for path resolution in uprobe_multi
      bpf: Add support to specify uprobe_multi target via file descriptor
      libbpf: Add path_fd to struct bpf_link_create_opts
      selftests/bpf: Add uprobe_multi path_fd test
      selftests/bpf: Add uprobe_multi path_fd fail tests
      selftests/bpf: Fix typo in verify_umulti_link_info

 include/uapi/linux/bpf.h                                   |  7 +++++-
 kernel/bpf/syscall.c                                       |  4 +--
 kernel/trace/bpf_trace.c                                   | 43 +++++++++++++++++++++-----------
 tools/include/uapi/linux/bpf.h                             |  7 +++++-
 tools/lib/bpf/bpf.c                                        |  1 +
 tools/lib/bpf/bpf.h                                        |  3 ++-
 tools/testing/selftests/bpf/prog_tests/fill_link_info.c    |  2 +-
 tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 8 files changed, 140 insertions(+), 21 deletions(-)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi
  2026-06-09 10:42 [PATCH bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
@ 2026-06-09 10:42 ` Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 10:42 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	Oleg Nesterov, Masami Hiramatsu

Resolve the uprobe_multi user path with user_path_at() instead of copying
the string with strndup_user() and passing it to kern_path(). This removes
the temporary allocation and keeps the lookup logic in one helper.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 kernel/trace/bpf_trace.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 90432f0fc2a8..970ce7bbf99e 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -3226,7 +3226,6 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
 	void __user *upath;
 	u32 flags, cnt, i;
 	struct path path;
-	char *name;
 	pid_t pid;
 	int err;
 
@@ -3261,14 +3260,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
 	uref_ctr_offsets = u64_to_user_ptr(attr->link_create.uprobe_multi.ref_ctr_offsets);
 	ucookies = u64_to_user_ptr(attr->link_create.uprobe_multi.cookies);
 
-	name = strndup_user(upath, PATH_MAX);
-	if (IS_ERR(name)) {
-		err = PTR_ERR(name);
-		return err;
-	}
-
-	err = kern_path(name, LOOKUP_FOLLOW, &path);
-	kfree(name);
+	err = user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, &path);
 	if (err)
 		return err;
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
  2026-06-09 10:42 [PATCH bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
@ 2026-06-09 10:42 ` Jiri Olsa
  2026-06-09 10:57   ` sashiko-bot
                     ` (2 more replies)
  2026-06-09 10:42 ` [PATCH bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
                   ` (3 subsequent siblings)
  5 siblings, 3 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 10:42 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	Oleg Nesterov, Masami Hiramatsu

Allow uprobe_multi link to identify the target binary by an already
opened file descriptor.

Adding new BPF_F_UPROBE_MULTI_PATH_FD flag and the path_fd field for
the attr.link_create.uprobe_multi struct.

When the flag is set, we resolve the target from path_fd, without the
flag, we keep the existing string path behavior.

I don't see a use case for supporting O_PATH file descriptors, because
we need need to read the binary first to get probes offsets, so I'm
using the CLASS(fd, f), which fails for O_PATH fds.

Assisted-by: Codex:GPT-5.4
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 include/uapi/linux/bpf.h       |  7 ++++++-
 kernel/bpf/syscall.c           |  4 ++--
 kernel/trace/bpf_trace.c       | 37 +++++++++++++++++++++++++++-------
 tools/include/uapi/linux/bpf.h |  7 ++++++-
 4 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 11dd610fa5fa..89b36de5fdbb 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1327,7 +1327,11 @@ enum {
  * BPF_TRACE_UPROBE_MULTI attach type to create return probe.
  */
 enum {
-	BPF_F_UPROBE_MULTI_RETURN = (1U << 0)
+	/* Get return uprobe. */
+	BPF_F_UPROBE_MULTI_RETURN     = (1U << 0),
+
+	/* Get path from provided path_fd. */
+	BPF_F_UPROBE_MULTI_PATH_FD    = (1U << 1),
 };
 
 /* link_create.netfilter.flags used in LINK_CREATE command for
@@ -1864,6 +1868,7 @@ union bpf_attr {
 				__u32		cnt;
 				__u32		flags;
 				__u32		pid;
+				__u32		path_fd;
 			} uprobe_multi;
 			struct {
 				union {
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index d4188a992bd8..cef9bd6316a5 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3475,7 +3475,7 @@ static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
 			seq_printf(m, "link_type:\t%s\n", link->flags == BPF_F_KPROBE_MULTI_RETURN ?
 				   "kretprobe_multi" : "kprobe_multi");
 		else if (link->type == BPF_LINK_TYPE_UPROBE_MULTI)
-			seq_printf(m, "link_type:\t%s\n", link->flags == BPF_F_UPROBE_MULTI_RETURN ?
+			seq_printf(m, "link_type:\t%s\n", link->flags & BPF_F_UPROBE_MULTI_RETURN ?
 				   "uretprobe_multi" : "uprobe_multi");
 		else
 			seq_printf(m, "link_type:\t%s\n", bpf_link_type_strs[type]);
@@ -5835,7 +5835,7 @@ static int bpf_map_do_batch(const union bpf_attr *attr,
 	return err;
 }
 
-#define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.pid
+#define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.path_fd
 static int link_create(union bpf_attr *attr, bpfptr_t uattr)
 {
 	struct bpf_prog *prog;
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 970ce7bbf99e..4965006d58ee 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -23,6 +23,7 @@
 #include <linux/sort.h>
 #include <linux/key.h>
 #include <linux/namei.h>
+#include <linux/file.h>
 
 #include <net/bpf_sk_storage.h>
 
@@ -3240,29 +3241,51 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
 		return -EINVAL;
 
 	flags = attr->link_create.uprobe_multi.flags;
-	if (flags & ~BPF_F_UPROBE_MULTI_RETURN)
+	if (flags & ~(BPF_F_UPROBE_MULTI_RETURN|BPF_F_UPROBE_MULTI_PATH_FD))
 		return -EINVAL;
 
 	/*
-	 * path, offsets and cnt are mandatory,
+	 * offsets and cnt are mandatory,
 	 * ref_ctr_offsets and cookies are optional
 	 */
-	upath = u64_to_user_ptr(attr->link_create.uprobe_multi.path);
 	uoffsets = u64_to_user_ptr(attr->link_create.uprobe_multi.offsets);
 	cnt = attr->link_create.uprobe_multi.cnt;
 	pid = attr->link_create.uprobe_multi.pid;
 
-	if (!upath || !uoffsets || !cnt || pid < 0)
+	if (!uoffsets || !cnt || pid < 0)
 		return -EINVAL;
 	if (cnt > MAX_UPROBE_MULTI_CNT)
 		return -E2BIG;
 
 	uref_ctr_offsets = u64_to_user_ptr(attr->link_create.uprobe_multi.ref_ctr_offsets);
 	ucookies = u64_to_user_ptr(attr->link_create.uprobe_multi.cookies);
+	upath = u64_to_user_ptr(attr->link_create.uprobe_multi.path);
 
-	err = user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, &path);
-	if (err)
-		return err;
+	if (flags & BPF_F_UPROBE_MULTI_PATH_FD) {
+		/*
+		 * When BPF_F_UPROBE_MULTI_PATH_FD is set, the executable is identified
+		 * by path_fd, and upath must be NULL.
+		 */
+		if (upath)
+			return -EINVAL;
+
+		CLASS(fd, f)(attr->link_create.uprobe_multi.path_fd);
+		if (fd_empty(f))
+			return -EBADF;
+		path = fd_file(f)->f_path;
+		path_get(&path);
+	} else {
+		/*
+		 * When BPF_F_UPROBE_MULTI_PATH_FD is not set, the path is resolved
+		 * relative to the cwd (AT_FDCWD) or absolute  using the upath string.
+		 */
+		if (!upath)
+			return -EINVAL;
+
+		err = user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, &path);
+		if (err)
+			return err;
+	}
 
 	if (!d_is_reg(path.dentry)) {
 		err = -EBADF;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 11dd610fa5fa..89b36de5fdbb 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1327,7 +1327,11 @@ enum {
  * BPF_TRACE_UPROBE_MULTI attach type to create return probe.
  */
 enum {
-	BPF_F_UPROBE_MULTI_RETURN = (1U << 0)
+	/* Get return uprobe. */
+	BPF_F_UPROBE_MULTI_RETURN     = (1U << 0),
+
+	/* Get path from provided path_fd. */
+	BPF_F_UPROBE_MULTI_PATH_FD    = (1U << 1),
 };
 
 /* link_create.netfilter.flags used in LINK_CREATE command for
@@ -1864,6 +1868,7 @@ union bpf_attr {
 				__u32		cnt;
 				__u32		flags;
 				__u32		pid;
+				__u32		path_fd;
 			} uprobe_multi;
 			struct {
 				union {
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts
  2026-06-09 10:42 [PATCH bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
@ 2026-06-09 10:42 ` Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 10:42 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	Oleg Nesterov, Masami Hiramatsu

Adding the path_fd field to struct bpf_link_create_opts and passing it
through kernel attr interface.

Assisted-by: Codex:GPT-5.4
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/lib/bpf/bpf.c | 1 +
 tools/lib/bpf/bpf.h | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index f37e3416f61a..96819c082c77 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -842,6 +842,7 @@ int bpf_link_create(int prog_fd, int target_fd,
 		attr.link_create.uprobe_multi.ref_ctr_offsets = ptr_to_u64(OPTS_GET(opts, uprobe_multi.ref_ctr_offsets, 0));
 		attr.link_create.uprobe_multi.cookies = ptr_to_u64(OPTS_GET(opts, uprobe_multi.cookies, 0));
 		attr.link_create.uprobe_multi.pid = OPTS_GET(opts, uprobe_multi.pid, 0);
+		attr.link_create.uprobe_multi.path_fd = OPTS_GET(opts, uprobe_multi.path_fd, 0);
 		if (!OPTS_ZEROED(opts, uprobe_multi))
 			return libbpf_err(-EINVAL);
 		break;
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 012354131cf6..7534a593edae 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -444,6 +444,7 @@ struct bpf_link_create_opts {
 			const unsigned long *ref_ctr_offsets;
 			const __u64 *cookies;
 			__u32 pid;
+			__u32 path_fd;
 		} uprobe_multi;
 		struct {
 			__u64 cookie;
@@ -477,7 +478,7 @@ struct bpf_link_create_opts {
 	};
 	size_t :0;
 };
-#define bpf_link_create_opts__last_field uprobe_multi.pid
+#define bpf_link_create_opts__last_field uprobe_multi.path_fd
 
 LIBBPF_API int bpf_link_create(int prog_fd, int target_fd,
 			       enum bpf_attach_type attach_type,
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test
  2026-06-09 10:42 [PATCH bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
                   ` (2 preceding siblings ...)
  2026-06-09 10:42 ` [PATCH bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
@ 2026-06-09 10:42 ` Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 6/6] selftests/bpf: Fix typo in verify_umulti_link_info Jiri Olsa
  5 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 10:42 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	Oleg Nesterov, Masami Hiramatsu

Add a uprobe_multi link API selftest that opens /proc/self/exe and passes
the resulting descriptor through opts.uprobe_multi.path_fd with
BPF_F_UPROBE_MULTI_PATH_FD set.

Assisted-by: Codex:GPT-5.4
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 .../bpf/prog_tests/uprobe_multi_test.c        | 62 +++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
index 56cbea280fbd..8c9eba1d4084 100644
--- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
@@ -2,6 +2,7 @@
 
 #include <unistd.h>
 #include <pthread.h>
+#include <fcntl.h>
 #include <test_progs.h>
 #include "uprobe_multi.skel.h"
 #include "uprobe_multi_bench.skel.h"
@@ -757,6 +758,65 @@ static void test_link_api(void)
 	__test_link_api(&child);
 }
 
+static void test_link_api_path_fd(void)
+{
+	const char *resolve_path = "/proc/self/exe";
+	LIBBPF_OPTS(bpf_link_create_opts, opts);
+	int prog_fd, link_fd = -1, path_fd = -1;
+	struct uprobe_multi *skel = NULL;
+	unsigned long *offsets = NULL;
+	const char *syms[3] = {
+		"uprobe_multi_func_1",
+		"uprobe_multi_func_2",
+		"uprobe_multi_func_3",
+	};
+	int err;
+
+	err = elf_resolve_syms_offsets(resolve_path, ARRAY_SIZE(syms), syms,
+				       &offsets, STT_FUNC);
+	if (!ASSERT_OK(err, "elf_resolve_syms_offsets"))
+		return;
+
+	path_fd = open(resolve_path, O_RDONLY);
+	if (!ASSERT_GE(path_fd, 0, "path_fd"))
+		goto cleanup;
+
+	opts.uprobe_multi.path_fd = path_fd;
+	opts.uprobe_multi.offsets = offsets;
+	opts.uprobe_multi.cnt = ARRAY_SIZE(syms);
+	opts.uprobe_multi.flags = BPF_F_UPROBE_MULTI_PATH_FD;
+
+	skel = uprobe_multi__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "uprobe_multi__open_and_load"))
+		goto cleanup;
+
+	prog_fd = bpf_program__fd(skel->progs.uprobe);
+	link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
+	if (!ASSERT_GE(link_fd, 0, "bpf_link_create"))
+		goto cleanup;
+
+	skel->bss->uprobe_multi_func_1_addr = (__u64)uprobe_multi_func_1;
+	skel->bss->uprobe_multi_func_2_addr = (__u64)uprobe_multi_func_2;
+	skel->bss->uprobe_multi_func_3_addr = (__u64)uprobe_multi_func_3;
+	skel->bss->pid = getpid();
+
+	uprobe_multi_func_1();
+	uprobe_multi_func_2();
+	uprobe_multi_func_3();
+
+	ASSERT_EQ(skel->bss->uprobe_multi_func_1_result, 1, "uprobe_multi_func_1_result");
+	ASSERT_EQ(skel->bss->uprobe_multi_func_2_result, 1, "uprobe_multi_func_2_result");
+	ASSERT_EQ(skel->bss->uprobe_multi_func_3_result, 1, "uprobe_multi_func_3_result");
+
+cleanup:
+	if (link_fd >= 0)
+		close(link_fd);
+	if (path_fd >= 0)
+		close(path_fd);
+	uprobe_multi__destroy(skel);
+	free(offsets);
+}
+
 static struct bpf_program *
 get_program(struct uprobe_multi_consumers *skel, int prog)
 {
@@ -1354,6 +1414,8 @@ void test_uprobe_multi_test(void)
 		test_attach_api_syms();
 	if (test__start_subtest("link_api"))
 		test_link_api();
+	if (test__start_subtest("link_api_path_fd"))
+		test_link_api_path_fd();
 	if (test__start_subtest("bench_uprobe"))
 		test_bench_attach_uprobe();
 	if (test__start_subtest("bench_usdt"))
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests
  2026-06-09 10:42 [PATCH bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
                   ` (3 preceding siblings ...)
  2026-06-09 10:42 ` [PATCH bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
@ 2026-06-09 10:42 ` Jiri Olsa
  2026-06-09 10:42 ` [PATCH bpf-next 6/6] selftests/bpf: Fix typo in verify_umulti_link_info Jiri Olsa
  5 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 10:42 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	Oleg Nesterov, Masami Hiramatsu

Adding tests to attach_api_fails suite to make sure we fail
wrong setup for path_fd usage.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 .../bpf/prog_tests/uprobe_multi_test.c        | 32 ++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
index 8c9eba1d4084..71eea809dce3 100644
--- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
+++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
@@ -537,7 +537,37 @@ static void test_attach_api_fails(void)
 	link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
 	if (!ASSERT_ERR(link_fd, "link_fd"))
 		goto cleanup;
-	ASSERT_EQ(link_fd, -EINVAL, "pid_is_wrong");
+	if (!ASSERT_EQ(link_fd, -EINVAL, "pid_is_wrong"))
+		goto cleanup;
+
+	/* wrong path_fd */
+	LIBBPF_OPTS_RESET(opts,
+		.uprobe_multi.path = NULL,
+		.uprobe_multi.path_fd = -1,
+		.uprobe_multi.flags = BPF_F_UPROBE_MULTI_PATH_FD,
+		.uprobe_multi.offsets = (unsigned long *) &offset,
+		.uprobe_multi.cnt = 1,
+	);
+
+	link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
+	if (!ASSERT_ERR(link_fd, "link_fd"))
+		goto cleanup;
+	if (!ASSERT_EQ(link_fd, -EBADF, "path_fd_is_wrong"))
+		goto cleanup;
+
+	/* path and path_fd both set with BPF_F_UPROBE_MULTI_PATH_FD flag */
+	LIBBPF_OPTS_RESET(opts,
+		.uprobe_multi.path = path,
+		.uprobe_multi.path_fd = 1,
+		.uprobe_multi.flags = BPF_F_UPROBE_MULTI_PATH_FD,
+		.uprobe_multi.offsets = (unsigned long *) &offset,
+		.uprobe_multi.cnt = 1,
+	);
+
+	link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &opts);
+	if (!ASSERT_ERR(link_fd, "link_fd"))
+		goto cleanup;
+	ASSERT_EQ(link_fd, -EINVAL, "path_and_path_fd_together");
 
 cleanup:
 	if (link_fd >= 0)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 6/6] selftests/bpf: Fix typo in verify_umulti_link_info
  2026-06-09 10:42 [PATCH bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
                   ` (4 preceding siblings ...)
  2026-06-09 10:42 ` [PATCH bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
@ 2026-06-09 10:42 ` Jiri Olsa
  5 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 10:42 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	Oleg Nesterov, Masami Hiramatsu

We verify info.uprobe_multi.flags against wrong kprobe-multi flag
(BPF_F_KPROBE_MULTI_RETURN). It's the same value as the correct
flag (BPF_F_UPROBE_MULTI_RETURN), so there's not functional change.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/testing/selftests/bpf/prog_tests/fill_link_info.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c
index e40114620751..f589eefbf9fb 100644
--- a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c
+++ b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c
@@ -469,7 +469,7 @@ verify_umulti_link_info(int fd, bool retprobe, __u64 *offsets,
 
 		ASSERT_EQ(info.uprobe_multi.pid, getpid(), "info.uprobe_multi.pid");
 		ASSERT_EQ(info.uprobe_multi.count, 3, "info.uprobe_multi.count");
-		ASSERT_EQ(info.uprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN,
+		ASSERT_EQ(info.uprobe_multi.flags & BPF_F_UPROBE_MULTI_RETURN,
 			  retprobe, "info.uprobe_multi.flags.retprobe");
 		ASSERT_EQ(info.uprobe_multi.path_size, strlen(path) + 1, "info.uprobe_multi.path_size");
 		ASSERT_STREQ(path_buf, path, "info.uprobe_multi.path");
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
  2026-06-09 10:42 ` [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
@ 2026-06-09 10:57   ` sashiko-bot
  2026-06-09 13:23     ` Jiri Olsa
  2026-06-09 11:17   ` bot+bpf-ci
  2026-06-09 18:22   ` Alexei Starovoitov
  2 siblings, 1 reply; 12+ messages in thread
From: sashiko-bot @ 2026-06-09 10:57 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Missing strict zero-validation for the unused `path_fd` field when the `BPF_F_UPROBE_MULTI_PATH_FD` flag is not set.
- [Low] Mixing scope-based cleanup (`CLASS()`) with `goto`-based error handling in `bpf_uprobe_multi_link_attach`.
--

commit f7958ff1ce57c1ab456d3f134881a0081a58b8ed
Author: Jiri Olsa <jolsa@kernel.org>

bpf: Add support to specify uprobe_multi target via file descriptor

This commit adds the BPF_F_UPROBE_MULTI_PATH_FD flag to allow uprobe_multi
links to specify the target binary using an already opened file descriptor
instead of a path string.

> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index 970ce7bbf99e1..4965006d58ee6 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
[ ... ]
> @@ -3240,29 +3241,51 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
[ ... ]
>  	uref_ctr_offsets = u64_to_user_ptr(attr->link_create.uprobe_multi.ref_ctr_offsets);
>  	ucookies = u64_to_user_ptr(attr->link_create.uprobe_multi.cookies);
> +	upath = u64_to_user_ptr(attr->link_create.uprobe_multi.path);
>  
> -	err = user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, &path);
> -	if (err)
> -		return err;
> +	if (flags & BPF_F_UPROBE_MULTI_PATH_FD) {
> +		/*
> +		 * When BPF_F_UPROBE_MULTI_PATH_FD is set, the executable is identified
> +		 * by path_fd, and upath must be NULL.
> +		 */
> +		if (upath)
> +			return -EINVAL;
> +
> +		CLASS(fd, f)(attr->link_create.uprobe_multi.path_fd);

[Severity: Low]
Does this code violate the cleanup subsystem guidelines by mixing scope-based
cleanup with goto-based error handling?

The bpf_uprobe_multi_link_attach() function relies heavily on goto labels
for error paths (e.g., error_path_put, error_free, error_unregister). The
kernel guidelines state that goto-based cleanup and scope-based cleanup
helpers (like CLASS) should never be mixed in the same function.

Should this function be fully converted to scope-based cleanup, or should it
use explicit fdget()/fdput() without CLASS() instead?

> +		if (fd_empty(f))
> +			return -EBADF;
> +		path = fd_file(f)->f_path;
> +		path_get(&path);
> +	} else {
> +		/*
> +		 * When BPF_F_UPROBE_MULTI_PATH_FD is not set, the path is resolved
> +		 * relative to the cwd (AT_FDCWD) or absolute  using the upath string.
> +		 */
> +		if (!upath)
> +			return -EINVAL;

[Severity: Medium]
Should there be strict zero-validation for the unused path_fd field here?

When the BPF_F_UPROBE_MULTI_PATH_FD flag is not set, this branch is taken
and attr->link_create.uprobe_multi.path_fd is ignored without being
validated as zero.

If userspace passes uninitialized garbage in this field, it won't be
rejected. Could this break forward compatibility if path_fd needs to be
assigned a new meaning in the future?

> +
> +		err = user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, &path);
> +		if (err)
> +			return err;
> +	}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260609104244.588321-1-jolsa@kernel.org?part=2

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
  2026-06-09 10:42 ` [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
  2026-06-09 10:57   ` sashiko-bot
@ 2026-06-09 11:17   ` bot+bpf-ci
  2026-06-09 13:24     ` Jiri Olsa
  2026-06-09 18:22   ` Alexei Starovoitov
  2 siblings, 1 reply; 12+ messages in thread
From: bot+bpf-ci @ 2026-06-09 11:17 UTC (permalink / raw)
  To: jolsa, ast, daniel, andrii
  Cc: bpf, martin.lau, eddyz87, songliubraving, yhs, oleg, mhiramat,
	ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
	ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 1646 bytes --]

> Allow uprobe_multi link to identify the target binary by an already
> opened file descriptor.
>
> Adding new BPF_F_UPROBE_MULTI_PATH_FD flag and the path_fd field for
> the attr.link_create.uprobe_multi struct.
>
> When the flag is set, we resolve the target from path_fd, without the
> flag, we keep the existing string path behavior.
>
> I don't see a use case for supporting O_PATH file descriptors, because
> we need need to read the binary first to get probes offsets, so I'm
> using the CLASS(fd, f), which fails for O_PATH fds.
>
> Assisted-by: Codex:GPT-5.4
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

This change also fixes a latent bug in bpf_link_show_fdinfo(), changing
the exact-equality test to a bitwise test:

	else if (link->type == BPF_LINK_TYPE_UPROBE_MULTI)
		seq_printf(m, "link_type:\t%s\n", link->flags & BPF_F_UPROBE_MULTI_RETURN ?
			   "uretprobe_multi" : "uprobe_multi");

The original "link->flags == BPF_F_UPROBE_MULTI_RETURN" was harmless
while BPF_F_UPROBE_MULTI_RETURN was the only defined uprobe_multi flag.
This commit adds a second flag (BPF_F_UPROBE_MULTI_PATH_FD), so the
exact "==" comparison would misreport a uretprobe_multi link as
"uprobe_multi" whenever both flags are set.

Should this carry a Fixes: tag pointing at the commit that introduced
the fragile comparison?

  Fixes: 803f0700a3bb ("bpf: Show precise link_type for {uprobe,kprobe}_multi fdinfo")


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27201419867

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
  2026-06-09 10:57   ` sashiko-bot
@ 2026-06-09 13:23     ` Jiri Olsa
  0 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 13:23 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: bpf

On Tue, Jun 09, 2026 at 10:57:22AM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Medium] Missing strict zero-validation for the unused `path_fd` field when the `BPF_F_UPROBE_MULTI_PATH_FD` flag is not set.
> - [Low] Mixing scope-based cleanup (`CLASS()`) with `goto`-based error handling in `bpf_uprobe_multi_link_attach`.
> --
> 
> commit f7958ff1ce57c1ab456d3f134881a0081a58b8ed
> Author: Jiri Olsa <jolsa@kernel.org>
> 
> bpf: Add support to specify uprobe_multi target via file descriptor
> 
> This commit adds the BPF_F_UPROBE_MULTI_PATH_FD flag to allow uprobe_multi
> links to specify the target binary using an already opened file descriptor
> instead of a path string.
> 
> > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> > index 970ce7bbf99e1..4965006d58ee6 100644
> > --- a/kernel/trace/bpf_trace.c
> > +++ b/kernel/trace/bpf_trace.c
> [ ... ]
> > @@ -3240,29 +3241,51 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
> [ ... ]
> >  	uref_ctr_offsets = u64_to_user_ptr(attr->link_create.uprobe_multi.ref_ctr_offsets);
> >  	ucookies = u64_to_user_ptr(attr->link_create.uprobe_multi.cookies);
> > +	upath = u64_to_user_ptr(attr->link_create.uprobe_multi.path);
> >  
> > -	err = user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, &path);
> > -	if (err)
> > -		return err;
> > +	if (flags & BPF_F_UPROBE_MULTI_PATH_FD) {
> > +		/*
> > +		 * When BPF_F_UPROBE_MULTI_PATH_FD is set, the executable is identified
> > +		 * by path_fd, and upath must be NULL.
> > +		 */
> > +		if (upath)
> > +			return -EINVAL;
> > +
> > +		CLASS(fd, f)(attr->link_create.uprobe_multi.path_fd);
> 
> [Severity: Low]
> Does this code violate the cleanup subsystem guidelines by mixing scope-based
> cleanup with goto-based error handling?
> 
> The bpf_uprobe_multi_link_attach() function relies heavily on goto labels
> for error paths (e.g., error_path_put, error_free, error_unregister). The
> kernel guidelines state that goto-based cleanup and scope-based cleanup
> helpers (like CLASS) should never be mixed in the same function.
> 
> Should this function be fully converted to scope-based cleanup, or should it
> use explicit fdget()/fdput() without CLASS() instead?

ah true, I'll unwind the fd retrieval or perhaps move the path retrival
into separate function, will check

> > +		if (fd_empty(f))
> > +			return -EBADF;
> > +		path = fd_file(f)->f_path;
> > +		path_get(&path);
> > +	} else {
> > +		/*
> > +		 * When BPF_F_UPROBE_MULTI_PATH_FD is not set, the path is resolved
> > +		 * relative to the cwd (AT_FDCWD) or absolute  using the upath string.
> > +		 */
> > +		if (!upath)
> > +			return -EINVAL;
> 
> [Severity: Medium]
> Should there be strict zero-validation for the unused path_fd field here?
> 
> When the BPF_F_UPROBE_MULTI_PATH_FD flag is not set, this branch is taken
> and attr->link_create.uprobe_multi.path_fd is ignored without being
> validated as zero.
> 
> If userspace passes uninitialized garbage in this field, it won't be
> rejected. Could this break forward compatibility if path_fd needs to be
> assigned a new meaning in the future?

right, I'll add the path_fd check in here

jirka

> 
> > +
> > +		err = user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, &path);
> > +		if (err)
> > +			return err;
> > +	}
> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/20260609104244.588321-1-jolsa@kernel.org?part=2

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
  2026-06-09 11:17   ` bot+bpf-ci
@ 2026-06-09 13:24     ` Jiri Olsa
  0 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-09 13:24 UTC (permalink / raw)
  To: bot+bpf-ci
  Cc: ast, daniel, andrii, bpf, martin.lau, eddyz87, songliubraving,
	yhs, oleg, mhiramat, martin.lau, yonghong.song, clm,
	ihor.solodrai

On Tue, Jun 09, 2026 at 11:17:11AM +0000, bot+bpf-ci@kernel.org wrote:
> > Allow uprobe_multi link to identify the target binary by an already
> > opened file descriptor.
> >
> > Adding new BPF_F_UPROBE_MULTI_PATH_FD flag and the path_fd field for
> > the attr.link_create.uprobe_multi struct.
> >
> > When the flag is set, we resolve the target from path_fd, without the
> > flag, we keep the existing string path behavior.
> >
> > I don't see a use case for supporting O_PATH file descriptors, because
> > we need need to read the binary first to get probes offsets, so I'm
> > using the CLASS(fd, f), which fails for O_PATH fds.
> >
> > Assisted-by: Codex:GPT-5.4
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> This change also fixes a latent bug in bpf_link_show_fdinfo(), changing
> the exact-equality test to a bitwise test:
> 
> 	else if (link->type == BPF_LINK_TYPE_UPROBE_MULTI)
> 		seq_printf(m, "link_type:\t%s\n", link->flags & BPF_F_UPROBE_MULTI_RETURN ?
> 			   "uretprobe_multi" : "uprobe_multi");
> 
> The original "link->flags == BPF_F_UPROBE_MULTI_RETURN" was harmless
> while BPF_F_UPROBE_MULTI_RETURN was the only defined uprobe_multi flag.
> This commit adds a second flag (BPF_F_UPROBE_MULTI_PATH_FD), so the
> exact "==" comparison would misreport a uretprobe_multi link as
> "uprobe_multi" whenever both flags are set.
> 
> Should this carry a Fixes: tag pointing at the commit that introduced
> the fragile comparison?
> 
>   Fixes: 803f0700a3bb ("bpf: Show precise link_type for {uprobe,kprobe}_multi fdinfo")

hum, I don't think so, it wasn't really a bug until this change

jirka

> 
> 
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
> 
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/27201419867


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
  2026-06-09 10:42 ` [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
  2026-06-09 10:57   ` sashiko-bot
  2026-06-09 11:17   ` bot+bpf-ci
@ 2026-06-09 18:22   ` Alexei Starovoitov
  2 siblings, 0 replies; 12+ messages in thread
From: Alexei Starovoitov @ 2026-06-09 18:22 UTC (permalink / raw)
  To: Jiri Olsa, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Martin KaFai Lau, Eduard Zingerman, Song Liu, Yonghong Song,
	Oleg Nesterov, Masami Hiramatsu

On Tue Jun 9, 2026 at 3:42 AM PDT, Jiri Olsa wrote:
>  	flags = attr->link_create.uprobe_multi.flags;
> -	if (flags & ~BPF_F_UPROBE_MULTI_RETURN)
> +	if (flags & ~(BPF_F_UPROBE_MULTI_RETURN|BPF_F_UPROBE_MULTI_PATH_FD))

In addition to what bots said, pls run checkpatch on above.
It should complain of lack of ' '.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-06-09 18:22 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-09 10:42 [PATCH bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
2026-06-09 10:42 ` [PATCH bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
2026-06-09 10:42 ` [PATCH bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
2026-06-09 10:57   ` sashiko-bot
2026-06-09 13:23     ` Jiri Olsa
2026-06-09 11:17   ` bot+bpf-ci
2026-06-09 13:24     ` Jiri Olsa
2026-06-09 18:22   ` Alexei Starovoitov
2026-06-09 10:42 ` [PATCH bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
2026-06-09 10:42 ` [PATCH bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
2026-06-09 10:42 ` [PATCH bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
2026-06-09 10:42 ` [PATCH bpf-next 6/6] selftests/bpf: Fix typo in verify_umulti_link_info Jiri Olsa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.