[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