From 26ef1781a0f9d49d2eeb6d4e09c77509eb3264f7 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Dec 10 2013 13:52:45 +0000 Subject: CVE-2013-XXXX net: memory leak in recvmsg (rhbz 1039845 1039874) --- diff --git a/kernel.spec b/kernel.spec index e2e31df..16c5750 100644 --- a/kernel.spec +++ b/kernel.spec @@ -823,6 +823,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 @@ -1583,6 +1587,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 +- CVE-2013-XXXX net: memory leak in recvmsg (rhbz 1039845 1039874) + * Tue Dec 03 2013 Josh Boyer - Add patches to fix rfkill switch on Dell machines (rhbz 958826) 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 +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 +Suggested-by: Eric Dumazet +Signed-off-by: Hannes Frederic Sowa +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + 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 +