mptcp: do not inherit inet proto ops
authorFlorian Westphal <fw@strlen.de>
Sat, 25 Jan 2020 00:04:02 +0000 (16:04 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 25 Jan 2020 07:14:39 +0000 (08:14 +0100)
We need to initialise the struct ourselves, else we expose tcp-specific
callbacks such as tcp_splice_read which will then trigger splat because
the socket is an mptcp one:

BUG: KASAN: slab-out-of-bounds in tcp_mstamp_refresh+0x80/0xa0 net/ipv4/tcp_output.c:57
Write of size 8 at addr ffff888116aa21d0 by task syz-executor.0/5478

CPU: 1 PID: 5478 Comm: syz-executor.0 Not tainted 5.5.0-rc6 #3
Call Trace:
 tcp_mstamp_refresh+0x80/0xa0 net/ipv4/tcp_output.c:57
 tcp_rcv_space_adjust+0x72/0x7f0 net/ipv4/tcp_input.c:612
 tcp_read_sock+0x622/0x990 net/ipv4/tcp.c:1674
 tcp_splice_read+0x20b/0xb40 net/ipv4/tcp.c:791
 do_splice+0x1259/0x1560 fs/splice.c:1205

To prevent build error with ipv6, add the recv/sendmsg function
declaration to ipv6.h.  The functions are already accessible "thanks"
to retpoline related work, but they are currently only made visible
by socket.c specific INDIRECT_CALLABLE macros.

Reported-by: Christoph Paasch <cpaasch@apple.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ipv6.h
net/mptcp/protocol.c

index 4e95f6df508cb5178963749d4e1836566f781c4e..cec1a54401f283d8f17de8c3a2bac03dd530c606 100644 (file)
@@ -1113,6 +1113,9 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 
 int inet6_hash_connect(struct inet_timewait_death_row *death_row,
                              struct sock *sk);
+int inet6_sendmsg(struct socket *sock, struct msghdr *msg, size_t size);
+int inet6_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
+                 int flags);
 
 /*
  * reassembly.c
index ee916b3686fe51e54b5abf6d91d6273d00cc935b..41d49126d29aab6262ea9d36febc5c7e6c08bdd1 100644 (file)
@@ -1163,7 +1163,31 @@ out_unlock:
        return ret;
 }
 
-static struct proto_ops mptcp_stream_ops;
+static const struct proto_ops mptcp_stream_ops = {
+       .family            = PF_INET,
+       .owner             = THIS_MODULE,
+       .release           = inet_release,
+       .bind              = mptcp_bind,
+       .connect           = mptcp_stream_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = mptcp_stream_accept,
+       .getname           = mptcp_v4_getname,
+       .poll              = mptcp_poll,
+       .ioctl             = inet_ioctl,
+       .gettstamp         = sock_gettstamp,
+       .listen            = mptcp_listen,
+       .shutdown          = mptcp_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = inet_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = inet_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+};
 
 static struct inet_protosw mptcp_protosw = {
        .type           = SOCK_STREAM,
@@ -1176,14 +1200,6 @@ static struct inet_protosw mptcp_protosw = {
 void mptcp_proto_init(void)
 {
        mptcp_prot.h.hashinfo = tcp_prot.h.hashinfo;
-       mptcp_stream_ops = inet_stream_ops;
-       mptcp_stream_ops.bind = mptcp_bind;
-       mptcp_stream_ops.connect = mptcp_stream_connect;
-       mptcp_stream_ops.poll = mptcp_poll;
-       mptcp_stream_ops.accept = mptcp_stream_accept;
-       mptcp_stream_ops.getname = mptcp_v4_getname;
-       mptcp_stream_ops.listen = mptcp_listen;
-       mptcp_stream_ops.shutdown = mptcp_shutdown;
 
        mptcp_subflow_init();
 
@@ -1194,7 +1210,32 @@ void mptcp_proto_init(void)
 }
 
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
-static struct proto_ops mptcp_v6_stream_ops;
+static const struct proto_ops mptcp_v6_stream_ops = {
+       .family            = PF_INET6,
+       .owner             = THIS_MODULE,
+       .release           = inet6_release,
+       .bind              = mptcp_bind,
+       .connect           = mptcp_stream_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = mptcp_stream_accept,
+       .getname           = mptcp_v6_getname,
+       .poll              = mptcp_poll,
+       .ioctl             = inet6_ioctl,
+       .gettstamp         = sock_gettstamp,
+       .listen            = mptcp_listen,
+       .shutdown          = mptcp_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet6_sendmsg,
+       .recvmsg           = inet6_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = inet_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+};
+
 static struct proto mptcp_v6_prot;
 
 static void mptcp_v6_destroy(struct sock *sk)
@@ -1226,15 +1267,6 @@ int mptcp_proto_v6_init(void)
        if (err)
                return err;
 
-       mptcp_v6_stream_ops = inet6_stream_ops;
-       mptcp_v6_stream_ops.bind = mptcp_bind;
-       mptcp_v6_stream_ops.connect = mptcp_stream_connect;
-       mptcp_v6_stream_ops.poll = mptcp_poll;
-       mptcp_v6_stream_ops.accept = mptcp_stream_accept;
-       mptcp_v6_stream_ops.getname = mptcp_v6_getname;
-       mptcp_v6_stream_ops.listen = mptcp_listen;
-       mptcp_v6_stream_ops.shutdown = mptcp_shutdown;
-
        err = inet6_register_protosw(&mptcp_v6_protosw);
        if (err)
                proto_unregister(&mptcp_v6_prot);