On Thu, Jan 09, 2020 at 11:57:48AM +0000, Lorenz Bauer wrote: > It's possible to leak time wait and request sockets via the following > BPF pseudo code: > > sk = bpf_skc_lookup_tcp(...) > if (sk) > bpf_sk_release(sk) > > If sk->sk_state is TCP_NEW_SYN_RECV or TCP_TIME_WAIT the refcount taken > by bpf_skc_lookup_tcp is not undone by bpf_sk_release. This is because > sk_flags is re-used for other data in both kinds of sockets. The check Thanks for the report. > > !sock_flag(sk, SOCK_RCU_FREE) > > therefore returns a bogus result. > > Introduce a helper to account for this complication, and call it from > the necessary places. > > Fixes: edbf8c01de5a ("bpf: add skc_lookup_tcp helper") > Fixes: f7355a6c0497 ("bpf: Check sk_fullsock() before returning from bpf_sk_lookup()") > Signed-off-by: Lorenz Bauer <lmb@xxxxxxxxxxxxxx> > --- > net/core/filter.c | 17 +++++++++++------ > 1 file changed, 11 insertions(+), 6 deletions(-) > > diff --git a/net/core/filter.c b/net/core/filter.c > index 42fd17c48c5f..d98dc4526d82 100644 > --- a/net/core/filter.c > +++ b/net/core/filter.c > @@ -5266,6 +5266,14 @@ __bpf_skc_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, > return sk; > } > > +static void __bpf_sk_release(struct sock *sk) > +{ > + /* time wait and request socks don't have sk_flags. */ > + if (sk->sk_state == TCP_TIME_WAIT || sk->sk_state == TCP_NEW_SYN_RECV || > + !sock_flag(sk, SOCK_RCU_FREE)) Would this work too? if (!sk_fullsock(sk) || !sock_flag(sk, SOCK_RCU_FREE)) > + sock_gen_put(sk); > +} > + > static struct sock * > __bpf_sk_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, > struct net *caller_net, u32 ifindex, u8 proto, u64 netns_id, > @@ -5277,8 +5285,7 @@ __bpf_sk_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, > if (sk) { > sk = sk_to_full_sk(sk); > if (!sk_fullsock(sk)) { > - if (!sock_flag(sk, SOCK_RCU_FREE)) > - sock_gen_put(sk); > + __bpf_sk_release(sk); > return NULL; > } > } > @@ -5315,8 +5322,7 @@ bpf_sk_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, > if (sk) { > sk = sk_to_full_sk(sk); > if (!sk_fullsock(sk)) { > - if (!sock_flag(sk, SOCK_RCU_FREE)) > - sock_gen_put(sk); > + __bpf_sk_release(sk); > return NULL; > } > } > @@ -5383,8 +5389,7 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = { > > BPF_CALL_1(bpf_sk_release, struct sock *, sk) > { > - if (!sock_flag(sk, SOCK_RCU_FREE)) > - sock_gen_put(sk); > + __bpf_sk_release(sk); > return 0; > } > > -- > 2.20.1 >