* [PATCHv2 bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor
@ 2026-06-10 14:36 Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
` (5 more replies)
0 siblings, 6 replies; 17+ messages in thread
From: Jiri Olsa @ 2026-06-10 14:36 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.
v1: https://lore.kernel.org/bpf/20260609104244.588321-1-jolsa@kernel.org/T/#m0275d5f39805c57dc8fd3308c640237dc7aec4db
v2 changes:
- move path retrieval in separate function so CLASS(..) is not used in function
with goto-based cleanup [sashiko]
- force zero path_fd in case BPF_F_UPROBE_MULTI_PATH_FD is not set [sashiko]
- add space around | in bpf_uprobe_multi_link_attach [Alexei]
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 | 51 +++++++++++++++++++++++++++-----------
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, 148 insertions(+), 21 deletions(-)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCHv2 bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi
2026-06-10 14:36 [PATCHv2 bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
@ 2026-06-10 14:36 ` Jiri Olsa
2026-06-10 14:52 ` sashiko-bot
2026-06-10 14:36 ` [PATCHv2 bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
` (4 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Jiri Olsa @ 2026-06-10 14:36 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] 17+ messages in thread
* [PATCHv2 bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
2026-06-10 14:36 [PATCHv2 bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
@ 2026-06-10 14:36 ` Jiri Olsa
2026-06-10 15:51 ` bot+bpf-ci
2026-06-10 14:36 ` [PATCHv2 bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
` (3 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Jiri Olsa @ 2026-06-10 14:36 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 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 | 43 +++++++++++++++++++++++++++++-----
tools/include/uapi/linux/bpf.h | 7 +++++-
4 files changed, 51 insertions(+), 10 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..f5d68f6d90f3 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>
@@ -3214,6 +3215,38 @@ static u64 bpf_uprobe_multi_cookie(struct bpf_run_ctx *ctx)
return run_ctx->uprobe->cookie;
}
+static int bpf_uprobe_multi_get_path(const union bpf_attr *attr, struct path *path)
+{
+ void __user *upath = u64_to_user_ptr(attr->link_create.uprobe_multi.path);
+ u32 path_fd = attr->link_create.uprobe_multi.path_fd;
+ u32 flags = attr->link_create.uprobe_multi.flags;
+
+ if (flags & BPF_F_UPROBE_MULTI_PATH_FD) {
+ /*
+ * When BPF_F_UPROBE_MULTI_PATH_FD is set, the executable is
+ * identified by path_fd, upath must be NULL.
+ */
+ if (upath)
+ return -EINVAL;
+
+ CLASS(fd, f)(path_fd);
+ if (fd_empty(f))
+ return -EBADF;
+ *path = fd_file(f)->f_path;
+ path_get(path);
+ return 0;
+ }
+
+ /*
+ * 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 || path_fd)
+ return -EINVAL;
+
+ return user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, path);
+}
+
int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
{
struct bpf_uprobe_multi_link *link = NULL;
@@ -3223,7 +3256,6 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
struct task_struct *task = NULL;
unsigned long __user *uoffsets;
u64 __user *ucookies;
- void __user *upath;
u32 flags, cnt, i;
struct path path;
pid_t pid;
@@ -3240,19 +3272,18 @@ 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;
@@ -3260,7 +3291,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);
- err = user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, &path);
+ err = bpf_uprobe_multi_get_path(attr, &path);
if (err)
return err;
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] 17+ messages in thread
* [PATCHv2 bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts
2026-06-10 14:36 [PATCHv2 bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
@ 2026-06-10 14:36 ` Jiri Olsa
2026-06-10 14:50 ` sashiko-bot
2026-06-10 14:36 ` [PATCHv2 bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
` (2 subsequent siblings)
5 siblings, 1 reply; 17+ messages in thread
From: Jiri Olsa @ 2026-06-10 14:36 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] 17+ messages in thread
* [PATCHv2 bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test
2026-06-10 14:36 [PATCHv2 bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
` (2 preceding siblings ...)
2026-06-10 14:36 ` [PATCHv2 bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
@ 2026-06-10 14:36 ` Jiri Olsa
2026-06-10 14:50 ` sashiko-bot
2026-06-10 14:36 ` [PATCHv2 bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 6/6] selftests/bpf: Fix typo in verify_umulti_link_info Jiri Olsa
5 siblings, 1 reply; 17+ messages in thread
From: Jiri Olsa @ 2026-06-10 14:36 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..ffcf3c92f047 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)
+{
+ LIBBPF_OPTS(bpf_link_create_opts, opts);
+ const char *resolve_path = "/proc/self/exe";
+ 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] 17+ messages in thread
* [PATCHv2 bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests
2026-06-10 14:36 [PATCHv2 bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
` (3 preceding siblings ...)
2026-06-10 14:36 ` [PATCHv2 bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
@ 2026-06-10 14:36 ` Jiri Olsa
2026-06-10 14:48 ` sashiko-bot
2026-06-10 14:36 ` [PATCHv2 bpf-next 6/6] selftests/bpf: Fix typo in verify_umulti_link_info Jiri Olsa
5 siblings, 1 reply; 17+ messages in thread
From: Jiri Olsa @ 2026-06-10 14:36 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 ffcf3c92f047..f0baf5738b75 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] 17+ messages in thread
* [PATCHv2 bpf-next 6/6] selftests/bpf: Fix typo in verify_umulti_link_info
2026-06-10 14:36 [PATCHv2 bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
` (4 preceding siblings ...)
2026-06-10 14:36 ` [PATCHv2 bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
@ 2026-06-10 14:36 ` Jiri Olsa
5 siblings, 0 replies; 17+ messages in thread
From: Jiri Olsa @ 2026-06-10 14:36 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.
Fixes: 147c69307bcf ("selftests/bpf: Add link_info test for uprobe_multi link")
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] 17+ messages in thread
* Re: [PATCHv2 bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests
2026-06-10 14:36 ` [PATCHv2 bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
@ 2026-06-10 14:48 ` sashiko-bot
2026-06-11 9:37 ` Jiri Olsa
0 siblings, 1 reply; 17+ messages in thread
From: sashiko-bot @ 2026-06-10 14:48 UTC (permalink / raw)
To: Jiri Olsa; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The patch references an undefined struct member `path_fd` and an undeclared macro `BPF_F_UPROBE_MULTI_PATH_FD`, which will cause compilation to fail.
--
commit 0e3f7d4f9ed46a64d02a1c29acb4f8e2215cb7c0
Author: Jiri Olsa <jolsa@kernel.org>
selftests/bpf: Add uprobe_multi path_fd fail tests
This commit adds tests to the attach_api_fails suite to verify that
invalid setups using the new path_fd feature in uprobe_multi fail as
expected.
> diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> @@ -536,7 +536,37 @@ static void test_attach_api_fails(void)
[ ... ]
> - 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,
[Severity: Low]
Does this commit depend on a missing prerequisite patch?
The path_fd member and BPF_F_UPROBE_MULTI_PATH_FD macro do not appear to be
defined in the current tree's bpf_link_create_opts struct or UAPI headers,
which will cause a compilation failure here.
> + .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,
> + );
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260610143627.804790-6-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts
2026-06-10 14:36 ` [PATCHv2 bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
@ 2026-06-10 14:50 ` sashiko-bot
2026-06-11 9:37 ` Jiri Olsa
0 siblings, 1 reply; 17+ messages in thread
From: sashiko-bot @ 2026-06-10 14:50 UTC (permalink / raw)
To: Jiri Olsa; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Compilation fails due to missing `path_fd` in the `uprobe_multi` UAPI struct.
--
commit c73ec6f8d6c5a6bb4c8a75f70c333cac0d6d30d4
Author: Jiri Olsa <jolsa@kernel.org>
libbpf: Add path_fd to struct bpf_link_create_opts
This commit adds the path_fd field to struct bpf_link_create_opts for
uprobe_multi. It passes this new field through the kernel attribute interface.
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index f37e3416f61a5..96819c082c772 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);
[Severity: Low]
Will this assignment cause a build failure?
Looking at the UAPI header in tools/include/uapi/linux/bpf.h, the
uprobe_multi struct inside union bpf_attr doesn't appear to have a path_fd
member:
struct {
__aligned_u64 path;
__aligned_u64 offsets;
__aligned_u64 ref_ctr_offsets;
__aligned_u64 cookies;
__u32 cnt;
__u32 flags;
__u32 pid;
} uprobe_multi;
Should the path_fd member be added to the UAPI bpf_attr union as well?
> if (!OPTS_ZEROED(opts, uprobe_multi))
> return libbpf_err(-EINVAL);
> break;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260610143627.804790-4-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test
2026-06-10 14:36 ` [PATCHv2 bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
@ 2026-06-10 14:50 ` sashiko-bot
2026-06-11 9:37 ` Jiri Olsa
0 siblings, 1 reply; 17+ messages in thread
From: sashiko-bot @ 2026-06-10 14:50 UTC (permalink / raw)
To: Jiri Olsa; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The selftest references a nonexistent struct member `path_fd` and an undeclared flag `BPF_F_UPROBE_MULTI_PATH_FD`, which will cause a compilation error.
--
commit e5937d581d08ece9671b371d37fb6cd0d497b692
Author: Jiri Olsa <jolsa@kernel.org>
selftests/bpf: Add uprobe_multi path_fd test
This commit adds 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.
> 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 56cbea280fbd2..ffcf3c92f0474 100644
> --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
[ ... ]
> @@ -757,6 +758,65 @@ static void test_link_api(void)
> __test_link_api(&child);
> }
>
> +static void test_link_api_path_fd(void)
> +{
> + LIBBPF_OPTS(bpf_link_create_opts, opts);
> + const char *resolve_path = "/proc/self/exe";
> + int prog_fd, link_fd = -1, path_fd = -1;
[ ... ]
> + 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;
[Severity: Low]
Does this code reference an API that hasn't been introduced yet?
The struct field path_fd is not a valid member of uprobe_multi within
struct bpf_link_create_opts in the libbpf headers, and the
BPF_F_UPROBE_MULTI_PATH_FD macro is undeclared.
Because the patch doesn't include the corresponding kernel or libbpf
changes, it looks like this will cause a compilation error.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260610143627.804790-5-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi
2026-06-10 14:36 ` [PATCHv2 bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
@ 2026-06-10 14:52 ` sashiko-bot
2026-06-11 9:37 ` Jiri Olsa
0 siblings, 1 reply; 17+ messages in thread
From: sashiko-bot @ 2026-06-10 14:52 UTC (permalink / raw)
To: Jiri Olsa; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Missing `access_ok()` checks before calling `__get_user()` on user-controlled arrays, leading to arbitrary kernel memory read.
--
commit e18574361f20d4f27005e4d927610e3ce16986dd
Author: Jiri Olsa <jolsa@kernel.org>
bpf: Use user_path_at for path resolution in uprobe_multi
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.
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index 90432f0fc2a8e..970ce7bbf99e1 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
[ ... ]
> @@ -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;
>
[Severity: Critical]
This isn't a bug introduced by this patch, but while looking at
bpf_uprobe_multi_link_attach(), I noticed the user-provided arrays
uoffsets, uref_ctr_offsets, and ucookies are accessed shortly after this
path resolution:
kernel/trace/bpf_trace.c:bpf_uprobe_multi_link_attach() {
...
if (__get_user(uprobes[i].offset, uoffsets + i)) {
...
if (uref_ctr_offsets && __get_user(uprobes[i].ref_ctr_offset, uref_ctr_offsets + i)) {
...
if (ucookies && __get_user(uprobes[i].cookie, ucookies + i)) {
...
}
Are these arrays validated with access_ok() before __get_user() is called?
Because __get_user() bypasses the access_ok() address-space bounds check
on most architectures, could an attacker supply kernel addresses for these
arrays, causing the kernel to read arbitrary memory and store it into the
uprobes structures?
If an attacker retrieves these contents by querying the link info via
bpf_obj_get_info_by_fd() (which calls bpf_uprobe_multi_link_fill_link_info()
and copies the memory back to user space), could this act as an arbitrary
kernel memory read primitive to bypass kernel lockdown and KASLR?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260610143627.804790-2-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
2026-06-10 14:36 ` [PATCHv2 bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
@ 2026-06-10 15:51 ` bot+bpf-ci
2026-06-11 9:37 ` Jiri Olsa
0 siblings, 1 reply; 17+ messages in thread
From: bot+bpf-ci @ 2026-06-10 15:51 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: 3148 bytes --]
> 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");
This change in bpf_link_show_fdinfo() switches the uprobe_multi check from
an equality test to a bitwise test. Once a second flag bit exists (the
BPF_F_UPROBE_MULTI_PATH_FD flag added by this same patch), a uretprobe_multi
link created with both flags set would be misreported as "uprobe_multi"
because the equality test no longer matches.
The equality comparison was introduced in:
803f0700a3bb ("bpf: Show precise link_type for {uprobe,kprobe}_multi fdinfo")
Should this change include:
Fixes: 803f0700a3bb ("bpf: Show precise link_type for {uprobe,kprobe}_multi fdinfo")
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index 970ce7bbf99e..f5d68f6d90f3 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
> @@ -3214,6 +3215,38 @@ static u64 bpf_uprobe_multi_cookie(struct bpf_run_ctx *ctx)
> return run_ctx->uprobe->cookie;
> }
>
> +static int bpf_uprobe_multi_get_path(const union bpf_attr *attr, struct path *path)
> +{
> + void __user *upath = u64_to_user_ptr(attr->link_create.uprobe_multi.path);
> + u32 path_fd = attr->link_create.uprobe_multi.path_fd;
> + u32 flags = attr->link_create.uprobe_multi.flags;
> +
> + if (flags & BPF_F_UPROBE_MULTI_PATH_FD) {
[ ... ]
> + }
> +
> + /*
> + * 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 || path_fd)
> + return -EINVAL;
This isn't a bug, but the non-FD branch (taken when
BPF_F_UPROBE_MULTI_PATH_FD is not set) reads path_fd in the check
'if (!upath || path_fd)'.
path_fd is only meaningful when BPF_F_UPROBE_MULTI_PATH_FD is set. A caller
that supplies a valid string path but leaves path_fd as non-zero garbage (in
a struct large enough to include path_fd) would get a spurious -EINVAL here.
The garbage value is never dereferenced or used for arithmetic, so this looks
more like defensive input validation than a dangerous use, and old-style
callers passing the pre-path_fd struct size get path_fd zeroed and pass
cleanly.
Is rejecting a non-zero path_fd in the string-path mode intended, or should
path_fd be ignored when the flag is absent?
> +
> + return user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, path);
> +}
---
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/27284577665
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test
2026-06-10 14:50 ` sashiko-bot
@ 2026-06-11 9:37 ` Jiri Olsa
0 siblings, 0 replies; 17+ messages in thread
From: Jiri Olsa @ 2026-06-11 9:37 UTC (permalink / raw)
To: sashiko-reviews; +Cc: bpf
On Wed, Jun 10, 2026 at 02:50:45PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Low] The selftest references a nonexistent struct member `path_fd` and an undeclared flag `BPF_F_UPROBE_MULTI_PATH_FD`, which will cause a compilation error.
> --
>
> commit e5937d581d08ece9671b371d37fb6cd0d497b692
> Author: Jiri Olsa <jolsa@kernel.org>
>
> selftests/bpf: Add uprobe_multi path_fd test
>
> This commit adds 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.
>
> > 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 56cbea280fbd2..ffcf3c92f0474 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
>
> [ ... ]
>
> > @@ -757,6 +758,65 @@ static void test_link_api(void)
> > __test_link_api(&child);
> > }
> >
> > +static void test_link_api_path_fd(void)
> > +{
> > + LIBBPF_OPTS(bpf_link_create_opts, opts);
> > + const char *resolve_path = "/proc/self/exe";
> > + int prog_fd, link_fd = -1, path_fd = -1;
>
> [ ... ]
>
> > + 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;
>
> [Severity: Low]
> Does this code reference an API that hasn't been introduced yet?
>
> The struct field path_fd is not a valid member of uprobe_multi within
> struct bpf_link_create_opts in the libbpf headers, and the
> BPF_F_UPROBE_MULTI_PATH_FD macro is undeclared.
>
> Because the patch doesn't include the corresponding kernel or libbpf
> changes, it looks like this will cause a compilation error.
compiles fine, it was introduced in:
bpf: Add support to specify uprobe_multi target via file descriptor
jirka
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests
2026-06-10 14:48 ` sashiko-bot
@ 2026-06-11 9:37 ` Jiri Olsa
0 siblings, 0 replies; 17+ messages in thread
From: Jiri Olsa @ 2026-06-11 9:37 UTC (permalink / raw)
To: sashiko-reviews; +Cc: bpf
On Wed, Jun 10, 2026 at 02:48:21PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Low] The patch references an undefined struct member `path_fd` and an undeclared macro `BPF_F_UPROBE_MULTI_PATH_FD`, which will cause compilation to fail.
> --
>
> commit 0e3f7d4f9ed46a64d02a1c29acb4f8e2215cb7c0
> Author: Jiri Olsa <jolsa@kernel.org>
>
> selftests/bpf: Add uprobe_multi path_fd fail tests
>
> This commit adds tests to the attach_api_fails suite to verify that
> invalid setups using the new path_fd feature in uprobe_multi fail as
> expected.
>
> > diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> > --- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c
> > @@ -536,7 +536,37 @@ static void test_attach_api_fails(void)
>
> [ ... ]
>
> > - 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,
>
> [Severity: Low]
> Does this commit depend on a missing prerequisite patch?
>
> The path_fd member and BPF_F_UPROBE_MULTI_PATH_FD macro do not appear to be
> defined in the current tree's bpf_link_create_opts struct or UAPI headers,
> which will cause a compilation failure here.
it compiles fine, it was added in this commit:
bpf: Add support to specify uprobe_multi target via file descriptor
jirka
>
> > + .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,
> > + );
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260610143627.804790-6-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts
2026-06-10 14:50 ` sashiko-bot
@ 2026-06-11 9:37 ` Jiri Olsa
0 siblings, 0 replies; 17+ messages in thread
From: Jiri Olsa @ 2026-06-11 9:37 UTC (permalink / raw)
To: sashiko-reviews; +Cc: bpf
On Wed, Jun 10, 2026 at 02:50:18PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Low] Compilation fails due to missing `path_fd` in the `uprobe_multi` UAPI struct.
> --
>
> commit c73ec6f8d6c5a6bb4c8a75f70c333cac0d6d30d4
> Author: Jiri Olsa <jolsa@kernel.org>
>
> libbpf: Add path_fd to struct bpf_link_create_opts
>
> This commit adds the path_fd field to struct bpf_link_create_opts for
> uprobe_multi. It passes this new field through the kernel attribute interface.
>
> > diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> > index f37e3416f61a5..96819c082c772 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);
>
> [Severity: Low]
> Will this assignment cause a build failure?
>
> Looking at the UAPI header in tools/include/uapi/linux/bpf.h, the
> uprobe_multi struct inside union bpf_attr doesn't appear to have a path_fd
> member:
compiles fine, path_fd was added in previous patch
jirka
>
> struct {
> __aligned_u64 path;
> __aligned_u64 offsets;
> __aligned_u64 ref_ctr_offsets;
> __aligned_u64 cookies;
> __u32 cnt;
> __u32 flags;
> __u32 pid;
> } uprobe_multi;
>
> Should the path_fd member be added to the UAPI bpf_attr union as well?
>
> > if (!OPTS_ZEROED(opts, uprobe_multi))
> > return libbpf_err(-EINVAL);
> > break;
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260610143627.804790-4-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi
2026-06-10 14:52 ` sashiko-bot
@ 2026-06-11 9:37 ` Jiri Olsa
0 siblings, 0 replies; 17+ messages in thread
From: Jiri Olsa @ 2026-06-11 9:37 UTC (permalink / raw)
To: sashiko-reviews; +Cc: bpf
On Wed, Jun 10, 2026 at 02:52:35PM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [Critical] Missing `access_ok()` checks before calling `__get_user()` on user-controlled arrays, leading to arbitrary kernel memory read.
> --
>
> commit e18574361f20d4f27005e4d927610e3ce16986dd
> Author: Jiri Olsa <jolsa@kernel.org>
>
> bpf: Use user_path_at for path resolution in uprobe_multi
>
> 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.
>
> > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> > index 90432f0fc2a8e..970ce7bbf99e1 100644
> > --- a/kernel/trace/bpf_trace.c
> > +++ b/kernel/trace/bpf_trace.c
>
> [ ... ]
>
> > @@ -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;
> >
>
> [Severity: Critical]
> This isn't a bug introduced by this patch, but while looking at
> bpf_uprobe_multi_link_attach(), I noticed the user-provided arrays
> uoffsets, uref_ctr_offsets, and ucookies are accessed shortly after this
> path resolution:
>
> kernel/trace/bpf_trace.c:bpf_uprobe_multi_link_attach() {
> ...
> if (__get_user(uprobes[i].offset, uoffsets + i)) {
> ...
> if (uref_ctr_offsets && __get_user(uprobes[i].ref_ctr_offset, uref_ctr_offsets + i)) {
> ...
> if (ucookies && __get_user(uprobes[i].cookie, ucookies + i)) {
> ...
> }
>
> Are these arrays validated with access_ok() before __get_user() is called?
>
> Because __get_user() bypasses the access_ok() address-space bounds check
> on most architectures, could an attacker supply kernel addresses for these
> arrays, causing the kernel to read arbitrary memory and store it into the
> uprobes structures?
>
> If an attacker retrieves these contents by querying the link info via
> bpf_obj_get_info_by_fd() (which calls bpf_uprobe_multi_link_fill_link_info()
> and copies the memory back to user space), could this act as an arbitrary
> kernel memory read primitive to bypass kernel lockdown and KASLR?
ugh right.. will include fix for this in next version
jirka
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCHv2 bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor
2026-06-10 15:51 ` bot+bpf-ci
@ 2026-06-11 9:37 ` Jiri Olsa
0 siblings, 0 replies; 17+ messages in thread
From: Jiri Olsa @ 2026-06-11 9:37 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 Wed, Jun 10, 2026 at 03:51:39PM +0000, bot+bpf-ci@kernel.org wrote:
> > 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");
>
> This change in bpf_link_show_fdinfo() switches the uprobe_multi check from
> an equality test to a bitwise test. Once a second flag bit exists (the
> BPF_F_UPROBE_MULTI_PATH_FD flag added by this same patch), a uretprobe_multi
> link created with both flags set would be misreported as "uprobe_multi"
> because the equality test no longer matches.
>
> The equality comparison was introduced in:
>
> 803f0700a3bb ("bpf: Show precise link_type for {uprobe,kprobe}_multi fdinfo")
>
> Should this change include:
>
> Fixes: 803f0700a3bb ("bpf: Show precise link_type for {uprobe,kprobe}_multi fdinfo")
answered this one in previous version
jirka
>
> > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> > index 970ce7bbf99e..f5d68f6d90f3 100644
> > --- a/kernel/trace/bpf_trace.c
> > +++ b/kernel/trace/bpf_trace.c
> > @@ -3214,6 +3215,38 @@ static u64 bpf_uprobe_multi_cookie(struct bpf_run_ctx *ctx)
> > return run_ctx->uprobe->cookie;
> > }
> >
> > +static int bpf_uprobe_multi_get_path(const union bpf_attr *attr, struct path *path)
> > +{
> > + void __user *upath = u64_to_user_ptr(attr->link_create.uprobe_multi.path);
> > + u32 path_fd = attr->link_create.uprobe_multi.path_fd;
> > + u32 flags = attr->link_create.uprobe_multi.flags;
> > +
> > + if (flags & BPF_F_UPROBE_MULTI_PATH_FD) {
>
> [ ... ]
>
> > + }
> > +
> > + /*
> > + * 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 || path_fd)
> > + return -EINVAL;
>
> This isn't a bug, but the non-FD branch (taken when
> BPF_F_UPROBE_MULTI_PATH_FD is not set) reads path_fd in the check
> 'if (!upath || path_fd)'.
>
> path_fd is only meaningful when BPF_F_UPROBE_MULTI_PATH_FD is set. A caller
> that supplies a valid string path but leaves path_fd as non-zero garbage (in
> a struct large enough to include path_fd) would get a spurious -EINVAL here.
>
> The garbage value is never dereferenced or used for arithmetic, so this looks
> more like defensive input validation than a dangerous use, and old-style
> callers passing the pre-path_fd struct size get path_fd zeroed and pass
> cleanly.
>
> Is rejecting a non-zero path_fd in the string-path mode intended, or should
> path_fd be ignored when the flag is absent?
>
> > +
> > + return user_path_at(AT_FDCWD, upath, LOOKUP_FOLLOW, path);
> > +}
>
>
> ---
> 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/27284577665
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-06-11 9:37 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-10 14:36 [PATCHv2 bpf-next 0/6] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 1/6] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
2026-06-10 14:52 ` sashiko-bot
2026-06-11 9:37 ` Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 2/6] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
2026-06-10 15:51 ` bot+bpf-ci
2026-06-11 9:37 ` Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 3/6] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
2026-06-10 14:50 ` sashiko-bot
2026-06-11 9:37 ` Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 4/6] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
2026-06-10 14:50 ` sashiko-bot
2026-06-11 9:37 ` Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 bpf-next 5/6] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
2026-06-10 14:48 ` sashiko-bot
2026-06-11 9:37 ` Jiri Olsa
2026-06-10 14:36 ` [PATCHv2 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.