All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: Jiri Olsa <jolsa@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Networking <netdev@vger.kernel.org>, bpf <bpf@vger.kernel.org>,
	Yonghong Song <yhs@fb.com>, Martin KaFai Lau <kafai@fb.com>,
	David Miller <davem@redhat.com>,
	John Fastabend <john.fastabend@gmail.com>,
	Jesper Dangaard Brouer <hawk@kernel.org>,
	Wenbo Zhang <ethercflow@gmail.com>,
	KP Singh <kpsingh@chromium.org>, Andrii Nakryiko <andriin@fb.com>,
	Brendan Gregg <bgregg@netflix.com>,
	Florent Revest <revest@chromium.org>,
	Al Viro <viro@zeniv.linux.org.uk>
Subject: Re: [PATCH 4/9] bpf: Allow nested BTF object to be refferenced by BTF object + offset
Date: Thu, 14 May 2020 15:32:29 -0700	[thread overview]
Message-ID: <CAEf4BzZXyCjjaofaOROTKCRr5fqHkdZkBHZmfiqqQiKTyOYv1Q@mail.gmail.com> (raw)
In-Reply-To: <20200506132946.2164578-5-jolsa@kernel.org>

On Wed, May 6, 2020 at 6:31 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Adding btf_struct_address function that takes 2 BTF objects
> and offset as arguments and checks wether object A is nested
> in object B on given offset.
>
> This function is be used when checking the helper function
> PTR_TO_BTF_ID arguments. If the argument has an offset value,
> the btf_struct_address will check if the final address is
> the expected BTF ID.
>
> This way we can access nested BTF objects under PTR_TO_BTF_ID
> pointer type and pass them to helpers, while they still point
> to valid kernel BTF objects.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  include/linux/bpf.h   |  3 ++
>  kernel/bpf/btf.c      | 69 +++++++++++++++++++++++++++++++++++++++++++
>  kernel/bpf/verifier.c | 32 +++++++++++++-------
>  3 files changed, 94 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 1262ec460ab3..bc589cdd8c34 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -1213,6 +1213,9 @@ int btf_struct_access(struct bpf_verifier_log *log,
>                       const struct btf_type *t, int off, int size,
>                       enum bpf_access_type atype,
>                       u32 *next_btf_id);
> +int btf_struct_address(struct bpf_verifier_log *log,
> +                    const struct btf_type *t,
> +                    u32 off, u32 exp_id);
>  int btf_resolve_helper_id(struct bpf_verifier_log *log,
>                           const struct bpf_func_proto *fn, int);
>
> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index a2cfba89a8e1..07f22469acab 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -4004,6 +4004,75 @@ int btf_struct_access(struct bpf_verifier_log *log,
>         return -EINVAL;
>  }
>
> +int btf_struct_address(struct bpf_verifier_log *log,
> +                      const struct btf_type *t,
> +                      u32 off, u32 exp_id)

The logic in this function is quite tricky and overlaps heavily with
btf_struct_access. You are already missing flexible array support that
Yonghong added recently. Let's see if it's possible to extract all
this "find field in a struct by offset" logic into reusable function?

> +{
> +       u32 i, moff, mtrue_end, msize = 0;
> +       const struct btf_member *member;
> +       const struct btf_type *mtype;
> +       const char *tname, *mname;
> +
> +again:
> +       tname = __btf_name_by_offset(btf_vmlinux, t->name_off);
> +       if (!btf_type_is_struct(t)) {
> +               bpf_log(log, "Type '%s' is not a struct\n", tname);
> +               return -EINVAL;
> +       }
> +
> +       if (off > t->size) {

>=, actually?

> +               bpf_log(log, "address beyond struct %s at off %u size %u\n",
> +                       tname, off, t->size);
> +               return -EACCES;
> +       }
> +

[...]

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 70ad009577f8..b988df5ada20 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -3665,6 +3665,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
>  {
>         struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
>         enum bpf_reg_type expected_type, type = reg->type;
> +       const struct btf_type *btf_type;
>         int err = 0;
>
>         if (arg_type == ARG_DONTCARE)
> @@ -3743,17 +3744,28 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno,
>                 expected_type = PTR_TO_BTF_ID;
>                 if (type != expected_type)
>                         goto err_type;
> -               if (reg->btf_id != meta->btf_id) {
> -                       verbose(env, "Helper has type %s got %s in R%d\n",
> -                               kernel_type_name(meta->btf_id),
> -                               kernel_type_name(reg->btf_id), regno);
> +               if (reg->off) {

well, off==0 can still point to (arbitrarily) nested structs that are
first member of outer struct... So I guess it would be better to
search for inner struct if btf_id is unexpected regardless of off
value?

> +                       btf_type = btf_type_by_id(btf_vmlinux, reg->btf_id);
> +                       if (btf_struct_address(&env->log, btf_type, reg->off, meta->btf_id)) {
> +                               verbose(env, "Helper has type %s got %s in R%d, off %d\n",
> +                                       kernel_type_name(meta->btf_id),
> +                                       kernel_type_name(reg->btf_id), regno, reg->off);
>
> -                       return -EACCES;
> -               }
> -               if (!tnum_is_const(reg->var_off) || reg->var_off.value || reg->off) {
> -                       verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
> -                               regno);
> -                       return -EACCES;
> +                               return -EACCES;
> +                       }
> +               } else {
> +                       if (reg->btf_id != meta->btf_id) {
> +                               verbose(env, "Helper has type %s got %s in R%d\n",
> +                                       kernel_type_name(meta->btf_id),
> +                                       kernel_type_name(reg->btf_id), regno);
> +
> +                               return -EACCES;
> +                       }
> +                       if (!tnum_is_const(reg->var_off) || reg->var_off.value) {
> +                               verbose(env, "R%d is a pointer to in-kernel struct with non-zero offset\n",
> +                                       regno);
> +                               return -EACCES;
> +                       }
>                 }
>         } else if (arg_type == ARG_PTR_TO_SPIN_LOCK) {
>                 if (meta->func_id == BPF_FUNC_spin_lock) {
> --
> 2.25.4
>

  reply	other threads:[~2020-05-14 22:32 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-06 13:29 [RFCv2 0/9] bpf: Add d_path helper Jiri Olsa
2020-05-06 13:29 ` [PATCH 1/9] " Jiri Olsa
2020-05-14 22:06   ` Andrii Nakryiko
2020-05-15 14:59     ` Jiri Olsa
2020-05-06 13:29 ` [PATCH 2/9] bpf: Add d_path whitelist Jiri Olsa
2020-05-06 13:29 ` [PATCH 3/9] bpf: Add bpfwl tool to construct bpf whitelists Jiri Olsa
2020-05-14 22:20   ` Andrii Nakryiko
2020-05-15 14:58     ` Jiri Olsa
2020-05-06 13:29 ` [PATCH 4/9] bpf: Allow nested BTF object to be refferenced by BTF object + offset Jiri Olsa
2020-05-14 22:32   ` Andrii Nakryiko [this message]
2020-05-06 13:29 ` [PATCH 5/9] bpf: Add support to check on BTF id whitelist for d_path helper Jiri Olsa
2020-05-06 13:29 ` [PATCH 6/9] bpf: Compile bpfwl tool at kernel compilation start Jiri Olsa
2020-05-14 22:38   ` Andrii Nakryiko
2020-05-15 14:57     ` Jiri Olsa
2020-05-06 13:29 ` [PATCH 7/9] bpf: Compile the BTF id whitelist data in vmlinux Jiri Olsa
2020-05-13 18:29   ` Alexei Starovoitov
2020-05-14  8:05     ` Jiri Olsa
2020-05-14 22:46       ` Andrii Nakryiko
2020-05-15 14:57         ` Jiri Olsa
2020-05-28 17:23         ` Jiri Olsa
2020-05-29 20:48           ` Andrii Nakryiko
2020-05-31 15:10             ` Jiri Olsa
2020-06-01 19:06               ` Andrii Nakryiko
2020-06-02  8:16                 ` Jiri Olsa
2020-05-06 13:29 ` [PATCH 8/9] selftests/bpf: Add test for d_path helper Jiri Olsa
2020-05-14 22:48   ` Andrii Nakryiko
2020-05-15 14:57     ` Jiri Olsa
2020-05-06 13:29 ` [PATCH 9/9] selftests/bpf: Add verifier " Jiri Olsa

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAEf4BzZXyCjjaofaOROTKCRr5fqHkdZkBHZmfiqqQiKTyOYv1Q@mail.gmail.com \
    --to=andrii.nakryiko@gmail.com \
    --cc=andriin@fb.com \
    --cc=ast@kernel.org \
    --cc=bgregg@netflix.com \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@redhat.com \
    --cc=ethercflow@gmail.com \
    --cc=hawk@kernel.org \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kafai@fb.com \
    --cc=kpsingh@chromium.org \
    --cc=netdev@vger.kernel.org \
    --cc=revest@chromium.org \
    --cc=viro@zeniv.linux.org.uk \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.