Re: [PATCH bpf-next v5 1/4] bpf: BPF token support for BPF_BTF_GET_FD_BY_ID

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Mar 12, 2025 at 11:53 AM Andrii Nakryiko
<andrii.nakryiko@xxxxxxxxx> wrote:
>
> On Tue, Mar 11, 2025 at 2:54 PM Mykyta Yatsenko
> <mykyta.yatsenko5@xxxxxxxxx> wrote:
> >
> > From: Mykyta Yatsenko <yatsenko@xxxxxxxx>
> >
> > Currently BPF_BTF_GET_FD_BY_ID requires CAP_SYS_ADMIN, which does not
> > allow running it from user namespace. This creates a problem when
> > freplace program running from user namespace needs to query target
> > program BTF.
> > This patch relaxes capable check from CAP_SYS_ADMIN to CAP_BPF and adds
> > support for BPF token that can be passed in attributes to syscall.
> >
> > Signed-off-by: Mykyta Yatsenko <yatsenko@xxxxxxxx>
> > ---
> >  include/uapi/linux/bpf.h                      |  1 +
> >  kernel/bpf/syscall.c                          | 20 +++++++++++++++++--
> >  tools/include/uapi/linux/bpf.h                |  1 +
> >  .../bpf/prog_tests/libbpf_get_fd_by_id_opts.c |  3 +--
> >  4 files changed, 21 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> > index bb37897c0393..73c23daacabf 100644
> > --- a/include/uapi/linux/bpf.h
> > +++ b/include/uapi/linux/bpf.h
> > @@ -1652,6 +1652,7 @@ union bpf_attr {
> >                 };
> >                 __u32           next_id;
> >                 __u32           open_flags;
> > +               __s32           token_fd;

So I almost applied it (I was going to add that flags check myself),
but then I realized that attrs->token_fd looks a bit too good to be
true... It's an ugly "historical" bpf_attr structure, but we have
these weird mixes of named and anon sub-structs, so some fields are
way too easily accessed even when dealing with a completely unrelated
command.

That is just to say that token_fd here is way too error-prone and
generically named, unfortunately. All other token-enabled commands
have more specific name (btf_token_fd, prog_token_fd, map_token_fd),
so I think we should continue the pattern here.

Let's call it `fd_by_id_token_fd` (unless someone has a better name)?
Let's keep a clean "token_fd" on libbpf API side (in opts), like we
did for other APIs.


> >         };
> >
> >         struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
> > diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> > index 57a438706215..188f7296cf9f 100644
> > --- a/kernel/bpf/syscall.c
> > +++ b/kernel/bpf/syscall.c
> > @@ -5137,15 +5137,31 @@ static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_
> >         return btf_new_fd(attr, uattr, uattr_size);
> >  }
> >
> > -#define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id
> > +#define BPF_BTF_GET_FD_BY_ID_LAST_FIELD token_fd
> >
> >  static int bpf_btf_get_fd_by_id(const union bpf_attr *attr)
> >  {
> > +       struct bpf_token *token = NULL;
> > +
> >         if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID))
> >                 return -EINVAL;
>
> as I mentioned in another email, we used to implicitly reject any
> open_flags set because of BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id, but
> now that we do support some flags in open_flags, we need to validate
> that there are no other flags. So you need something like:
>
> if (attr->open_flags & ~BPF_F_TOKEN_FD)
>     return -EINVAL;
>
>
> pw-bot: cr
>
> >
> > -       if (!capable(CAP_SYS_ADMIN))
> > +       if (attr->open_flags & BPF_F_TOKEN_FD) {
> > +               token = bpf_token_get_from_fd(attr->token_fd);
> > +               if (IS_ERR(token))
> > +                       return PTR_ERR(token);
> > +               if (!bpf_token_allow_cmd(token, BPF_BTF_GET_FD_BY_ID)) {
> > +                       bpf_token_put(token);
> > +                       token = NULL;
> > +               }
> > +       }
> > +
> > +       if (!bpf_token_capable(token, CAP_SYS_ADMIN)) {
> > +               bpf_token_put(token);
> >                 return -EPERM;
> > +       }
> > +
> > +       bpf_token_put(token);
> >
> >         return btf_get_fd_by_id(attr->btf_id);
> >  }
> > diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
> > index bb37897c0393..73c23daacabf 100644
> > --- a/tools/include/uapi/linux/bpf.h
> > +++ b/tools/include/uapi/linux/bpf.h
> > @@ -1652,6 +1652,7 @@ union bpf_attr {
> >                 };
> >                 __u32           next_id;
> >                 __u32           open_flags;
> > +               __s32           token_fd;
> >         };
> >
> >         struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
> > diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_get_fd_by_id_opts.c b/tools/testing/selftests/bpf/prog_tests/libbpf_get_fd_by_id_opts.c
> > index a3f238f51d05..976ff38a6d43 100644
> > --- a/tools/testing/selftests/bpf/prog_tests/libbpf_get_fd_by_id_opts.c
> > +++ b/tools/testing/selftests/bpf/prog_tests/libbpf_get_fd_by_id_opts.c
> > @@ -75,9 +75,8 @@ void test_libbpf_get_fd_by_id_opts(void)
> >         if (!ASSERT_EQ(ret, -EINVAL, "bpf_link_get_fd_by_id_opts"))
> >                 goto close_prog;
> >
> > -       /* BTF get fd with opts set should not work (no kernel support). */
> >         ret = bpf_btf_get_fd_by_id_opts(0, &fd_opts_rdonly);
> > -       ASSERT_EQ(ret, -EINVAL, "bpf_btf_get_fd_by_id_opts");
> > +       ASSERT_EQ(ret, -ENOENT, "bpf_btf_get_fd_by_id_opts");
> >
> >  close_prog:
> >         if (fd >= 0)
> > --
> > 2.48.1
> >





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux