tcp_bpf: Don't let child socket inherit parent protocol ops on copy
authorJakub Sitnicki <jakub@cloudflare.com>
Tue, 18 Feb 2020 17:10:15 +0000 (17:10 +0000)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 21 Feb 2020 21:29:45 +0000 (22:29 +0100)
Prepare for cloning listening sockets that have their protocol callbacks
overridden by sk_msg. Child sockets must not inherit parent callbacks that
access state stored in sk_user_data owned by the parent.

Restore the child socket protocol callbacks before it gets hashed and any
of the callbacks can get invoked.

Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20200218171023.844439-4-jakub@cloudflare.com
include/net/tcp.h
net/ipv4/tcp_bpf.c
net/ipv4/tcp_minisocks.c

index a5ea27df3c2b25ad5e159d28a968ce94d3036ff7..07f947cc80e6383e07a4bf80aaf2c9b844521589 100644 (file)
@@ -2203,6 +2203,13 @@ int tcp_bpf_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
                    int nonblock, int flags, int *addr_len);
 int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock,
                      struct msghdr *msg, int len, int flags);
+#ifdef CONFIG_NET_SOCK_MSG
+void tcp_bpf_clone(const struct sock *sk, struct sock *newsk);
+#else
+static inline void tcp_bpf_clone(const struct sock *sk, struct sock *newsk)
+{
+}
+#endif
 
 /* Call BPF_SOCK_OPS program that returns an int. If the return value
  * is < 0, then the BPF op failed (for example if the loaded BPF
index dd183b0506427ac9733d97da69bc1edd3b73b730..7d6e1b75d4d4f3dc160fff615426b0ff01d327a9 100644 (file)
@@ -693,3 +693,17 @@ int tcp_bpf_init(struct sock *sk)
        rcu_read_unlock();
        return 0;
 }
+
+/* If a child got cloned from a listening socket that had tcp_bpf
+ * protocol callbacks installed, we need to restore the callbacks to
+ * the default ones because the child does not inherit the psock state
+ * that tcp_bpf callbacks expect.
+ */
+void tcp_bpf_clone(const struct sock *sk, struct sock *newsk)
+{
+       int family = sk->sk_family == AF_INET6 ? TCP_BPF_IPV6 : TCP_BPF_IPV4;
+       struct proto *prot = newsk->sk_prot;
+
+       if (prot == &tcp_bpf_prots[family][TCP_BPF_BASE])
+               newsk->sk_prot = sk->sk_prot_creator;
+}
index ad3b56d9fa7156f724f7558abccb1367fb5ea8d3..c8274371c3d04bb0fdddc984d34e7402b24d814e 100644 (file)
@@ -548,6 +548,8 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
        newtp->fastopen_req = NULL;
        RCU_INIT_POINTER(newtp->fastopen_rsk, NULL);
 
+       tcp_bpf_clone(sk, newsk);
+
        __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS);
 
        return newsk;