> bpf: Add tracing_multi link support for bpf progs

TL;DR: The new tracing_multi fds field is not tail-checked, so older 7.2/7.3
kernels may silently treat program BTF ids as vmlinux ids, attaching to
unrelated kernel functions. Suggests a link_create flag to gate it.

> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index 6f70db7515dd..94302a3b680c 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -1927,6 +1927,8 @@ union bpf_attr {
>                               __aligned_u64   ids;
>                               __aligned_u64   cookies;
>                               __u32           cnt;
> +                             __u32           :32;
> +                             __aligned_u64   fds;
>                       } tracing_multi;
>               };
>       } link_create;

Can a kernel that already has tracing_multi but not fds reject a request
that sets fds?

The generic tail-zero check only covers bytes after
BPF_LINK_CREATE_LAST_FIELD:

    #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.path_fd

uprobe_multi.path_fd ends at byte 64 of union bpf_attr, while the new
tracing_multi.fds sits at bytes 40-47 (overlapping uprobe_multi.cookies).
So CHECK_ATTR(BPF_LINK_CREATE) in link_create() never looks at it.

The tracing_multi link shipped in 7.2 (c1d32dea5d46 "bpf: Add support for
tracing multi link"), and there bpf_tracing_multi_attach() reads only ids,
cookies and cnt:

    uids = u64_to_user_ptr(attr->link_create.tracing_multi.ids);
    cnt = attr->link_create.tracing_multi.cnt;
    ...
    if (attr->link_create.flags || attr->link_create.target_fd)
        return -EINVAL;
    ...
    err = bpf_trampoline_multi_attach(prog, ids, link);

bpf_trampoline_multi_attach() then resolves each id with
bpf_check_attach_btf_id_multi(prog->aux->attach_btf, prog, ids[i], ...),
which looks the id up in the vmlinux (or module) BTF that the fentry.multi
program was loaded against.  If the type is a FUNC with an ftrace location,
the program is attached there.

The libbpf change later in this series (85b62f93fd2d "libbpf: Add
tracing_multi link support for bpf progs") fills ids[] from
libbpf_find_prog_btf_id(funcs[i], fds[i], ...) and sets
lopts.tracing_multi.fds = fds, with no feature probe.  A new libbpf running
on a 7.2 or 7.3 kernel would therefore send target-program BTF ids, and the
older kernel would treat them as vmlinux BTF ids.  Depending on what those
ids name in vmlinux BTF, that gives either:

- a misleading -EINVAL or -ENOENT that cannot be told apart from bad input,
  or
- a successful link whose program runs on unrelated kernel functions
  instead of the requested BPF program functions.

No later commit in the series changes this.  ef1ca3de15ec only adds a flag
to the bpf_link_info output struct, and older kernels already reject a
non-zero attr->link_create.flags in bpf_tracing_multi_attach().

Could the program-target mode be keyed off a new link_create.flags bit (for
example a BPF_F_TRACING_MULTI_PROGS style flag), so that kernels without
fds support fail with -EINVAL instead of reinterpreting ids?

Related to that, the new padding is not checked for zero:

> +                             __u32           :32;

so it cannot later become an input field either.


---
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

Reply via email to