[PATCH bpf-next 2/9] bpf: Add log support for tracing_multi link_create

From: Leon Hwang

Date: Mon Nov 09 2026 - 09:14:24 EST


tracing_multi BPF_LINK_CREATE returns an error for invalid counts, missing
IDs, unsupported flags, or a nonzero target FD without explaining which
check failed.

Report these failures through the BPF_LINK_CREATE log.

Signed-off-by: Leon Hwang <leon.hwang@xxxxxxxxx>
---
include/linux/trace_events.h | 7 +++++--
kernel/bpf/syscall.c | 2 +-
kernel/trace/bpf_trace.c | 26 +++++++++++++++++++++-----
3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 321f2f3a6c8e..bb825ea5d09c 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -16,6 +16,7 @@ struct tracer;
struct dentry;
struct bpf_prog;
union bpf_attr;
+struct bpf_verifier_log;

/* Used for event string fields when they are NULL */
#define EVENT_NULL_STR "(null)"
@@ -796,7 +797,8 @@ int bpf_get_perf_event_info(const struct perf_event *event, u32 *prog_id,
unsigned long *missed);
int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
-int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr);
+int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr,
+ struct bpf_verifier_log *log);
#else
static inline unsigned int trace_call_bpf(struct trace_event_call *call, void *ctx)
{
@@ -855,7 +857,8 @@ bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
return -EOPNOTSUPP;
}
static inline int
-bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr)
+bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr,
+ struct bpf_verifier_log *log)
{
return -EOPNOTSUPP;
}
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 6147d386b777..aed1c6a2f203 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -5932,7 +5932,7 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr, struct bpf_common_a
else if (prog->expected_attach_type == BPF_LSM_CGROUP)
ret = cgroup_bpf_link_attach(attr, prog);
else if (is_tracing_multi(prog->expected_attach_type))
- ret = bpf_tracing_multi_attach(prog, attr);
+ ret = bpf_tracing_multi_attach(prog, attr, log);
else
ret = bpf_tracing_prog_attach(prog,
attr->link_create.target_fd,
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 2aec56d7f3d3..352a1cd0c863 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -3861,7 +3861,8 @@ static int check_dup_ids(u32 *ids, u64 *cookies, u32 cnt)
return err;
}

-int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr)
+int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr,
+ struct bpf_verifier_log *log)
{
struct bpf_tracing_multi_link *link = NULL;
struct bpf_tramp_node *fexits = NULL;
@@ -3875,12 +3876,26 @@ int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr)
uids = u64_to_user_ptr(attr->link_create.tracing_multi.ids);
cnt = attr->link_create.tracing_multi.cnt;

- if (!cnt || !uids)
+ if (!cnt) {
+ bpf_log(log, "tracing_multi.cnt cannot be zero.\n");
return -EINVAL;
- if (cnt > MAX_TRACING_MULTI_CNT)
+ }
+ if (!uids) {
+ bpf_log(log, "tracing_multi.ids must be set.\n");
+ return -EINVAL;
+ }
+ if (cnt > MAX_TRACING_MULTI_CNT) {
+ bpf_log(log, "tracing_multi.cnt is too large.\n");
return -E2BIG;
- if (attr->link_create.flags || attr->link_create.target_fd)
+ }
+ if (attr->link_create.flags) {
+ bpf_log(log, "Invalid flags.\n");
return -EINVAL;
+ }
+ if (attr->link_create.target_fd) {
+ bpf_log(log, "Invalid target_fd.\n");
+ return -EINVAL;
+ }

ids = kvmalloc_objs(*ids, cnt);
if (!ids)
@@ -3951,7 +3966,8 @@ int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr)

#else

-int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr)
+int bpf_tracing_multi_attach(struct bpf_prog *prog, const union bpf_attr *attr,
+ struct bpf_verifier_log *log)
{
return -EOPNOTSUPP;
}
--
2.55.0