Re: [PATCH bpf-next v2] bpf: bpf_{g,s}etsockopt for struct bpf_sock

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

 



On Wed, Apr 29, 2020 at 04:33:12PM -0700, sdf@xxxxxxxxxx wrote:
> On 04/30, Daniel Borkmann wrote:
> > On 4/29/20 7:05 PM, Stanislav Fomichev wrote:
> > > Currently, bpf_getsocktop and bpf_setsockopt helpers operate on the
> > > 'struct bpf_sock_ops' context in BPF_PROG_TYPE_SOCK_OPS program.
> > > Let's generalize them and make the first argument be 'struct bpf_sock'.
> > > That way, in the future, we can allow those helpers in more places.
> > >
> > > BPF_PROG_TYPE_SOCK_OPS still has the existing helpers that operate
> > > on 'struct bpf_sock_ops', but we add new bpf_{g,s}etsockopt that work
> > > on 'struct bpf_sock'. [Alternatively, for BPF_PROG_TYPE_SOCK_OPS,
> > > we can enable them both and teach verifier to pick the right one
> > > based on the context (bpf_sock_ops vs bpf_sock).]
> > >
> > > As an example, let's allow those 'struct bpf_sock' based helpers to
> > > be called from the BPF_CGROUP_INET{4,6}_CONNECT hooks. That way
> > > we can override CC before the connection is made.
> > >
> > > v2:
> > > * s/BPF_PROG_TYPE_CGROUP_SOCKOPT/BPF_PROG_TYPE_SOCK_OPS/
> > >
> > > Acked-by: John Fastabend <john.fastabend@xxxxxxxxx>
> > > Acked-by: Martin KaFai Lau <kafai@xxxxxx>
> > > Signed-off-by: Stanislav Fomichev <sdf@xxxxxxxxxx>
> > [...]
> > > +BPF_CALL_5(bpf_setsockopt, struct sock *, sk,
> > > +	   int, level, int, optname, char *, optval, int, optlen)
> > > +{
> > > +	u32 flags = 0;
> > > +	return _bpf_setsockopt(sk, level, optname, optval, optlen, flags);
> > > +}
> > > +
> > > +static const struct bpf_func_proto bpf_setsockopt_proto = {
> > > +	.func		= bpf_setsockopt,
> > > +	.gpl_only	= false,
> > > +	.ret_type	= RET_INTEGER,
> > > +	.arg1_type	= ARG_PTR_TO_SOCKET,
> > > +	.arg2_type	= ARG_ANYTHING,
> > > +	.arg3_type	= ARG_ANYTHING,
> > > +	.arg4_type	= ARG_PTR_TO_MEM,
> > > +	.arg5_type	= ARG_CONST_SIZE,
> > > +};
> > > +
> > > +BPF_CALL_5(bpf_getsockopt, struct sock *, sk,
> > > +	   int, level, int, optname, char *, optval, int, optlen)
> > > +{
> > > +	return _bpf_getsockopt(sk, level, optname, optval, optlen);
> > > +}
> > > +
> > >   static const struct bpf_func_proto bpf_getsockopt_proto = {
> > >   	.func		= bpf_getsockopt,
> > >   	.gpl_only	= false,
> > >   	.ret_type	= RET_INTEGER,
> > > +	.arg1_type	= ARG_PTR_TO_SOCKET,
> > > +	.arg2_type	= ARG_ANYTHING,
> > > +	.arg3_type	= ARG_ANYTHING,
> > > +	.arg4_type	= ARG_PTR_TO_UNINIT_MEM,
> > > +	.arg5_type	= ARG_CONST_SIZE,
> > > +};
> > > +
> > [...]
> > > @@ -6043,6 +6098,22 @@ sock_addr_func_proto(enum bpf_func_id func_id,
> > const struct bpf_prog *prog)
> > >   		return &bpf_sk_storage_get_proto;
> > >   	case BPF_FUNC_sk_storage_delete:
> > >   		return &bpf_sk_storage_delete_proto;
> > > +	case BPF_FUNC_setsockopt:
> > > +		switch (prog->expected_attach_type) {
> > > +		case BPF_CGROUP_INET4_CONNECT:
> > > +		case BPF_CGROUP_INET6_CONNECT:
> > > +			return &bpf_setsockopt_proto;
> 
> > Hm, I'm not sure this is safe. In the sock_addr_func_proto() we also have
> > other helpers callable from connect hooks like sk_lookup_{tcp,udp} which
> > return a PTR_TO_SOCKET_OR_NULL, and now we can pass those sockets also
> > into
> > bpf_{get,set}sockopt() helper after lookup to change various sk related
> > stuff
> > but w/o being under lock. Doesn't the sock_owned_by_me() yell here at
> > minimum
> > (I'd expect so)?
> Ugh, good point, I missed the fact that sk_lookup_{tcp,udp} are there
> for sock_addr :-( I can try to do a simple test case to verify
> that sock_owned_by_me triggers, but I'm pretty certain it should
> (I've been calling bpf_{s,g}etsockopt for context socket so it's quiet).
> 
> I don't think there is any helper similar to sock_owned_by_me() that
> I can call to verify that the socket is held by current thread
> (without the lockdep splat) and bail out?
> 
> In this case, is something like adding new PTR_TO_LOCKED_SOCKET_OR_NULL
> is the way to go? Any other ideas?

Looks like networking will benefit from sleepable progs too.
We could have just did lock_sock() inside bpf_setsockopt
before setting cong control.
In the mean time how about introducing try_lock_sock() 
that will bail out if it cannot grab the lock?
For most practical cases that would work and eventually we
can convert it to full lock_sock ?



[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