From: John Fastabend john.fastabend@gmail.com
mainline inclusion from mainline-v5.16-rc1 commit 40a34121ac1dc52ed9cd34a8f4e48e32517a52fd category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IB0F23 CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
In order to fix an issue with sockets in TCP sockmap redirect cases we plan to allow CLOSE state sockets to exist in the sockmap. However, the check in bpf_sk_lookup_assign() currently only invalidates sockets in the TCP_ESTABLISHED case relying on the checks on sockmap insert to ensure we never SOCK_CLOSE state sockets in the map.
To prepare for this change we flip the logic in bpf_sk_lookup_assign() to explicitly test for the accepted cases. Namely, a tcp socket in TCP_LISTEN or a udp socket in TCP_CLOSE state. This also makes the code more resilent to future changes.
Suggested-by: Jakub Sitnicki jakub@cloudflare.com Signed-off-by: John Fastabend john.fastabend@gmail.com Signed-off-by: Daniel Borkmann daniel@iogearbox.net Reviewed-by: Jakub Sitnicki jakub@cloudflare.com Link: https://lore.kernel.org/bpf/20211103204736.248403-2-john.fastabend@gmail.com Conflicts: include/linux/skmsg.h net/core/sock_map.c [Context conflicts] Signed-off-by: Yu Kuai yukuai3@huawei.com --- include/linux/skmsg.h | 12 ++++++++++++ net/core/filter.c | 6 ++++-- net/core/sock_map.c | 12 ------------ 3 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h index f9d8e8b1a4e8..91ba0da57d0c 100644 --- a/include/linux/skmsg.h +++ b/include/linux/skmsg.h @@ -521,4 +521,16 @@ static inline bool sk_psock_strp_enabled(struct sk_psock *psock) return false; return psock->parser.enabled; } + +static inline bool sk_is_tcp(const struct sock *sk) +{ + return sk->sk_type == SOCK_STREAM && + sk->sk_protocol == IPPROTO_TCP; +} + +static inline bool sk_is_udp(const struct sock *sk) +{ + return sk->sk_type == SOCK_DGRAM && + sk->sk_protocol == IPPROTO_UDP; +} #endif /* _LINUX_SKMSG_H */ diff --git a/net/core/filter.c b/net/core/filter.c index 62d09520a55d..fb84fd152fd7 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -10370,8 +10370,10 @@ BPF_CALL_3(bpf_sk_lookup_assign, struct bpf_sk_lookup_kern *, ctx, return -EINVAL; if (unlikely(sk && sk_is_refcounted(sk))) return -ESOCKTNOSUPPORT; /* reject non-RCU freed sockets */ - if (unlikely(sk && sk->sk_state == TCP_ESTABLISHED)) - return -ESOCKTNOSUPPORT; /* reject connected sockets */ + if (unlikely(sk && sk_is_tcp(sk) && sk->sk_state != TCP_LISTEN)) + return -ESOCKTNOSUPPORT; /* only accept TCP socket in LISTEN */ + if (unlikely(sk && sk_is_udp(sk) && sk->sk_state != TCP_CLOSE)) + return -ESOCKTNOSUPPORT; /* only accept UDP socket in CLOSE */
/* Check if socket is suitable for packet L3/L4 protocol */ if (sk && sk->sk_protocol != ctx->protocol) diff --git a/net/core/sock_map.c b/net/core/sock_map.c index a4d1d41883b0..ae55940a1fc4 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -551,18 +551,6 @@ static bool sock_map_op_okay(const struct bpf_sock_ops_kern *ops) ops->op == BPF_SOCK_OPS_TCP_LISTEN_CB; }
-static bool sk_is_tcp(const struct sock *sk) -{ - return sk->sk_type == SOCK_STREAM && - sk->sk_protocol == IPPROTO_TCP; -} - -static bool sk_is_udp(const struct sock *sk) -{ - return sk->sk_type == SOCK_DGRAM && - sk->sk_protocol == IPPROTO_UDP; -} - static bool sock_map_redirect_allowed(const struct sock *sk) { return sk_is_tcp(sk) && sk->sk_state != TCP_LISTEN;