| From 69502e9c7bc51373638e0be0b35a123349f19681 Mon Sep 17 00:00:00 2001 |
| From: Lorenz Bauer <lmb@cloudflare.com> |
| Date: Fri, 10 Jan 2020 13:23:36 +0000 |
| Subject: [PATCH] net: bpf: Don't leak time wait and request sockets |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit 2e012c74823629d9db27963c79caa3f5b2010746 upstream. |
| |
| 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: 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@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 |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/core/filter.c b/net/core/filter.c |
| index 03236f795725..1a4b72e1e7b5 100644 |
| --- a/net/core/filter.c |
| +++ b/net/core/filter.c |
| @@ -5344,8 +5344,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; |
| } |
| } |
| @@ -5382,8 +5381,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; |
| } |
| } |
| @@ -5450,7 +5448,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; |
| } |
| -- |
| 2.7.4 |
| |