Re: [PATCH RFC bpf-next v1 9/9] selftests/bpf: Add tests for BPF exceptions

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

 



On Fri, Apr 07, 2023 at 02:42:14AM +0200, Kumar Kartikeya Dwivedi wrote:
> On Thu, Apr 06, 2023 at 04:38:09AM CEST, Alexei Starovoitov wrote:
> > On Wed, Apr 05, 2023 at 02:42:39AM +0200, Kumar Kartikeya Dwivedi wrote:
> > > +static __noinline int throwing_subprog(struct __sk_buff *ctx)
> > > +{
> > > +	if (ctx)
> > > +		bpf_throw();
> > > +	return 0;
> > > +}
> > > +
> > > +__noinline int global_subprog(struct __sk_buff *ctx)
> > > +{
> > > +	return subprog(ctx) + 1;
> > > +}
> > > +
> > > +__noinline int throwing_global_subprog(struct __sk_buff *ctx)
> > > +{
> > > +	if (ctx)
> > > +		bpf_throw();
> > > +	return 0;
> > > +}
> > > +
> > > +static __noinline int exception_cb(void)
> > > +{
> > > +	return 16;
> > > +}
> > > +
> > > +SEC("tc")
> > > +int exception_throw_subprog(struct __sk_buff *ctx)
> > > +{
> > > +	volatile int i;
> > > +
> > > +	exception_cb();
> > > +	bpf_set_exception_callback(exception_cb);
> > > +	i = subprog(ctx);
> > > +	i += global_subprog(ctx) - 1;
> > > +	if (!i)
> > > +		return throwing_global_subprog(ctx);
> > > +	else
> > > +		return throwing_subprog(ctx);
> > > +	bpf_throw();
> > > +	return 0;
> > > +}
> > > +
> > > +__noinline int throwing_gfunc(volatile int i)
> > > +{
> > > +	bpf_assert_eq(i, 0);
> > > +	return 1;
> > > +}
> > > +
> > > +__noinline static int throwing_func(volatile int i)
> > > +{
> > > +	bpf_assert_lt(i, 1);
> > > +	return 1;
> > > +}
> >
> > exception_cb() has no way of knowning which assert statement threw the exception.
> > How about extending a macro:
> > bpf_assert_eq(i, 0, MY_INT_ERR);
> > or
> > bpf_assert_eq(i, 0) {bpf_throw(MY_INT_ERR);}
> >
> > bpf_throw can store it in prog->aux->exception pass the address to cb.
> >
> 
> I agree and will add passing of a value that gets passed to the callback
> (probably just set it in the exception state), but I don't think prog->aux will
> work, see previous mails.
> 
> > Also I think we shouldn't complicate the verifier with auto release of resources.
> > If the user really wants to assert when spin_lock is held it should be user's
> > job to specify what resources should be released.
> > Can we make it look like:
> >
> > bpf_spin_lock(&lock);
> > bpf_assert_eq(i, 0) {
> >   bpf_spin_unlock(&lock);
> >   bpf_throw(MY_INT_ERR);
> > }
> 
> Do you mean just locks or all resources? Then it kind of undermines the point of
> having something like bpf_throw IMO. Since it's easy to insert code from the
> point of throw but it's not possible to do the same in callers (unless we add a
> way to 'catch' throws), so it only works for some particular cases where callers
> don't hold references (or in the main subprog).

That's a good point. This approach will force caller of functions that can
throw not hold any referenced objects (spin_locks, sk_lookup, obj_new, etc)
That indeed might be too restrictive.
It would be great if we could come up with a way for bpf prog to release resources
explicitly though. I'm not a fan of magic release of spin locks.

> There are also other ways to go about this whole thing, like having the compiler
> emit calls to instrinsics which the BPF runtime provides (or have the call
> configurable through compiler switches), and it already emits the landing pad
> code to release stuff and we simply receive the table of pads indexed by each
> throwing instruction, perform necessary checks to ensure everything is actually
> released correctly when control flow goes through them (e.g. when exploring
> multiple paths through the same instruction), and unwind frame by frame. That
> reduces the burden on both the verifier and user, but then it would be probably
> need to be BPF C++, or have to be a new language extension for BPF C. E.g. there
> was something about defer, panic, recover etc. in wg14
> https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2542.pdf . Having the compiler
> do it is also probably easier if we want 'catch' style handlers.

Interesting idea. __attribute__((cleanup(..))) may be handy, but that's a ton of work.
I'm in a camp of developers who enforce -fno-exceptions in C++ projects.
bpf_assert is not analogous to C++ exceptions. It shouldn't be seen a mechanism
to simplify control flow and error handling.



[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