Skip to content

Commit

Permalink
net: bpf: Don't leak time wait and request sockets
Browse files Browse the repository at this point in the history
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

  !sock_flag(sk, SOCK_RCU_FREE)

therefore returns a bogus result. Check that sk_flags is valid by calling
sk_fullsock. Skip checking SOCK_RCU_FREE if we already know that sk is
not a full socket.

Fixes: edbf8c0 ("bpf: add skc_lookup_tcp helper")
Fixes: f7355a6 ("bpf: Check sk_fullsock() before returning from bpf_sk_lookup()")
Signed-off-by: Lorenz Bauer <lmb@cloudflare.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/20200110132336.26099-1-lmb@cloudflare.com
  • Loading branch information
Lorenz Bauer authored and Alexei Starovoitov committed Jan 10, 2020
1 parent e7a5f1f commit 2e012c7
Showing 1 changed file with 4 additions and 5 deletions.
9 changes: 4 additions & 5 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -5318,8 +5318,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);
sock_gen_put(sk);
return NULL;
}
}
Expand Down Expand Up @@ -5356,8 +5355,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);
sock_gen_put(sk);
return NULL;
}
}
Expand Down Expand Up @@ -5424,7 +5422,8 @@ 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))
/* Only full sockets have sk->sk_flags. */
if (!sk_fullsock(sk) || !sock_flag(sk, SOCK_RCU_FREE))
sock_gen_put(sk);
return 0;
}
Expand Down

0 comments on commit 2e012c7

Please sign in to comment.