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 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).

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.



[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