> bpf: Add tracing_multi link info support for bpf progs
TL;DR: The new -EINVAL in tracing_multi fill_link_info may break existing
userspace, e.g. bpftool link show, when querying links with bpf prog targets
without func_btf_ids; it may stop listing later links.
> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
> index 8b1a52350cfd..39c911917ae2 100644
> --- a/kernel/trace/bpf_trace.c
> +++ b/kernel/trace/bpf_trace.c
[ ... ]
> @@ -3725,9 +3726,13 @@ static int bpf_tracing_multi_link_fill_link_info(const
> struct bpf_link *link,
> info->tracing_multi.attach_type = tr_link->link.attach_type;
> info->tracing_multi.count = tr_link->nodes_cnt;
> info->tracing_multi.btf_obj_id =
> btf_obj_id(tr_link->link.prog->aux->attach_btf);
> + has_progs = !!tr_link->tgt_progs;
> + info->tracing_multi.flags = has_progs ? BPF_F_TRACING_MULTI_TGT_PROGS :
> 0;
>
> - if (!uids && !ucookies && !uaddrs)
> + if (!uids && !ucookies && !uaddrs && !fids)
> return 0;
> + if (has_progs != !!fids)
> + return -EINVAL;
>
> if (ucount < tr_link->nodes_cnt)
> err = -ENOSPC;
Does this new -EINVAL break existing userspace that queries a tracing_multi
link with bpf prog targets?
A caller written before this change passes ids, addrs and cookies, but has no
way to supply func_btf_ids. For example, the bpftool already in the tree does
a two-step query in do_show_link():
if (info.type == BPF_LINK_TYPE_TRACING_MULTI && !info.tracing_multi.ids) {
...
info.tracing_multi.ids = ptr_to_u64(ids);
info.tracing_multi.addrs = ptr_to_u64(addrs);
info.tracing_multi.cookies = ptr_to_u64(cookies);
goto again;
On the second call, for a link with prog targets, has_progs is true and fids
is NULL, so this check returns -EINVAL:
if (has_progs != !!fids)
return -EINVAL;
bpf_link_get_info_by_fd() returns before copy_to_user() when fill_link_info()
fails, so the caller also never sees the new flags value that would explain the
failure.
do_show_link() then prints "can't get link info: Invalid argument", and
do_show() does:
err = do_show_link(fd);
if (err)
break;
so "bpftool link show" stops at the first such link and does not list the
links after it. Any other tool that only wants addrs or cookies for this link
type would hit the same error.
The reverse direction also fails: a link without prog targets and a non-NULL
func_btf_ids now returns -EINVAL for a request that would have succeeded
before.
These queries worked before this commit. The check looks like it is needed
only because ids now changes meaning, and carries prog IDs when has_progs is
set:
put_user(has_progs ? prog_id : btf_id, uids + i)
Would it work to keep ids as BTF IDs and return the prog IDs in a separate new
array, or to fill only the arrays the caller asked for, the way ids, addrs and
cookies are already optional one by one?
The commit message does not mention this behavior, and no later patch in the
series changes it.
---
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/38273555988