aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2013-11-20 21:14:22 -0500
committerDavid S. Miller <davem@davemloft.net>2013-11-20 21:52:30 -0500
commitf3d3342602f8bcbf37d7c46641cb9bca7618eb1c (patch)
tree11aebad9cca99426db27130b19417141259c81f4
parentf873042093c0b418d2351fe142222b625c740149 (diff)
net: rework recvmsg handler msg_name and msg_namelen logic
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@davemloft.net> Suggested-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--crypto/algif_hash.c2
-rw-r--r--crypto/algif_skcipher.c1
-rw-r--r--drivers/isdn/mISDN/socket.c13
-rw-r--r--drivers/net/ppp/pppoe.c2
-rw-r--r--include/linux/net.h8
-rw-r--r--net/appletalk/ddp.c16
-rw-r--r--net/atm/common.c2
-rw-r--r--net/ax25/af_ax25.c4
-rw-r--r--net/bluetooth/af_bluetooth.c9
-rw-r--r--net/bluetooth/hci_sock.c2
-rw-r--r--net/bluetooth/rfcomm/sock.c1
-rw-r--r--net/bluetooth/sco.c1
-rw-r--r--net/caif/caif_socket.c4
-rw-r--r--net/compat.c3
-rw-r--r--net/core/iovec.c3
-rw-r--r--net/ipx/af_ipx.c3
-rw-r--r--net/irda/af_irda.c4
-rw-r--r--net/iucv/af_iucv.c2
-rw-r--r--net/key/af_key.c1
-rw-r--r--net/l2tp/l2tp_ppp.c2
-rw-r--r--net/llc/af_llc.c2
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/netrom/af_netrom.c3
-rw-r--r--net/nfc/llcp_sock.c2
-rw-r--r--net/nfc/rawsock.c2
-rw-r--r--net/packet/af_packet.c32
-rw-r--r--net/rds/recv.c2
-rw-r--r--net/rose/af_rose.c8
-rw-r--r--net/rxrpc/ar-recvmsg.c9
-rw-r--r--net/socket.c19
-rw-r--r--net/tipc/socket.c6
-rw-r--r--net/unix/af_unix.c5
-rw-r--r--net/vmw_vsock/af_vsock.c2
-rw-r--r--net/vmw_vsock/vmci_transport.c2
-rw-r--r--net/x25/af_x25.c3
35 files changed, 67 insertions, 115 deletions
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index 0262210cad38..ef5356cd280a 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,
161 else if (len < ds) 161 else if (len < ds)
162 msg->msg_flags |= MSG_TRUNC; 162 msg->msg_flags |= MSG_TRUNC;
163 163
164 msg->msg_namelen = 0;
165
166 lock_sock(sk); 164 lock_sock(sk);
167 if (ctx->more) { 165 if (ctx->more) {
168 ctx->more = 0; 166 ctx->more = 0;
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index a1c4f0a55583..6a6dfc062d2a 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,
432 long copied = 0; 432 long copied = 0;
433 433
434 lock_sock(sk); 434 lock_sock(sk);
435 msg->msg_namelen = 0;
436 for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0; 435 for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
437 iovlen--, iov++) { 436 iovlen--, iov++) {
438 unsigned long seglen = iov->iov_len; 437 unsigned long seglen = iov->iov_len;
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index e47dcb9d1e91..5cefb479c707 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,
117{ 117{
118 struct sk_buff *skb; 118 struct sk_buff *skb;
119 struct sock *sk = sock->sk; 119 struct sock *sk = sock->sk;
120 struct sockaddr_mISDN *maddr;
121 120
122 int copied, err; 121 int copied, err;
123 122
@@ -135,9 +134,9 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
135 if (!skb) 134 if (!skb)
136 return err; 135 return err;
137 136
138 if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { 137 if (msg->msg_name) {
139 msg->msg_namelen = sizeof(struct sockaddr_mISDN); 138 struct sockaddr_mISDN *maddr = msg->msg_name;
140 maddr = (struct sockaddr_mISDN *)msg->msg_name; 139
141 maddr->family = AF_ISDN; 140 maddr->family = AF_ISDN;
142 maddr->dev = _pms(sk)->dev->id; 141 maddr->dev = _pms(sk)->dev->id;
143 if ((sk->sk_protocol == ISDN_P_LAPD_TE) || 142 if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
@@ -150,11 +149,7 @@ mISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
150 maddr->sapi = _pms(sk)->ch.addr & 0xFF; 149 maddr->sapi = _pms(sk)->ch.addr & 0xFF;
151 maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; 150 maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF;
152 } 151 }
153 } else { 152 msg->msg_namelen = sizeof(*maddr);
154 if (msg->msg_namelen)
155 printk(KERN_WARNING "%s: too small namelen %d\n",
156 __func__, msg->msg_namelen);
157 msg->msg_namelen = 0;
158 } 153 }
159 154
160 copied = skb->len + MISDN_HEADER_LEN; 155 copied = skb->len + MISDN_HEADER_LEN;
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 5f66e30d9823..82ee6ed954cb 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,
979 if (error < 0) 979 if (error < 0)
980 goto end; 980 goto end;
981 981
982 m->msg_namelen = 0;
983
984 if (skb) { 982 if (skb) {
985 total_len = min_t(size_t, total_len, skb->len); 983 total_len = min_t(size_t, total_len, skb->len);
986 error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len); 984 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 b292a0435571..4bcee94cef93 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -164,6 +164,14 @@ struct proto_ops {
164#endif 164#endif
165 int (*sendmsg) (struct kiocb *iocb, struct socket *sock, 165 int (*sendmsg) (struct kiocb *iocb, struct socket *sock,
166 struct msghdr *m, size_t total_len); 166 struct msghdr *m, size_t total_len);
167 /* Notes for implementing recvmsg:
168 * ===============================
169 * msg->msg_namelen should get updated by the recvmsg handlers
170 * iff msg_name != NULL. It is by default 0 to prevent
171 * returning uninitialized memory to user space. The recvfrom
172 * handlers can assume that msg.msg_name is either NULL or has
173 * a minimum size of sizeof(struct sockaddr_storage).
174 */
167 int (*recvmsg) (struct kiocb *iocb, struct socket *sock, 175 int (*recvmsg) (struct kiocb *iocb, struct socket *sock,
168 struct msghdr *m, size_t total_len, 176 struct msghdr *m, size_t total_len,
169 int flags); 177 int flags);
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 7fee50d637f9..7d424ac6e760 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
1735 size_t size, int flags) 1735 size_t size, int flags)
1736{ 1736{
1737 struct sock *sk = sock->sk; 1737 struct sock *sk = sock->sk;
1738 struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
1739 struct ddpehdr *ddp; 1738 struct ddpehdr *ddp;
1740 int copied = 0; 1739 int copied = 0;
1741 int offset = 0; 1740 int offset = 0;
@@ -1764,14 +1763,13 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
1764 } 1763 }
1765 err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied); 1764 err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
1766 1765
1767 if (!err) { 1766 if (!err && msg->msg_name) {
1768 if (sat) { 1767 struct sockaddr_at *sat = msg->msg_name;
1769 sat->sat_family = AF_APPLETALK; 1768 sat->sat_family = AF_APPLETALK;
1770 sat->sat_port = ddp->deh_sport; 1769 sat->sat_port = ddp->deh_sport;
1771 sat->sat_addr.s_node = ddp->deh_snode; 1770 sat->sat_addr.s_node = ddp->deh_snode;
1772 sat->sat_addr.s_net = ddp->deh_snet; 1771 sat->sat_addr.s_net = ddp->deh_snet;
1773 } 1772 msg->msg_namelen = sizeof(*sat);
1774 msg->msg_namelen = sizeof(*sat);
1775 } 1773 }
1776 1774
1777 skb_free_datagram(sk, skb); /* Free the datagram. */