* [PATCHv3 bpf-next 1/7] bpf: Guard __get_user acesss with access_ok for uprobe_multi data
2026-06-11 11:42 [PATCHv3 bpf-next 0/7] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
@ 2026-06-11 11:42 ` Jiri Olsa
2026-06-11 11:55 ` sashiko-bot
2026-06-11 11:42 ` [PATCHv3 bpf-next 2/7] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
` (5 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Jiri Olsa @ 2026-06-11 11: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
As reported by sashiko [1] we need to use access_ok to check the user
space data bounds before we use __get-user to get it.
[1] https://lore.kernel.org/bpf/20260610145235.CB1441F00893@smtp.kernel.org/
Fixes: 0b779b61f651 ("bpf: Add cookies support for uprobe_multi link")
Fixes: 89ae89f53d20 ("bpf: Add multi uprobe link")
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
kernel/trace/bpf_trace.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 90432f0fc2a8..b5a12af2d3f8 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -3224,6 +3224,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
unsigned long __user *uoffsets;
u64 __user *ucookies;
void __user *upath;
+ unsigned long size;
u32 flags, cnt, i;
struct path path;
char *name;
@@ -3261,6 +3262,16 @@ 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);
+ /*
+ * All uoffsets/uref_ctr_offsets/ucookies arrays have the same value
+ * size, we need to check their address range is safe for __get_user
+ * calls.
+ */
+ size = sizeof(*uoffsets) * cnt;
+ if (!access_ok(uoffsets, size) || !access_ok(uref_ctr_offsets, size) ||
+ !access_ok(ucookies, size))
+ return -EFAULT;
+
name = strndup_user(upath, PATH_MAX);
if (IS_ERR(name)) {
err = PTR_ERR(name);
--
2.54.0
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCHv3 bpf-next 1/7] bpf: Guard __get_user acesss with access_ok for uprobe_multi data
2026-06-11 11:42 ` [PATCHv3 bpf-next 1/7] bpf: Guard __get_user acesss with access_ok for uprobe_multi data Jiri Olsa
@ 2026-06-11 11:55 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-06-11 11:55 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:
- [High] Missing access_ok() check for the usyms array in bpf_kprobe_multi_link_attach() allows arbitrary kernel memory read.
--
commit e5440667240e003d50bb838ad4b19e526ef6c703
Author: Jiri Olsa <jolsa@kernel.org>
bpf: Guard __get_user acesss with access_ok for uprobe_multi data
This patch adds access_ok checks for uprobe_multi arrays before calling
__get_user. It ensures that the user space data bounds are safe.
Link: https://lore.kernel.org/bpf/20260610145235.CB1441F00893@smtp.kernel.org/
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
[ ... ]
> @@ -3261,6 +3262,16 @@ 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);
>
> + /*
> + * All uoffsets/uref_ctr_offsets/ucookies arrays have the same value
> + * size, we need to check their address range is safe for __get_user
> + * calls.
> + */
> + size = sizeof(*uoffsets) * cnt;
> + if (!access_ok(uoffsets, size) || !access_ok(uref_ctr_offsets, size) ||
> + !access_ok(ucookies, size))
> + return -EFAULT;
[Severity: High]
This is a pre-existing issue, but while you are adding these access checks
for uprobes, does bpf_kprobe_multi_link_attach() have an identical missing
check for the usyms array?
Looking at bpf_kprobe_multi_link_attach(), it calls copy_user_syms() with
the unchecked user pointer usyms:
kernel/trace/bpf_trace.c:bpf_kprobe_multi_link_attach() {
...
struct user_syms us;
err = copy_user_syms(&us, usyms, cnt);
if (err)
goto error;
...
}
And copy_user_syms() iteratively calls __get_user(usymbol, usyms + i)
without any prior access checks on the array:
kernel/trace/bpf_trace.c:copy_user_syms() {
...
for (p = buf, i = 0; i < cnt; i++) {
if (__get_user(usymbol, usyms + i)) {
err = -EFAULT;
goto error;
}
...
}
Since __get_user() bypasses bounds checking, couldn't an attacker provide
a kernel address for usyms and read arbitrary kernel memory into usymbol?
A subsequent strncpy_from_user() call would use usymbol as its source
pointer, potentially acting as a side-channel oracle to leak kernel
information or bypass kernel address layout randomization.
Should copy_user_syms() or bpf_kprobe_multi_link_attach() also include
an access_ok() check for the usyms array?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260611114230.950379-2-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCHv3 bpf-next 2/7] bpf: Use user_path_at for path resolution in uprobe_multi
2026-06-11 11:42 [PATCHv3 bpf-next 0/7] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
2026-06-11 11:42 ` [PATCHv3 bpf-next 1/7] bpf: Guard __get_user acesss with access_ok for uprobe_multi data Jiri Olsa
@ 2026-06-11 11:42 ` Jiri Olsa
2026-06-11 11:42 ` [PATCHv3 bpf-next 3/7] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
` (4 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-11 11: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 b5a12af2d3f8..f8990bc6b64c 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -3227,7 +3227,6 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
unsigned long size;
u32 flags, cnt, i;
struct path path;
- char *name;
pid_t pid;
int err;
@@ -3272,14 +3271,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
!access_ok(ucookies, size))
return -EFAULT;
- 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* [PATCHv3 bpf-next 3/7] bpf: Add support to specify uprobe_multi target via file descriptor
2026-06-11 11:42 [PATCHv3 bpf-next 0/7] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
2026-06-11 11:42 ` [PATCHv3 bpf-next 1/7] bpf: Guard __get_user acesss with access_ok for uprobe_multi data Jiri Olsa
2026-06-11 11:42 ` [PATCHv3 bpf-next 2/7] bpf: Use user_path_at for path resolution in uprobe_multi Jiri Olsa
@ 2026-06-11 11:42 ` Jiri Olsa
2026-06-11 11:42 ` [PATCHv3 bpf-next 4/7] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
` (3 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-11 11: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 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 7ed949f70f82..b44106c8ea75 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3480,7 +3480,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]);
@@ -5840,7 +5840,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 f8990bc6b64c..82f8feea6931 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;
unsigned long size;
u32 flags, cnt, i;
struct path path;
@@ -3241,19 +3273,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;
@@ -3271,7 +3302,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
!access_ok(ucookies, size))
return -EFAULT;
- 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] 12+ messages in thread* [PATCHv3 bpf-next 4/7] libbpf: Add path_fd to struct bpf_link_create_opts
2026-06-11 11:42 [PATCHv3 bpf-next 0/7] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
` (2 preceding siblings ...)
2026-06-11 11:42 ` [PATCHv3 bpf-next 3/7] bpf: Add support to specify uprobe_multi target via file descriptor Jiri Olsa
@ 2026-06-11 11:42 ` Jiri Olsa
2026-06-11 11:53 ` sashiko-bot
2026-06-11 11:42 ` [PATCHv3 bpf-next 5/7] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
` (2 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Jiri Olsa @ 2026-06-11 11: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* Re: [PATCHv3 bpf-next 4/7] libbpf: Add path_fd to struct bpf_link_create_opts
2026-06-11 11:42 ` [PATCHv3 bpf-next 4/7] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
@ 2026-06-11 11:53 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-06-11 11:53 UTC (permalink / raw)
To: Jiri Olsa; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] The kernel-side implementation for processing `path_fd` is completely missing.
- [Medium] The high-level libbpf API for uprobe_multi was not updated to support `path_fd`.
- [Low] The patch references a non-existent `path_fd` field in `union bpf_attr`'s `uprobe_multi` struct, which will cause a fatal compilation failure.
- [Low] The `path_fd` field is incorrectly typed as `__u32` instead of a signed integer, breaking proper semantics for special directory file descriptors like `AT_FDCWD`.
--
commit f8c10c02ad07ee86163cb02487766ca5ac58a262
Author: Jiri Olsa <jolsa@kernel.org>
libbpf: Add path_fd to struct bpf_link_create_opts
This patch adds the path_fd field to struct bpf_link_create_opts and
attempts to pass it through the kernel attribute interface for uprobe_multi
links.
> libbpf: Add path_fd to struct bpf_link_create_opts
>
> Adding the path_fd field to struct bpf_link_create_opts and passing it
> through kernel attr interface.
[Severity: Medium]
Are there missing kernel-side changes in this patch? The commit message
states the field is being passed through the kernel attr interface, but there
are no corresponding changes in sys_bpf() or bpf_uprobe_multi_link_attach()
to extract and utilize the path_fd parameter.
[Severity: Medium]
Will this feature be exposed to the high-level libbpf API? The path_fd field
was added to the low-level struct bpf_link_create_opts, but the user-facing
struct bpf_uprobe_multi_opts and bpf_program__attach_uprobe_multi() do not
appear to be updated to support it.
> 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]
Does this assignment cause a build failure? It looks like the path_fd field
has not been added to the UAPI union bpf_attr for uprobe_multi.
> 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 012354131cf66..7534a593edae2 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;
[Severity: Low]
Should path_fd be defined as a signed integer, such as __s32 or int? File
descriptors intended for path lookup need to support special values like
AT_FDCWD (-100), which will wrap around if stored in an unsigned 32-bit
variable.
> } uprobe_multi;
> struct {
> __u64 cookie;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260611114230.950379-5-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCHv3 bpf-next 5/7] selftests/bpf: Add uprobe_multi path_fd test
2026-06-11 11:42 [PATCHv3 bpf-next 0/7] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
` (3 preceding siblings ...)
2026-06-11 11:42 ` [PATCHv3 bpf-next 4/7] libbpf: Add path_fd to struct bpf_link_create_opts Jiri Olsa
@ 2026-06-11 11:42 ` Jiri Olsa
2026-06-11 11:52 ` sashiko-bot
2026-06-11 11:42 ` [PATCHv3 bpf-next 6/7] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
2026-06-11 11:42 ` [PATCHv3 bpf-next 7/7] selftests/bpf: Fix typo in verify_umulti_link_info Jiri Olsa
6 siblings, 1 reply; 12+ messages in thread
From: Jiri Olsa @ 2026-06-11 11: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..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] 12+ messages in thread* Re: [PATCHv3 bpf-next 5/7] selftests/bpf: Add uprobe_multi path_fd test
2026-06-11 11:42 ` [PATCHv3 bpf-next 5/7] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
@ 2026-06-11 11:52 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-06-11 11:52 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 uses a non-existent structure member `opts.uprobe_multi.path_fd` and an undefined macro `BPF_F_UPROBE_MULTI_PATH_FD`, which will cause a build failure.
--
commit 7f1afda8cdc452975b891e8563b1e8e01d191c3a
Author: Jiri Olsa <jolsa@kernel.org>
selftests/bpf: Add uprobe_multi path_fd test
This patch adds a uprobe_multi link API selftest. The test opens
/proc/self/exe and passes the descriptor through opts.uprobe_multi.path_fd
using the BPF_F_UPROBE_MULTI_PATH_FD flag.
> 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;
> + struct uprobe_multi *skel = NULL;
[ ... ]
> + 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 the uprobe_multi structure in bpf_link_create_opts actually have a
path_fd member? It appears this code references an undefined struct member
along with an undefined macro BPF_F_UPROBE_MULTI_PATH_FD. Will this cause
a build failure?
> +
> + skel = uprobe_multi__open_and_load();
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260611114230.950379-6-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCHv3 bpf-next 6/7] selftests/bpf: Add uprobe_multi path_fd fail tests
2026-06-11 11:42 [PATCHv3 bpf-next 0/7] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
` (4 preceding siblings ...)
2026-06-11 11:42 ` [PATCHv3 bpf-next 5/7] selftests/bpf: Add uprobe_multi path_fd test Jiri Olsa
@ 2026-06-11 11:42 ` Jiri Olsa
2026-06-11 11:54 ` sashiko-bot
2026-06-11 11:42 ` [PATCHv3 bpf-next 7/7] selftests/bpf: Fix typo in verify_umulti_link_info Jiri Olsa
6 siblings, 1 reply; 12+ messages in thread
From: Jiri Olsa @ 2026-06-11 11: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 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] 12+ messages in thread* Re: [PATCHv3 bpf-next 6/7] selftests/bpf: Add uprobe_multi path_fd fail tests
2026-06-11 11:42 ` [PATCHv3 bpf-next 6/7] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
@ 2026-06-11 11:54 ` sashiko-bot
0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-06-11 11:54 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 introduces a compilation failure because it uses the undeclared macro BPF_F_UPROBE_MULTI_PATH_FD and references a non-existent struct member 'path_fd' in struct bpf_link_create_opts.
--
commit acbff7cfc9a00c3bfed7027c436c6abc5a678d5d
Author: Jiri Olsa <jolsa@kernel.org>
selftests/bpf: Add uprobe_multi path_fd fail tests
This commit adds new tests to the attach_api_fails suite in
uprobe_multi_test.c to ensure that incorrect setups using path_fd 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
> index 56cbea280fbd2..58a7db7fba902 100644
> --- 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)
> 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,
[Severity: Low]
Does this cause a compilation failure? The struct member path_fd in
bpf_link_create_opts and the BPF_F_UPROBE_MULTI_PATH_FD macro appear to be
missing or undeclared here, which would typically cause the compiler to fail
with an undeclared identifier error.
> + .uprobe_multi.offsets = (unsigned long *)&offset,
> + .uprobe_multi.cnt = 1,
> + );
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260611114230.950379-7-jolsa@kernel.org?part=1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCHv3 bpf-next 7/7] selftests/bpf: Fix typo in verify_umulti_link_info
2026-06-11 11:42 [PATCHv3 bpf-next 0/7] bpf: Allow uprobe_multi binary specified by file descriptor Jiri Olsa
` (5 preceding siblings ...)
2026-06-11 11:42 ` [PATCHv3 bpf-next 6/7] selftests/bpf: Add uprobe_multi path_fd fail tests Jiri Olsa
@ 2026-06-11 11:42 ` Jiri Olsa
6 siblings, 0 replies; 12+ messages in thread
From: Jiri Olsa @ 2026-06-11 11: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.
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] 12+ messages in thread