Re: Dynptrs and Strings

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

 



On Thu, Apr 6, 2023 at 2:05 PM Daniel Rosenberg <drosen@xxxxxxxxxx> wrote:
>
> On Tue, Apr 4, 2023 at 7:57 PM Alexei Starovoitov
> <alexei.starovoitov@xxxxxxxxx> wrote:
> >
> > so the idea that bpf prog will see opaque ctx == name and a set
> > of kfuncs will extract different things from ctx into local dynptrs ?
> >
> > Have you considered passing dynptr-s directly into bpf progs
> > as arguments of struct_ops callbacks?
> > That would be faster or slower performance wise?
> >
>
> The kfunc records data that fuse then uses to clean up afterwards.
> That opaque struct seemed like the best place for it to live.
> Alternatively, I could provide dynpointers up front, but those are
> read only or read/write up front based on which operation they're
> dealing with, and may or may not be promotable to read/write, which
> involves creating a new dynpointer anyways. If I took that approach,
> I'd likely present a read-only dynpointer, and wrap it in a larger
> struct that contains the needed meta information. I'd definitely need
> to ensure that only fuse-bpf can call those kfuncs in that case.
>
> >
> > yep. Don't be shy from improving the verifier to your needs.
> >
>
> Uploaded a couple patches yesterday :)
> A patch to remove the buffer requirement for the slice functions, and
> another to accept dynpointer tagged mem as mem in helper functions.
>
>
> On Wed, Apr 5, 2023 at 11:49 AM Andrii Nakryiko
> <andrii.nakryiko@xxxxxxxxx> wrote:
> >
> > note that even if bpf_dynptr_slice() accepts a buffer, it won't ever
> > touch it for LOCAL dynptrs, as the data is already linear in memory.
> > This buffer is filled out only for skb/xdp **and** only if requested
> > memory range can't be accessed as sequential memory. So you won't be
> > copying data.
> >
>
> I added an '__opt' tag annotation for this, so I can avoid needing to
> supply the buffer in those cases.
>
> > For bpf_dynptr_read(), yep, it will copy data. Regardless if you are
> > going to use it or not, we should relax the condition that final
> > buffer should be smaller or equal to dynptr actual size, it should be
> > bigger and we should just write to first N bytes of it.
> >
>
> Should dynptr_read return the length read? Otherwise you need to get
> the dynpointer length and adjust for all the offsets to figure out how
> much was probably read. But returning the length read would break
> existing programs.

You are right, that's a pretty big change in semantics. I take it
back, let's keep bpf_dynptr_read() as is. As it is currently, it
matches bpf_probe_read_{kernel,user} behavior and return semantics, so
it's good to keep all that consistent.

But I think that's ok, because your use case is solvable once we land
Joanne's bpf_dynptr_get_size() helper from her latest dynptr patch
set. Just to test, here's what I tried, and it works, so I think it
will also for for you with bpf_dynptr_get_size() to get a minimum of
your fixed buffer size and actual dynptr content size:

$ git diff
diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c
b/tools/testing/selftests/bpf/progs/dynptr_success.c
index b2fa6c47ecc0..4e0172156cc9 100644
--- a/tools/testing/selftests/bpf/progs/dynptr_success.c
+++ b/tools/testing/selftests/bpf/progs/dynptr_success.c
@@ -37,7 +37,7 @@ int test_read_write(void *ctx)
        char write_data[64] = "hello there, world!!";
        char read_data[64] = {};
        struct bpf_dynptr ptr;
-       int i;
+       int n, i;

        if (bpf_get_current_pid_tgid() >> 32 != pid)
                return 0;
@@ -46,9 +46,15 @@ int test_read_write(void *ctx)

        /* Write data into the dynptr */
        err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
+       if (err)
+               goto cleanup;
+
+       n = bpf_get_prandom_u32();
+       if (n >= sizeof(read_data))
+               n = sizeof(read_data);

        /* Read the data that was written into the dynptr */
-       err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
+       err = bpf_dynptr_read(read_data, n, &ptr, 0, 0);

        /* Ensure the data we read matches the data we wrote */
        for (i = 0; i < sizeof(read_data); i++) {
@@ -58,6 +64,7 @@ int test_read_write(void *ctx)
                }
        }

+cleanup:
        bpf_ringbuf_discard_dynptr(&ptr, 0);
        return 0;
 }


> I also noticed that the various dynpointer offset/length checks don't
> seem to account for both the dynpointer offset and the read/write etc
> offset. All of the bounds checking there could use another pass.

If there are bugs, then yeah, let's definitely fix all of them. I
think offset problems are not noticeable right now, because we haven't
yet added the bpf_dynptr_advance() API, so currently offset is always
zero. So nothing should be broken right now, but please send fixes if
you've spotted issues.

>
> > >
> > > > At the moment I'm using bpf_dynptr_slice and declaring an empty and
> > > > unused buffer. I'm then hitting an issue with bpf_strncmp not
> > > > expecting mem that's tagged as being associated with a dynptr. I'm
> > > > currently working around that by adjusting check_reg_type to be less
> > > > picky, stripping away DYNPTR_TYPE_LOCAL if we're looking at an
> > > > ARG_PTR_TO_MEM. I suspect that would also be the case for other dynptr
> > > > types.
> >
> > So this seems unintended (or there is some unintentional misuse of
> > memory vs dynptr itself), we might be missing something in how we
> > handle arguments right now. It would be nice if you can send a patch
> > with a small selftest demonstrating this (and maybe a fix :) ).
> >
>
> Done :) Though not sure if the selftests I added are sufficient.
> https://lore.kernel.org/bpf/20230406004018.1439952-1-drosen@xxxxxxxxxx/

Yep, thanks! Already reviewed, let's iterate on respective patch set.

>
> >
> > We had previous discussions about whether to treat read-only as a
> > runtime-only or statically known attribute. There were pros and cons,
> > I don't remember what we ended up deciding. We do some custom handling
> > for some SKB programs, but it would be good to handle this
> > universally, yep.
> >
>
> I think it's currently not tracked, although the read only tag was
> being used for the dynptr itself. Almost tricked me there. In that
> case it'd probably be easier to add dynptr_data_ro than to add that
> information everywhere.
>

Not sure how hard it is to add static tracking of r/o vs r/w, but a
separate helper for read-only data probably makes sense anyways.

> >
> > +1. I feel like we are just missing a few helpers to help extract
> > and/or compare variable-sized strings (like bpf_dynptr_strncmp
> > mentioned earlier) for all this to work well. But a concrete use case
> > would allow us to design a coherent set of APIs to help with this.
>
> Should be able to get that patch set together soon. I'm reworking the
> test code with the verifier changes I mentioned above, and then will
> be doing a round of cleanup to make it a bit more possible to see
> what's actually in use now.

Nice.




[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