From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BE39CC3F2D2 for ; Fri, 28 Feb 2020 11:55:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8C485246AC for ; Fri, 28 Feb 2020 11:55:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="Ha0XE9y0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726956AbgB1Lyt (ORCPT ); Fri, 28 Feb 2020 06:54:49 -0500 Received: from mail-wm1-f52.google.com ([209.85.128.52]:56180 "EHLO mail-wm1-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726880AbgB1Lyp (ORCPT ); Fri, 28 Feb 2020 06:54:45 -0500 Received: by mail-wm1-f52.google.com with SMTP id q9so2871945wmj.5 for ; Fri, 28 Feb 2020 03:54:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3AjfHwxc7+pE1DB75z91GO99ApUXoYyaQ80TOOs+VtU=; b=Ha0XE9y0tZEnH8zUfgSFRimmtwceWEwDrcihQJALtXrXAganUeAWx+mPpDbOL1d7F6 9RwEyRZRkB8UaxtfnGcLz0nxG/3xSyVrZNRGXPuhaWKv6fVZYx+NWfqZyUFdsUSyQt8+ jXvjr4eUBC+1sR9v5pEY5JtDbMPfBxJp0nHhA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3AjfHwxc7+pE1DB75z91GO99ApUXoYyaQ80TOOs+VtU=; b=H3yUIG3vE7nBeVgUJpcb40ht7forCR8yvawKjoYBaJv8DL2jMlv95HV9LFyNulmNjE rPwqrMmLw+CqJRjuBh5vekk/DlMYf5Oo2KHiIZtATxZrDDUyf1fXCbFDHfgLGAOdrv1X +310JcsHLmmE53Bo+FfkdPCL7p1e4/yQ8A+Gg6CQnzAHOaciS2CUw4lewfUbzCT3MdSo 6ThE1IO+Pw/w7yemM4GgFyT+jDbqFSUEa8Hryc8RMSt/+IlWS6ReBbXiWHpvrfp3R249 LtXYFsRHDVDNy8EdUQVBB8m62XJBGYTmHtwsbPJ93YlKjMuvKQv0SQUdumgGFGlF4INM PVWw== X-Gm-Message-State: APjAAAXcQqauYQnFOoqBsmVuYaMD2xoIxkWt1WynnZ9c6u+LmpPMSDkf qZiJA+ZwkytW2b59z888LEyBPQ== X-Google-Smtp-Source: APXvYqxLbwznMzNR4oXKAzcAmPdyIvyhGQxT5DxFukyboaYHpkwdDRSR06Dd0IVjk4RlpDH4HEE0SQ== X-Received: by 2002:a05:600c:114d:: with SMTP id z13mr4470135wmz.105.1582890882134; Fri, 28 Feb 2020 03:54:42 -0800 (PST) Received: from antares.lan (b.2.d.a.1.b.1.b.2.c.5.e.0.3.d.4.f.f.6.2.a.5.a.7.0.b.8.0.1.0.0.2.ip6.arpa. [2001:8b0:7a5a:26ff:4d30:e5c2:b1b1:ad2b]) by smtp.gmail.com with ESMTPSA id q125sm2044284wme.19.2020.02.28.03.54.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Feb 2020 03:54:41 -0800 (PST) From: Lorenz Bauer To: john.fastabend@gmail.com, Daniel Borkmann , Jakub Sitnicki , Lorenz Bauer , "David S. Miller" , Jakub Kicinski , Alexey Kuznetsov , Hideaki YOSHIFUJI , Alexei Starovoitov Cc: kernel-team@cloudflare.com, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bpf@vger.kernel.org Subject: [PATCH bpf-next v2 5/9] bpf: sockmap: allow UDP sockets Date: Fri, 28 Feb 2020 11:53:40 +0000 Message-Id: <20200228115344.17742-6-lmb@cloudflare.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200228115344.17742-1-lmb@cloudflare.com> References: <20200228115344.17742-1-lmb@cloudflare.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add basic psock hooks for UDP sockets. This allows adding and removing sockets, as well as automatic removal on unhash and close. sock_map_sk_state_allowed is called from the syscall path, and ensures that only established or listening sockets are added. No such check exists for the BPF path: we rely on sockets being in particular states when a BPF sock ops hook is executed. For the passive open hook this means that sockets are actually in TCP_SYN_RECV state (and unhashed) when they are added to the sock map. UDP sockets are not saddled with this inconsistency, and so the checks for both syscall and BPF path should be identical. Rather than duplicating the logic into sock_map_sk_state_allowed merge it with sock_map_sk_is_suitable. Signed-off-by: Lorenz Bauer --- MAINTAINERS | 1 + include/linux/udp.h | 4 ++++ net/core/sock_map.c | 52 ++++++++++++++++++++++++++------------------ net/ipv4/Makefile | 1 + net/ipv4/udp_bpf.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 21 deletions(-) create mode 100644 net/ipv4/udp_bpf.c diff --git a/MAINTAINERS b/MAINTAINERS index 2af5fa73155e..495ba52038ad 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9358,6 +9358,7 @@ F: include/linux/skmsg.h F: net/core/skmsg.c F: net/core/sock_map.c F: net/ipv4/tcp_bpf.c +F: net/ipv4/udp_bpf.c LANTIQ / INTEL Ethernet drivers M: Hauke Mehrtens diff --git a/include/linux/udp.h b/include/linux/udp.h index aa84597bdc33..2485a35d113c 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -143,4 +143,8 @@ static inline bool udp_unexpected_gso(struct sock *sk, struct sk_buff *skb) #define IS_UDPLITE(__sk) (__sk->sk_protocol == IPPROTO_UDPLITE) +#ifdef CONFIG_BPF_STREAM_PARSER +int udp_bpf_init(struct sock *sk); +#endif + #endif /* _LINUX_UDP_H */ diff --git a/net/core/sock_map.c b/net/core/sock_map.c index c84cc9fc7f6b..d742e1538ae9 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -153,7 +153,7 @@ static struct sk_psock *sock_map_psock_get_checked(struct sock *sk) rcu_read_lock(); psock = sk_psock(sk); if (psock) { - if (sk->sk_prot->recvmsg != tcp_bpf_recvmsg) { + if (sk->sk_prot->close != sock_map_close) { psock = ERR_PTR(-EBUSY); goto out; } @@ -166,6 +166,14 @@ static struct sk_psock *sock_map_psock_get_checked(struct sock *sk) return psock; } +static int sock_map_init_hooks(struct sock *sk) +{ + if (sk->sk_type == SOCK_DGRAM) + return udp_bpf_init(sk); + else + return tcp_bpf_init(sk); +} + static int sock_map_link(struct bpf_map *map, struct sk_psock_progs *progs, struct sock *sk) { @@ -220,7 +228,7 @@ static int sock_map_link(struct bpf_map *map, struct sk_psock_progs *progs, if (msg_parser) psock_set_prog(&psock->progs.msg_parser, msg_parser); - ret = tcp_bpf_init(sk); + ret = sock_map_init_hooks(sk); if (ret < 0) goto out_drop; @@ -267,7 +275,7 @@ static int sock_map_link_no_progs(struct bpf_map *map, struct sock *sk) return -ENOMEM; init: - ret = tcp_bpf_init(sk); + ret = sock_map_init_hooks(sk); if (ret < 0) sk_psock_put(sk, psock); return ret; @@ -394,9 +402,14 @@ static int sock_map_get_next_key(struct bpf_map *map, void *key, void *next) return 0; } +static bool sock_map_sk_is_tcp(const struct sock *sk) +{ + return sk->sk_type == SOCK_STREAM && sk->sk_protocol == IPPROTO_TCP; +} + static bool sock_map_redirect_allowed(const struct sock *sk) { - return sk->sk_state != TCP_LISTEN; + return sock_map_sk_is_tcp(sk) && sk->sk_state != TCP_LISTEN; } static int sock_map_update_common(struct bpf_map *map, u32 idx, @@ -466,15 +479,20 @@ static bool sock_map_op_okay(const struct bpf_sock_ops_kern *ops) ops->op == BPF_SOCK_OPS_TCP_LISTEN_CB; } -static bool sock_map_sk_is_suitable(const struct sock *sk) +static bool sock_map_sk_is_udp(const struct sock *sk) { - return sk->sk_type == SOCK_STREAM && - sk->sk_protocol == IPPROTO_TCP; + return sk->sk_type == SOCK_DGRAM && sk->sk_protocol == IPPROTO_UDP; } -static bool sock_map_sk_state_allowed(const struct sock *sk) +static bool sock_map_sk_is_suitable(const struct sock *sk, bool from_bpf) { - return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN); + int tcp_flags = TCPF_ESTABLISHED | TCPF_LISTEN; + + if (from_bpf) + tcp_flags |= TCPF_SYN_RECV; + + return (sock_map_sk_is_udp(sk) && sk_hashed(sk)) || + (sock_map_sk_is_tcp(sk) && (1 << sk->sk_state) & tcp_flags); } static int sock_map_update_elem(struct bpf_map *map, void *key, @@ -501,13 +519,9 @@ static int sock_map_update_elem(struct bpf_map *map, void *key, ret = -EINVAL; goto out; } - if (!sock_map_sk_is_suitable(sk)) { - ret = -EOPNOTSUPP; - goto out; - } sock_map_sk_acquire(sk); - if (!sock_map_sk_state_allowed(sk)) + if (!sock_map_sk_is_suitable(sk, false)) ret = -EOPNOTSUPP; else ret = sock_map_update_common(map, idx, sk, flags); @@ -522,7 +536,7 @@ BPF_CALL_4(bpf_sock_map_update, struct bpf_sock_ops_kern *, sops, { WARN_ON_ONCE(!rcu_read_lock_held()); - if (likely(sock_map_sk_is_suitable(sops->sk) && + if (likely(sock_map_sk_is_suitable(sops->sk, true) && sock_map_op_okay(sops))) return sock_map_update_common(map, *(u32 *)key, sops->sk, flags); @@ -849,13 +863,9 @@ static int sock_hash_update_elem(struct bpf_map *map, void *key, ret = -EINVAL; goto out; } - if (!sock_map_sk_is_suitable(sk)) { - ret = -EOPNOTSUPP; - goto out; - } sock_map_sk_acquire(sk); - if (!sock_map_sk_state_allowed(sk)) + if (!sock_map_sk_is_suitable(sk, false)) ret = -EOPNOTSUPP; else ret = sock_hash_update_common(map, key, sk, flags); @@ -1023,7 +1033,7 @@ BPF_CALL_4(bpf_sock_hash_update, struct bpf_sock_ops_kern *, sops, { WARN_ON_ONCE(!rcu_read_lock_held()); - if (likely(sock_map_sk_is_suitable(sops->sk) && + if (likely(sock_map_sk_is_suitable(sops->sk, true) && sock_map_op_okay(sops))) return sock_hash_update_common(map, key, sops->sk, flags); return -EOPNOTSUPP; diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 9d97bace13c8..9e1a186a3671 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o obj-$(CONFIG_NET_SOCK_MSG) += tcp_bpf.o +obj-$(CONFIG_BPF_STREAM_PARSER) += udp_bpf.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c new file mode 100644 index 000000000000..3ecf246076be --- /dev/null +++ b/net/ipv4/udp_bpf.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2020 Cloudflare Ltd https://cloudflare.com */ + +#include +#include +#include +#include +#include +#include + +#include + +static int udp_bpf_rebuild_protos(struct proto *prot, struct proto *base) +{ + *prot = *base; + prot->unhash = sock_map_unhash; + prot->close = sock_map_close; + return 0; +} + +static struct proto *udp_bpf_choose_proto(struct proto prot[], + struct sk_psock *psock) +{ + return prot; +} + +static struct proto udpv4_proto; +static struct proto udpv6_proto; + +static struct sk_psock_hooks udp_bpf_hooks __read_mostly = { + .ipv4 = &udpv4_proto, + .ipv6 = &udpv6_proto, + .rebuild_proto = udp_bpf_rebuild_protos, + .choose_proto = udp_bpf_choose_proto, +}; + +static int __init udp_bpf_init_psock_hooks(void) +{ + return sk_psock_hooks_init(&udp_bpf_hooks, &udp_prot); +} +core_initcall(udp_bpf_init_psock_hooks); + +int udp_bpf_init(struct sock *sk) +{ + int ret; + + sock_owned_by_me(sk); + + rcu_read_lock(); + ret = sk_psock_hooks_install(&udp_bpf_hooks, sk); + rcu_read_unlock(); + return ret; +} -- 2.20.1