Re: [PATCH bpf-next v2 3/7] bpf: Add bpf_dynptr_from_mem, bpf_dynptr_alloc, bpf_dynptr_put

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

 



On Tue, Apr 26, 2022 at 8:53 PM Andrii Nakryiko
<andrii.nakryiko@xxxxxxxxx> wrote:
>
> On Tue, Apr 26, 2022 at 6:26 PM Alexei Starovoitov
> <alexei.starovoitov@xxxxxxxxx> wrote:
> >
> > On Tue, Apr 26, 2022 at 4:45 PM Joanne Koong <joannelkoong@xxxxxxxxx> wrote:
> > > >
> > > > I guess it's ok to treat refcnted dynptr special like above.
> > > > I wonder whether we can reuse check_reference_leak logic?
> > > I like this idea! My reason for not storing dynptr reference ids in
> > > state->refs was because it's costly (eg we realloc_array every time we
> > > acquire a reference). But thinking about this some more, I like the
> > > idea of keeping everything unified by having all reference ids reside
> > > within state->refs and checking for leaks the same way. Perhaps we can
> > > optimize acquire_reference_state() as well where we upfront allocate
> > > more space for state->refs instead of having to do a realloc_array
> > > every time.
> >
> > realloc is decently efficient underneath.
> > Probably not worth micro optimizing for it.
> > As far as ref state... Looks like dynptr patch is trying
> > hard to prevent writes into the stack area where dynptr
> > was allocated. Then cleans it up after dynptr_put.
> > For other pointers on stack we just mark the area as stack_misc
> > only when the stack slot was overwritten.
> > We don't mark the slot as 'misc' after the pointer was read from stack.
> > We can use the same approach with dynptr as long as dynptr
> > leaking is tracking through ref state
> > (instead of for(each stack slot) at the time of bpf_exit)
I think the trade-off with this is that the verifier error message
will be more ambiguous (eg if you try to call bpf_dynptr_put, the
message would be something like "arg 1 is an unacquired reference" vs.
a more clear-cut message like "direct write into dynptr is not
permitted" at the erring instruction). But I think that's fine. I will
change it to mark the slot as misc for v3.
> >
> > iirc we've debugged the case where clang reused stack area
> > with a scalar that was previously used for stack spill.
> > The dynptr on stack won't be seen as stack spill from compiler pov
> > but I worry about the case:
> > struct bpf_dynptr t;
> > bpf_dynptr_alloc(&t,..);
> > bpf_dynptr_put(&t);
> > // compiler thinks the stack area of 't' is dead and reuses
> > // it for something like scalar.
> > Even without dynptr_put above the compiler might
> > see that dynptr_alloc or another function stored
> > something into dynptr, but if nothing is using that
> > dynptr later it might consider the stack area as dead.
> > We cannot mark every dynptr variable as volatile.
> >
> > Another point to consider...
> > This patch unconditionally tells the verifier to
> > unmark_stack_slots_dynptr() after bpf_dynptr_put().
> > But that's valid only for refcnt=1 -> 0 transition.
> > I'm not sure that will be forever the case even
> > for dynptr-s on stack.
> > If we allows refcnt=2,3,... on stack then
> > the verifier won't be able to clear stack slots
> > after bpf_dynptr_put and we will face the stack reuse issue.
> > I guess the idea is that refcnt-ed dynptr will be only in a map?
> > That might be inconvenient.
> > We allow refcnt-ed kptrs to be in a map, in a register,
> > and spilled to the stack.
> > Surely, dynptr are more complex in that sense.
>
> struct dynptr on the stack isn't by itself refcounted. E.g., if we
> have dynptr pointing to PTR_TO_MAP_VALUE there is no refcounting
> involved and we don't have to do bpf_dynptr_put(). The really
> refcounted case is malloc()'ed memory pointed to by dynptr. But in
> this case refcount is stored next to the actual memory, not inside
> struct bpf_dynptr. So when we do bpf_dynptr_put() on local struct
> dynptr copy, it decrements refcount of malloc()'ed memory. If it was
> the last refcnt, then memory is freed. But we can still have other
> copies (e.g., in another on-the-stack struct bpf_dynptr copy of BPF
> program that runs on another CPU, or inside the map value) which will
> keep allocated memory.
>
> bpf_dynptr_put() are just saying "we are done with our local instance
> of struct bpf_dynptr and that slot can be reused for something else".
> So Clang deciding to reuse that stack slot for something unrelated
> after bpf_dynptr_put() should be fine.



[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