[kernel/f20] CVE-2013-XXXX net: memory leak in recvmsg (rhbz 1039845 1039874)

Josh Boyer jwboyer at fedoraproject.org
Tue Dec 10 13:53:13 UTC 2013


commit f1aa6ce30e98b688067f3a74b87b0c0e9a47717b
Author: Josh Boyer <jwboyer at fedoraproject.org>
Date:   Tue Dec 10 08:50:43 2013 -0500

    CVE-2013-XXXX net: memory leak in recvmsg (rhbz 1039845 1039874)

 kernel.spec                                        |   10 +
 ...recvmsg-handler-msg_name-and-msg_namelen-.patch |  771 ++++++++++++++++++++
 2 files changed, 781 insertions(+), 0 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index e62ec95..6615bb0 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -832,6 +832,10 @@ Patch25162: inet-fix-addr_len-msg_namelen-assignment-in-recv_error-and-rxpmtu-fu
 #rhbz 958826
 Patch25164: dell-laptop.patch
 
+#CVE-2013-XXXX rhbz 1039845 1039874
+Patch25165: net-rework-recvmsg-handler-msg_name-and-msg_namelen-.patch
+
+
 # END OF PATCH DEFINITIONS
 
 %endif
@@ -1622,6 +1626,9 @@ ApplyPatch inet-fix-addr_len-msg_namelen-assignment-in-recv_error-and-rxpmtu-fun
 #rhbz 958826
 ApplyPatch dell-laptop.patch
 
+#CVE-2013-XXXX rhbz 1039845 1039874
+ApplyPatch net-rework-recvmsg-handler-msg_name-and-msg_namelen-.patch
+
 # END OF PATCH APPLICATIONS
 
 %endif
@@ -2424,6 +2431,9 @@ fi
 #                 ||----w |
 #                 ||     ||
 %changelog
+* Tue Dec 10 2013 Josh Boyer <jwboyer at fedoraproject.org>
+- CVE-2013-XXXX net: memory leak in recvmsg (rhbz 1039845 1039874)
+
 * Fri Dec  6 2013 Peter Robinson <pbrobinson at fedoraproject.org>
 - Fix up ARM usb gadget config to make it useful
 
diff --git a/net-rework-recvmsg-handler-msg_name-and-msg_namelen-.patch b/net-rework-recvmsg-handler-msg_name-and-msg_namelen-.patch
new file mode 100644
index 0000000..08c6302
--- /dev/null
+++ b/net-rework-recvmsg-handler-msg_name-and-msg_namelen-.patch
@@ -0,0 +1,771 @@
+From 9cb9fb275f8794546dc31a79f2f02127fed5baf2 Mon Sep 17 00:00:00 2001
+From: Hannes Frederic Sowa <hannes at stressinduktion.org>
+Date: Thu, 21 Nov 2013 03:14:22 +0100
+Subject: [PATCH] net: rework recvmsg handler msg_name and msg_namelen logic
+
+[ Upstream commit f3d3342602f8bcbf37d7c46641cb9bca7618eb1c ]
+
+This patch now always passes msg->msg_namelen as 0. recvmsg handlers must
+set msg_namelen to the proper size <= sizeof(struct sockaddr_storage)
+to return msg_name to the user.
+
+This prevents numerous uninitialized memory leaks we had in the
+recvmsg handlers and makes it harder for new code to accidentally leak
+uninitialized memory.
+
+Optimize for the case recvfrom is called with NULL as address. We don't
+need to copy the address at all, so set it to NULL before invoking the
+recvmsg handler. We can do so, because all the recvmsg handlers must
+cope with the case a plain read() is called on them. read() also sets
+msg_name to NULL.
+
+Also document these changes in include/linux/net.h as suggested by David
+Miller.
+
+Changes since RFC:
+
+Set msg->msg_name = NULL if user specified a NULL in msg_name but had a
+non-null msg_namelen in verify_iovec/verify_compat_iovec. This doesn't
+affect sendto as it would bail out earlier while trying to copy-in the
+address. It also more naturally reflects the logic by the callers of
+verify_iovec.
+
+With this change in place I could remove "
+if (!uaddr || msg_sys->msg_namelen == 0)
+	msg->msg_name = NULL
+".
+
+This change does not alter the user visible error logic as we ignore
+msg_namelen as long as msg_name is NULL.
+
+Also remove two unnecessary curly brackets in ___sys_recvmsg and change
+comments to netdev style.
+
+Cc: David Miller <davem at davemloft.net>
+Suggested-by: Eric Dumazet <eric.dumazet at gmail.com>
+Signed-off-by: Hannes Frederic Sowa <hannes at stressinduktion.org>
+Signed-off-by: David S. Miller <davem at davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
+---
+ crypto/algif_hash.c            |  2 --
+ crypto/algif_skcipher.c        |  1 -
+ drivers/isdn/mISDN/socket.c    | 13 ++++---------
+ drivers/net/ppp/pppoe.c        |  2 --
+ include/linux/net.h            |  8 ++++++++
+ net/appletalk/ddp.c            | 16 +++++++---------
+ net/atm/common.c               |  2 --
+ net/ax25/af_ax25.c             |  4 ++--
+ net/bluetooth/af_bluetooth.c   |  4 ----
+ net/bluetooth/hci_sock.c       |  2 --
+ net/bluetooth/rfcomm/sock.c    |  1 -
+ net/bluetooth/sco.c            |  1 -
+ net/caif/caif_socket.c         |  4 ----
+ net/compat.c                   |  3 ++-
+ net/core/iovec.c               |  3 ++-
+ net/ipx/af_ipx.c               |  3 +--
+ net/irda/af_irda.c             |  4 ----
+ net/iucv/af_iucv.c             |  2 --
+ net/key/af_key.c               |  1 -
+ net/l2tp/l2tp_ppp.c            |  2 --
+ net/llc/af_llc.c               |  2 --
+ net/netlink/af_netlink.c       |  2 --
+ net/netrom/af_netrom.c         |  3 +--
+ net/nfc/llcp_sock.c            |  2 --
+ net/nfc/rawsock.c              |  2 --
+ net/packet/af_packet.c         | 32 +++++++++++++++-----------------
+ net/rds/recv.c                 |  2 --
+ net/rose/af_rose.c             |  8 +++++---
+ net/rxrpc/ar-recvmsg.c         |  9 ++++++---
+ net/socket.c                   | 19 +++++++++++--------
+ net/tipc/socket.c              |  6 ------
+ net/unix/af_unix.c             |  5 -----
+ net/vmw_vsock/af_vsock.c       |  2 --
+ net/vmw_vsock/vmci_transport.c |  2 --
+ net/x25/af_x25.c               |  3 +--
+ 35 files changed, 65 insertions(+), 112 deletions(-)
+
+diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
+index 0262210..ef5356c 100644
+--- a/crypto/algif_hash.c
++++ b/crypto/algif_hash.c
+@@ -161,8 +161,6 @@ static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
+ 	else if (len < ds)
+ 		msg->msg_flags |= MSG_TRUNC;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	lock_sock(sk);
+ 	if (ctx->more) {
+ 		ctx->more = 0;
+diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
+index a1c4f0a..6a6dfc0 100644
+--- a/crypto/algif_skcipher.c
++++ b/crypto/algif_skcipher.c
+@@ -432,7 +432,6 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
+ 	long copied = 0;
+ 
+ 	lock_sock(sk);
+-	msg->msg_namelen = 0;
+ 	for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
+ 	     iovlen--, iov++) {
+ 		unsigned long seglen = iov->iov_len;
+diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
+index e47dcb9..5cefb47 100644
+--- a/drivers/isdn/mISDN/socket.c
++++ b/drivers/isdn/mISDN/socket.c
+@@ -117,7 +117,6 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ {
+ 	struct sk_buff		*skb;
+ 	struct sock		*sk = sock->sk;
+-	struct sockaddr_mISDN	*maddr;
+ 
+ 	int		copied, err;
+ 
+@@ -135,9 +134,9 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (!skb)
+ 		return err;
+ 
+-	if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) {
+-		msg->msg_namelen = sizeof(struct sockaddr_mISDN);
+-		maddr = (struct sockaddr_mISDN *)msg->msg_name;
++	if (msg->msg_name) {
++		struct sockaddr_mISDN *maddr = msg->msg_name;
++
+ 		maddr->family = AF_ISDN;
+ 		maddr->dev = _pms(sk)->dev->id;
+ 		if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
+@@ -150,11 +149,7 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 			maddr->sapi = _pms(sk)->ch.addr & 0xFF;
+ 			maddr->tei =  (_pms(sk)->ch.addr >> 8) & 0xFF;
+ 		}
+-	} else {
+-		if (msg->msg_namelen)
+-			printk(KERN_WARNING "%s: too small namelen %d\n",
+-			       __func__, msg->msg_namelen);
+-		msg->msg_namelen = 0;
++		msg->msg_namelen = sizeof(*maddr);
+ 	}
+ 
+ 	copied = skb->len + MISDN_HEADER_LEN;
+diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
+index 5f66e30..82ee6ed 100644
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -979,8 +979,6 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (error < 0)
+ 		goto end;
+ 
+-	m->msg_namelen = 0;
+-
+ 	if (skb) {
+ 		total_len = min_t(size_t, total_len, skb->len);
+ 		error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len);
+diff --git a/include/linux/net.h b/include/linux/net.h
+index 4f27575..8bd9d92 100644
+--- a/include/linux/net.h
++++ b/include/linux/net.h
+@@ -163,6 +163,14 @@ struct proto_ops {
+ #endif
+ 	int		(*sendmsg)   (struct kiocb *iocb, struct socket *sock,
+ 				      struct msghdr *m, size_t total_len);
++	/* Notes for implementing recvmsg:
++	 * ===============================
++	 * msg->msg_namelen should get updated by the recvmsg handlers
++	 * iff msg_name != NULL. It is by default 0 to prevent
++	 * returning uninitialized memory to user space.  The recvfrom
++	 * handlers can assume that msg.msg_name is either NULL or has
++	 * a minimum size of sizeof(struct sockaddr_storage).
++	 */
+ 	int		(*recvmsg)   (struct kiocb *iocb, struct socket *sock,
+ 				      struct msghdr *m, size_t total_len,
+ 				      int flags);
+diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
+index 7fee50d..7d424ac 100644
+--- a/net/appletalk/ddp.c
++++ b/net/appletalk/ddp.c
+@@ -1735,7 +1735,6 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
+ 			 size_t size, int flags)
+ {
+ 	struct sock *sk = sock->sk;
+-	struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
+ 	struct ddpehdr *ddp;
+ 	int copied = 0;
+ 	int offset = 0;
+@@ -1764,14 +1763,13 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
+ 	}
+ 	err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
+ 
+-	if (!err) {
+-		if (sat) {
+-			sat->sat_family      = AF_APPLETALK;
+-			sat->sat_port        = ddp->deh_sport;
+-			sat->sat_addr.s_node = ddp->deh_snode;
+-			sat->sat_addr.s_net  = ddp->deh_snet;
+-		}
+-		msg->msg_namelen = sizeof(*sat);
++	if (!err && msg->msg_name) {
++		struct sockaddr_at *sat = msg->msg_name;
++		sat->sat_family      = AF_APPLETALK;
++		sat->sat_port        = ddp->deh_sport;
++		sat->sat_addr.s_node = ddp->deh_snode;
++		sat->sat_addr.s_net  = ddp->deh_snet;
++		msg->msg_namelen     = sizeof(*sat);
+ 	}
+ 
+ 	skb_free_datagram(sk, skb);	/* Free the datagram. */
+diff --git a/net/atm/common.c b/net/atm/common.c
+index 737bef5..7b49100 100644
+--- a/net/atm/common.c
++++ b/net/atm/common.c
+@@ -531,8 +531,6 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+ 	struct sk_buff *skb;
+ 	int copied, error = -EINVAL;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	if (sock->state != SS_CONNECTED)
+ 		return -ENOTCONN;
+ 
+diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
+index 4b4d2b7..78c474f 100644
+--- a/net/ax25/af_ax25.c
++++ b/net/ax25/af_ax25.c
+@@ -1636,11 +1636,11 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 
+ 	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ 
+-	if (msg->msg_namelen != 0) {
+-		struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
++	if (msg->msg_name) {
+ 		ax25_digi digi;
+ 		ax25_address src;
+ 		const unsigned char *mac = skb_mac_header(skb);
++		struct sockaddr_ax25 *sax = msg->msg_name;
+ 
+ 		memset(sax, 0, sizeof(struct full_sockaddr_ax25));
+ 		ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL,
+diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
+index 9096137..6629cdc 100644
+--- a/net/bluetooth/af_bluetooth.c
++++ b/net/bluetooth/af_bluetooth.c
+@@ -221,8 +221,6 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (flags & (MSG_OOB))
+ 		return -EOPNOTSUPP;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	skb = skb_recv_datagram(sk, flags, noblock, &err);
+ 	if (!skb) {
+ 		if (sk->sk_shutdown & RCV_SHUTDOWN)
+@@ -287,8 +285,6 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (flags & MSG_OOB)
+ 		return -EOPNOTSUPP;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	BT_DBG("sk %p size %zu", sk, size);
+ 
+ 	lock_sock(sk);
+diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
+index 9bd7d95..fa4bf66 100644
+--- a/net/bluetooth/hci_sock.c
++++ b/net/bluetooth/hci_sock.c
+@@ -752,8 +752,6 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (!skb)
+ 		return err;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	copied = skb->len;
+ 	if (len < copied) {
+ 		msg->msg_flags |= MSG_TRUNC;
+diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
+index 30b3721..c1c6028 100644
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -608,7 +608,6 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 
+ 	if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+ 		rfcomm_dlc_accept(d);
+-		msg->msg_namelen = 0;
+ 		return 0;
+ 	}
+ 
+diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
+index e7bd4ee..2bb1d3a 100644
+--- a/net/bluetooth/sco.c
++++ b/net/bluetooth/sco.c
+@@ -700,7 +700,6 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	    test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
+ 		sco_conn_defer_accept(pi->conn->hcon, 0);
+ 		sk->sk_state = BT_CONFIG;
+-		msg->msg_namelen = 0;
+ 
+ 		release_sock(sk);
+ 		return 0;
+diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
+index 05a41c7..d6be3ed 100644
+--- a/net/caif/caif_socket.c
++++ b/net/caif/caif_socket.c
+@@ -286,8 +286,6 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (m->msg_flags&MSG_OOB)
+ 		goto read_error;
+ 
+-	m->msg_namelen = 0;
+-
+ 	skb = skb_recv_datagram(sk, flags, 0 , &ret);
+ 	if (!skb)
+ 		goto read_error;
+@@ -361,8 +359,6 @@ static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (flags&MSG_OOB)
+ 		goto out;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	/*
+ 	 * Lock the socket to prevent queue disordering
+ 	 * while sleeps in memcpy_tomsg
+diff --git a/net/compat.c b/net/compat.c
+index 8903258..618c6a8 100644
+--- a/net/compat.c
++++ b/net/compat.c
+@@ -93,7 +93,8 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
+ 			if (err < 0)
+ 				return err;
+ 		}
+-		kern_msg->msg_name = kern_address;
++		if (kern_msg->msg_name)
++			kern_msg->msg_name = kern_address;
+ 	} else
+ 		kern_msg->msg_name = NULL;
+ 
+diff --git a/net/core/iovec.c b/net/core/iovec.c
+index de178e4..9a31515 100644
+--- a/net/core/iovec.c
++++ b/net/core/iovec.c
+@@ -48,7 +48,8 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a
+ 			if (err < 0)
+ 				return err;
+ 		}
+-		m->msg_name = address;
++		if (m->msg_name)
++			m->msg_name = address;
+ 	} else {
+ 		m->msg_name = NULL;
+ 	}
+diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
+index 7a1e0fc..e096025 100644
+--- a/net/ipx/af_ipx.c
++++ b/net/ipx/af_ipx.c
+@@ -1823,8 +1823,6 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (skb->tstamp.tv64)
+ 		sk->sk_stamp = skb->tstamp;
+ 
+-	msg->msg_namelen = sizeof(*sipx);
+-
+ 	if (sipx) {
+ 		sipx->sipx_family	= AF_IPX;
+ 		sipx->sipx_port		= ipx->ipx_source.sock;
+@@ -1832,6 +1830,7 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 		sipx->sipx_network	= IPX_SKB_CB(skb)->ipx_source_net;
+ 		sipx->sipx_type 	= ipx->ipx_type;
+ 		sipx->sipx_zero		= 0;
++		msg->msg_namelen	= sizeof(*sipx);
+ 	}
+ 	rc = copied;
+ 
+diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
+index 0578d4f..a5e62ef5 100644
+--- a/net/irda/af_irda.c
++++ b/net/irda/af_irda.c
+@@ -1385,8 +1385,6 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
+ 
+ 	IRDA_DEBUG(4, "%s()\n", __func__);
+ 
+-	msg->msg_namelen = 0;
+-
+ 	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+ 				flags & MSG_DONTWAIT, &err);
+ 	if (!skb)
+@@ -1451,8 +1449,6 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
+ 	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
+ 	timeo = sock_rcvtimeo(sk, noblock);
+ 
+-	msg->msg_namelen = 0;
+-
+ 	do {
+ 		int chunk;
+ 		struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue);
+diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
+index 168aff5..c4b7218 100644
+--- a/net/iucv/af_iucv.c
++++ b/net/iucv/af_iucv.c
+@@ -1324,8 +1324,6 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	int err = 0;
+ 	u32 offset;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	if ((sk->sk_state == IUCV_DISCONN) &&
+ 	    skb_queue_empty(&iucv->backlog_skb_q) &&
+ 	    skb_queue_empty(&sk->sk_receive_queue) &&
+diff --git a/net/key/af_key.c b/net/key/af_key.c
+index ab8bd2c..66f51c5 100644
+--- a/net/key/af_key.c
++++ b/net/key/af_key.c
+@@ -3623,7 +3623,6 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
+ 	if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
+ 		goto out;
+ 
+-	msg->msg_namelen = 0;
+ 	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
+ 	if (skb == NULL)
+ 		goto out;
+diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
+index 8c46b27..44441c0 100644
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -197,8 +197,6 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (sk->sk_state & PPPOX_BOUND)
+ 		goto end;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	err = 0;
+ 	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+ 				flags & MSG_DONTWAIT, &err);
+diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
+index 48aaa89..8870988 100644
+--- a/net/llc/af_llc.c
++++ b/net/llc/af_llc.c
+@@ -720,8 +720,6 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	int target;	/* Read at least this many bytes */
+ 	long timeo;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	lock_sock(sk);
+ 	copied = -ENOTCONN;
+ 	if (unlikely(sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN))
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index 0c61b59..90b654b 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -2317,8 +2317,6 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
+ 	}
+ #endif
+ 
+-	msg->msg_namelen = 0;
+-
+ 	copied = data_skb->len;
+ 	if (len < copied) {
+ 		msg->msg_flags |= MSG_TRUNC;
+diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
+index 698814b..53c19a3 100644
+--- a/net/netrom/af_netrom.c
++++ b/net/netrom/af_netrom.c
+@@ -1179,10 +1179,9 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 		sax->sax25_family = AF_NETROM;
+ 		skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call,
+ 			      AX25_ADDR_LEN);
++		msg->msg_namelen = sizeof(*sax);
+ 	}
+ 
+-	msg->msg_namelen = sizeof(*sax);
+-
+ 	skb_free_datagram(sk, skb);
+ 
+ 	release_sock(sk);
+diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
+index d308402..824c605 100644
+--- a/net/nfc/llcp_sock.c
++++ b/net/nfc/llcp_sock.c
+@@ -807,8 +807,6 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 
+ 	pr_debug("%p %zu\n", sk, len);
+ 
+-	msg->msg_namelen = 0;
+-
+ 	lock_sock(sk);
+ 
+ 	if (sk->sk_state == LLCP_CLOSED &&
+diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
+index 313bf1b..5d11f4a 100644
+--- a/net/nfc/rawsock.c
++++ b/net/nfc/rawsock.c
+@@ -241,8 +241,6 @@ static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (!skb)
+ 		return rc;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	copied = skb->len;
+ 	if (len < copied) {
+ 		msg->msg_flags |= MSG_TRUNC;
+diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
+index 75c8bbf..739c50d 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -2694,7 +2694,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	struct sock *sk = sock->sk;
+ 	struct sk_buff *skb;
+ 	int copied, err;
+-	struct sockaddr_ll *sll;
+ 	int vnet_hdr_len = 0;
+ 
+ 	err = -EINVAL;
+@@ -2777,22 +2776,10 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 			goto out_free;
+ 	}
+ 
+-	/*
+-	 *	If the address length field is there to be filled in, we fill
+-	 *	it in now.
+-	 */
+-
+-	sll = &PACKET_SKB_CB(skb)->sa.ll;
+-	if (sock->type == SOCK_PACKET)
+-		msg->msg_namelen = sizeof(struct sockaddr_pkt);
+-	else
+-		msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr);
+-
+-	/*
+-	 *	You lose any data beyond the buffer you gave. If it worries a
+-	 *	user program they can ask the device for its MTU anyway.
++	/* You lose any data beyond the buffer you gave. If it worries
++	 * a user program they can ask the device for its MTU
++	 * anyway.
+ 	 */
+-
+ 	copied = skb->len;
+ 	if (copied > len) {
+ 		copied = len;
+@@ -2805,9 +2792,20 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 
+ 	sock_recv_ts_and_drops(msg, sk, skb);
+ 
+-	if (msg->msg_name)
++	if (msg->msg_name) {
++		/* If the address length field is there to be filled
++		 * in, we fill it in now.
++		 */
++		if (sock->type == SOCK_PACKET) {
++			msg->msg_namelen = sizeof(struct sockaddr_pkt);
++		} else {
++			struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll;
++			msg->msg_namelen = sll->sll_halen +
++				offsetof(struct sockaddr_ll, sll_addr);
++		}
+ 		memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
+ 		       msg->msg_namelen);
++	}
+ 
+ 	if (pkt_sk(sk)->auxdata) {
+ 		struct tpacket_auxdata aux;
+diff --git a/net/rds/recv.c b/net/rds/recv.c
+index 9f0f17c..de339b2 100644
+--- a/net/rds/recv.c
++++ b/net/rds/recv.c
+@@ -410,8 +410,6 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+ 
+ 	rdsdebug("size %zu flags 0x%x timeo %ld\n", size, msg_flags, timeo);
+ 
+-	msg->msg_namelen = 0;
+-
+ 	if (msg_flags & MSG_OOB)
+ 		goto out;
+ 
+diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
+index e98fcfb..33af772 100644
+--- a/net/rose/af_rose.c
++++ b/net/rose/af_rose.c
+@@ -1216,7 +1216,6 @@ static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,
+ {
+ 	struct sock *sk = sock->sk;
+ 	struct rose_sock *rose = rose_sk(sk);
+-	struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name;
+ 	size_t copied;
+ 	unsigned char *asmptr;
+ 	struct sk_buff *skb;
+@@ -1252,8 +1251,11 @@ static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 
+ 	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ 
+-	if (srose != NULL) {
+-		memset(srose, 0, msg->msg_namelen);
++	if (msg->msg_name) {
++		struct sockaddr_rose *srose;
++
++		memset(msg->msg_name, 0, sizeof(struct full_sockaddr_rose));
++		srose = msg->msg_name;
+ 		srose->srose_family = AF_ROSE;
+ 		srose->srose_addr   = rose->dest_addr;
+ 		srose->srose_call   = rose->dest_call;
+diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c
+index 4b48687..898492a 100644
+--- a/net/rxrpc/ar-recvmsg.c
++++ b/net/rxrpc/ar-recvmsg.c
+@@ -143,10 +143,13 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 
+ 		/* copy the peer address and timestamp */
+ 		if (!continue_call) {
+-			if (msg->msg_name && msg->msg_namelen > 0)
++			if (msg->msg_name) {
++				size_t len =
++					sizeof(call->conn->trans->peer->srx);
+ 				memcpy(msg->msg_name,
+-				       &call->conn->trans->peer->srx,
+-				       sizeof(call->conn->trans->peer->srx));
++				       &call->conn->trans->peer->srx, len);
++				msg->msg_namelen = len;
++			}
+ 			sock_recv_ts_and_drops(msg, &rx->sk, skb);
+ 		}
+ 
+diff --git a/net/socket.c b/net/socket.c
+index 4b94643..5158ff7 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -1849,8 +1849,10 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
+ 	msg.msg_iov = &iov;
+ 	iov.iov_len = size;
+ 	iov.iov_base = ubuf;
+-	msg.msg_name = (struct sockaddr *)&address;
+-	msg.msg_namelen = sizeof(address);
++	/* Save some cycles and don't copy the address if not needed */
++	msg.msg_name = addr ? (struct sockaddr *)&address : NULL;
++	/* We assume all kernel code knows the size of sockaddr_storage */
++	msg.msg_namelen = 0;
+ 	if (sock->file->f_flags & O_NONBLOCK)
+ 		flags |= MSG_DONTWAIT;
+ 	err = sock_recvmsg(sock, &msg, size, flags);
+@@ -2230,16 +2232,14 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
+ 			goto out;
+ 	}
+ 
+-	/*
+-	 *      Save the user-mode address (verify_iovec will change the
+-	 *      kernel msghdr to use the kernel address space)
++	/* Save the user-mode address (verify_iovec will change the
++	 * kernel msghdr to use the kernel address space)
+ 	 */
+-
+ 	uaddr = (__force void __user *)msg_sys->msg_name;
+ 	uaddr_len = COMPAT_NAMELEN(msg);
+-	if (MSG_CMSG_COMPAT & flags) {
++	if (MSG_CMSG_COMPAT & flags)
+ 		err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
+-	} else
++	else
+ 		err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
+ 	if (err < 0)
+ 		goto out_freeiov;
+@@ -2248,6 +2248,9 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
+ 	cmsg_ptr = (unsigned long)msg_sys->msg_control;
+ 	msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
+ 
++	/* We assume all kernel code knows the size of sockaddr_storage */
++	msg_sys->msg_namelen = 0;
++
+ 	if (sock->file->f_flags & O_NONBLOCK)
+ 		flags |= MSG_DONTWAIT;
+ 	err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys,
+diff --git a/net/tipc/socket.c b/net/tipc/socket.c
+index 6cc7ddd..dffdbea 100644
+--- a/net/tipc/socket.c
++++ b/net/tipc/socket.c
+@@ -984,9 +984,6 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,
+ 		goto exit;
+ 	}
+ 
+-	/* will be updated in set_orig_addr() if needed */
+-	m->msg_namelen = 0;
+-
+ 	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+ restart:
+ 
+@@ -1095,9 +1092,6 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
+ 		goto exit;
+ 	}
+ 
+-	/* will be updated in set_orig_addr() if needed */
+-	m->msg_namelen = 0;
+-
+ 	target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
+ 	timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+ 
+diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
+index e64bbcf..6c66e8d 100644
+--- a/net/unix/af_unix.c
++++ b/net/unix/af_unix.c
+@@ -1762,7 +1762,6 @@ static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
+ {
+ 	struct unix_sock *u = unix_sk(sk);
+ 
+-	msg->msg_namelen = 0;
+ 	if (u->addr) {
+ 		msg->msg_namelen = u->addr->len;
+ 		memcpy(msg->msg_name, u->addr->name, u->addr->len);
+@@ -1786,8 +1785,6 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (flags&MSG_OOB)
+ 		goto out;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	err = mutex_lock_interruptible(&u->readlock);
+ 	if (err) {
+ 		err = sock_intr_errno(sock_rcvtimeo(sk, noblock));
+@@ -1927,8 +1924,6 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
+ 	timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
+ 
+-	msg->msg_namelen = 0;
+-
+ 	/* Lock the socket to prevent queue disordering
+ 	 * while sleeps in memcpy_tomsg
+ 	 */
+diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
+index 4d93346..16f721c 100644
+--- a/net/vmw_vsock/af_vsock.c
++++ b/net/vmw_vsock/af_vsock.c
+@@ -1663,8 +1663,6 @@ vsock_stream_recvmsg(struct kiocb *kiocb,
+ 	vsk = vsock_sk(sk);
+ 	err = 0;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	lock_sock(sk);
+ 
+ 	if (sk->sk_state != SS_CONNECTED) {
+diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
+index ffc11df..73ca104 100644
+--- a/net/vmw_vsock/vmci_transport.c
++++ b/net/vmw_vsock/vmci_transport.c
+@@ -1746,8 +1746,6 @@ static int vmci_transport_dgram_dequeue(struct kiocb *kiocb,
+ 	if (flags & MSG_OOB || flags & MSG_ERRQUEUE)
+ 		return -EOPNOTSUPP;
+ 
+-	msg->msg_namelen = 0;
+-
+ 	/* Retrieve the head sk_buff from the socket's receive queue. */
+ 	err = 0;
+ 	skb = skb_recv_datagram(&vsk->sk, flags, noblock, &err);
+diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
+index 45a3ab5..7622789 100644
+--- a/net/x25/af_x25.c
++++ b/net/x25/af_x25.c
+@@ -1340,10 +1340,9 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
+ 	if (sx25) {
+ 		sx25->sx25_family = AF_X25;
+ 		sx25->sx25_addr   = x25->dest_addr;
++		msg->msg_namelen = sizeof(*sx25);
+ 	}
+ 
+-	msg->msg_namelen = sizeof(struct sockaddr_x25);
+-
+ 	x25_check_rbuf(sk);
+ 	rc = copied;
+ out_free_dgram:
+-- 
+1.8.3.1
+


More information about the scm-commits mailing list