bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Cc: Joanne Koong <joannelkoong@gmail.com>,
	bpf@vger.kernel.org, daniel@iogearbox.net, martin.lau@kernel.org,
	andrii@kernel.org, ast@kernel.org, Kernel-team@fb.com
Subject: Re: [PATCH bpf-next v1 7/8] bpf: Add bpf_dynptr_iterator
Date: Wed, 28 Sep 2022 15:47:43 -0700	[thread overview]
Message-ID: <CAEf4BzawD+_buWqp_U3cu71QZH_OVTseuSUyEcva9qCd1=GQ-A@mail.gmail.com> (raw)
In-Reply-To: <CAP01T76YjXcxYsYue5Sxyp+Ppa3XR3nQq2nz8gV9VnWcD6Tdgg@mail.gmail.com>

On Sun, Sep 18, 2022 at 5:08 PM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> On Thu, 8 Sept 2022 at 02:16, Joanne Koong <joannelkoong@gmail.com> wrote:
> >
> > Add a new helper function, bpf_dynptr_iterator:
> >
> >   long bpf_dynptr_iterator(struct bpf_dynptr *ptr, void *callback_fn,
> >                            void *callback_ctx, u64 flags)
> >
> > where callback_fn is defined as:
> >
> >   long (*callback_fn)(struct bpf_dynptr *ptr, void *ctx)
> >
> > and callback_fn returns the number of bytes to advance the
> > dynptr by (or an error code in the case of error). The iteration
> > will stop if the callback_fn returns 0 or an error or tries to
> > advance by more bytes than available.
> >
> > Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
> > ---
>
> This is buggy as is.
>
> A user can just reinitialize the dynptr from inside the callback, and
> then you will never stop advancing it inside your helper, therefore an
> infinite loop can be constructed. The stack frame of the caller is
> accessible using callback_ctx.
>
> For example (modifying your selftest)
>
> diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c
> b/tools/testing/selftests/bpf/progs/dynptr_success.c
> index 22164ad6df9d..a9e78316c508 100644
> --- a/tools/testing/selftests/bpf/progs/dynptr_success.c
> +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c
> @@ -540,6 +540,19 @@ struct iter_ctx {
>
>  static int iter_callback(struct bpf_dynptr *ptr, struct iter_ctx *ctx)
>  {
> +       struct map_value *map_val;
> +       int key = 0;
> +
> +       map_val = bpf_map_lookup_elem(&array_map2, &key);
> +       if (!map_val) {
> +               return 0;
> +       }
> +
> +       *(void **)ptr = 0;
> +       *((void **)ptr + 1) = 0;
> +       bpf_dynptr_from_mem(map_val, 2, 0, ptr);
> +       return 1;
> +
>         if (ctx->trigger_err_erange)
>                 return bpf_dynptr_get_size(ptr) + 1;
>
> ... leads to a lockup.
>
> It doesn't have to be ringbuf_reserver_dynptr, it can just be
> dynptr_from_mem, which also gets around reference state restrictions
> inside callbacks.
>
> You cannot prevent overwriting dynptr stack slots in general. Some of
> them don't have to be released. It would be prohibitive for stack
> reuse.
>
> So it seems like you need to temporarily mark both the slots as
> immutable for the caller stack state during exploration of the
> callback.
> Setting some flag in r1 for callback is not enough (as it can reload
> PTR_TO_STACK of caller stack frame pointing at dynptr from
> callback_ctx). It needs to be set in spilled_ptr.

This sounds overcomplicated. We need a local copy of dynptr for the
duration of iteration and work with it. Basically internal
bpf_dynptr_clone(). See my other reply in this thread.

>
> Then certain operations modifying the view of the dynptr do not accept
> dynptr with that type flag set (e.g. trim, advance, init functions).
> While for others which only operate on the underlying view, you fold
> the flag (e.g. read/write/dynptr_data).
>
> It is the difference between struct bpf_dynptr *, vs const struct
> bpf_dynptr *, we need to give the callback access to the latter.
> I.e. it should still allow accessing the dynptr's view, but not modifying it.
>
> And at the risk of sounding like a broken record (and same suggestion
> as Martin in skb/xdp v6 set), the view's mutability should ideally
> also be part of the verifier's state. That doesn't preclude runtime
> tracking later, but there seems to be no strong motivation for that
> right now.

The unexpected NULL for bpf_dynptr_data() vs bpf_dynptr_data_rdonly()
argument from Martin is pretty convincing, I agree. So I guess I don't
mind tracking it statically at this point.

>
> >  include/uapi/linux/bpf.h       | 20 ++++++++++++++
> >  kernel/bpf/helpers.c           | 48 +++++++++++++++++++++++++++++++---
> >  kernel/bpf/verifier.c          | 27 +++++++++++++++++++
> >  tools/include/uapi/linux/bpf.h | 20 ++++++++++++++
> >  4 files changed, 111 insertions(+), 4 deletions(-)
> >

please trim irrelevant parts

[...]

  reply	other threads:[~2022-09-28 22:48 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-08  0:02 [PATCH bpf-next v1 0/8] Dynptr convenience helpers Joanne Koong
2022-09-08  0:02 ` [PATCH bpf-next v1 1/8] bpf: Add bpf_dynptr_data_rdonly Joanne Koong
2022-09-09 15:29   ` Song Liu
2022-09-09 15:32     ` Alexei Starovoitov
2022-09-09 15:59       ` Song Liu
2022-09-09 15:51   ` Shmulik Ladkani
2022-09-08  0:02 ` [PATCH bpf-next v1 2/8] bpf: Add bpf_dynptr_trim and bpf_dynptr_advance Joanne Koong
2022-09-09 15:32   ` Song Liu
2022-09-09 16:16   ` Shmulik Ladkani
2022-09-28 22:14   ` Andrii Nakryiko
2022-09-08  0:02 ` [PATCH bpf-next v1 3/8] bpf: Add bpf_dynptr_is_null and bpf_dynptr_is_rdonly Joanne Koong
2022-09-09 15:46   ` Song Liu
2022-09-09 21:28     ` Joanne Koong
2022-09-09 23:17       ` Song Liu
2022-09-08  0:02 ` [PATCH bpf-next v1 4/8] bpf: Add bpf_dynptr_get_size and bpf_dynptr_get_offset Joanne Koong
2022-09-09 16:52   ` Shmulik Ladkani
2022-09-09 20:37     ` Joanne Koong
2022-09-08  0:02 ` [PATCH bpf-next v1 5/8] bpf: Add bpf_dynptr_clone Joanne Koong
2022-09-09 16:41   ` Shmulik Ladkani
2022-09-09 22:18     ` Joanne Koong
2022-09-10  5:31       ` Shmulik Ladkani
2022-09-28 22:34         ` Andrii Nakryiko
2022-09-28 22:29   ` Andrii Nakryiko
2022-09-08  0:02 ` [PATCH bpf-next v1 6/8] bpf: Add verifier support for custom callback return range Joanne Koong
2022-09-08  0:02 ` [PATCH bpf-next v1 7/8] bpf: Add bpf_dynptr_iterator Joanne Koong
2022-09-19  0:07   ` Kumar Kartikeya Dwivedi
2022-09-28 22:47     ` Andrii Nakryiko [this message]
2022-09-28 22:41   ` Andrii Nakryiko
2022-09-29  0:31     ` Kumar Kartikeya Dwivedi
2022-09-29  0:43       ` Andrii Nakryiko
2022-10-02 16:45         ` Kumar Kartikeya Dwivedi
2022-10-03 18:39           ` Andrii Nakryiko
2022-09-08  0:02 ` [PATCH bpf-next v1 8/8] selftests/bpf: Tests for dynptr convenience helpers Joanne Koong

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='CAEf4BzawD+_buWqp_U3cu71QZH_OVTseuSUyEcva9qCd1=GQ-A@mail.gmail.com' \
    --to=andrii.nakryiko@gmail.com \
    --cc=Kernel-team@fb.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=joannelkoong@gmail.com \
    --cc=martin.lau@kernel.org \
    --cc=memxor@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).