diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2013-11-17 22:20:45 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-12-08 10:29:25 -0500 |
commit | a2214488937a84d8d0b5a3b546f97b2485029a17 (patch) | |
tree | 533a832124d21321da8413805ee548886bcbf0b1 | |
parent | ac6a5b926d2d8df1596f7cb91f46afc18e5e39f9 (diff) |
inet: prevent leakage of uninitialized memory to user in recv syscalls
[ Upstream commit bceaa90240b6019ed73b49965eac7d167610be69 ]
Only update *addr_len when we actually fill in sockaddr, otherwise we
can return uninitialized memory from the stack to the caller in the
recvfrom, recvmmsg and recvmsg syscalls. Drop the the (addr_len == NULL)
checks because we only get called with a valid addr_len pointer either
from sock_common_recvmsg or inet_recvmsg.
If a blocking read waits on a socket which is concurrently shut down we
now return zero and set msg_msgnamelen to 0.
Reported-by: mpb <mpb.mail@gmail.com>
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | net/ieee802154/dgram.c | 3 | ||||
-rw-r--r-- | net/ipv4/ping.c | 9 | ||||
-rw-r--r-- | net/ipv4/raw.c | 4 | ||||
-rw-r--r-- | net/ipv4/udp.c | 7 | ||||
-rw-r--r-- | net/ipv6/raw.c | 4 | ||||
-rw-r--r-- | net/ipv6/udp.c | 5 | ||||
-rw-r--r-- | net/l2tp/l2tp_ip.c | 4 | ||||
-rw-r--r-- | net/phonet/datagram.c | 9 |
8 files changed, 14 insertions, 31 deletions
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 581a59504bd5..1865fdf5a5a5 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c | |||
@@ -315,9 +315,8 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
315 | if (saddr) { | 315 | if (saddr) { |
316 | saddr->family = AF_IEEE802154; | 316 | saddr->family = AF_IEEE802154; |
317 | saddr->addr = mac_cb(skb)->sa; | 317 | saddr->addr = mac_cb(skb)->sa; |
318 | } | ||
319 | if (addr_len) | ||
320 | *addr_len = sizeof(*saddr); | 318 | *addr_len = sizeof(*saddr); |
319 | } | ||
321 | 320 | ||
322 | if (flags & MSG_TRUNC) | 321 | if (flags & MSG_TRUNC) |
323 | copied = skb->len; | 322 | copied = skb->len; |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 7d93d62cd5fd..be01d5b8571a 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -626,7 +626,6 @@ static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
626 | size_t len, int noblock, int flags, int *addr_len) | 626 | size_t len, int noblock, int flags, int *addr_len) |
627 | { | 627 | { |
628 | struct inet_sock *isk = inet_sk(sk); | 628 | struct inet_sock *isk = inet_sk(sk); |
629 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | ||
630 | struct sk_buff *skb; | 629 | struct sk_buff *skb; |
631 | int copied, err; | 630 | int copied, err; |
632 | 631 | ||
@@ -636,9 +635,6 @@ static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
636 | if (flags & MSG_OOB) | 635 | if (flags & MSG_OOB) |
637 | goto out; | 636 | goto out; |
638 | 637 | ||
639 | if (addr_len) | ||
640 | *addr_len = sizeof(*sin); | ||
641 | |||
642 | if (flags & MSG_ERRQUEUE) | 638 | if (flags & MSG_ERRQUEUE) |
643 | return ip_recv_error(sk, msg, len); | 639 | return ip_recv_error(sk, msg, len); |
644 | 640 | ||
@@ -660,11 +656,14 @@ static int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
660 | sock_recv_timestamp(msg, sk, skb); | 656 | sock_recv_timestamp(msg, sk, skb); |
661 | 657 | ||
662 | /* Copy the address. */ | 658 | /* Copy the address. */ |
663 | if (sin) { | 659 | if (msg->msg_name) { |
660 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | ||
661 | |||
664 | sin->sin_family = AF_INET; | 662 | sin->sin_family = AF_INET; |
665 | sin->sin_port = 0 /* skb->h.uh->source */; | 663 | sin->sin_port = 0 /* skb->h.uh->source */; |
666 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 664 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
667 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); | 665 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); |
666 | *addr_len = sizeof(*sin); | ||
668 | } | 667 | } |
669 | if (isk->cmsg_flags) | 668 | if (isk->cmsg_flags) |
670 | ip_cmsg_recv(msg, skb); | 669 | ip_cmsg_recv(msg, skb); |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 6fb233772f79..448e5a77fa88 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -692,9 +692,6 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
692 | if (flags & MSG_OOB) | 692 | if (flags & MSG_OOB) |
693 | goto out; | 693 | goto out; |
694 | 694 | ||
695 | if (addr_len) | ||
696 | *addr_len = sizeof(*sin); | ||
697 | |||
698 | if (flags & MSG_ERRQUEUE) { | 695 | if (flags & MSG_ERRQUEUE) { |
699 | err = ip_recv_error(sk, msg, len); | 696 | err = ip_recv_error(sk, msg, len); |
700 | goto out; | 697 | goto out; |
@@ -722,6 +719,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
722 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 719 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
723 | sin->sin_port = 0; | 720 | sin->sin_port = 0; |
724 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); | 721 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); |
722 | *addr_len = sizeof(*sin); | ||
725 | } | 723 | } |
726 | if (inet->cmsg_flags) | 724 | if (inet->cmsg_flags) |
727 | ip_cmsg_recv(msg, skb); | 725 | ip_cmsg_recv(msg, skb); |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 93b731d53221..eeb3474daa3f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1207,12 +1207,6 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1207 | int is_udplite = IS_UDPLITE(sk); | 1207 | int is_udplite = IS_UDPLITE(sk); |
1208 | bool slow; | 1208 | bool slow; |
1209 | 1209 | ||
1210 | /* | ||
1211 | * Check any passed addresses | ||
1212 | */ | ||
1213 | if (addr_len) | ||
1214 | *addr_len = sizeof(*sin); | ||
1215 | |||
1216 | if (flags & MSG_ERRQUEUE) | 1210 | if (flags & MSG_ERRQUEUE) |
1217 | return ip_recv_error(sk, msg, len); | 1211 | return ip_recv_error(sk, msg, len); |
1218 | 1212 | ||
@@ -1274,6 +1268,7 @@ try_again: | |||
1274 | sin->sin_port = udp_hdr(skb)->source; | 1268 | sin->sin_port = udp_hdr(skb)->source; |
1275 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 1269 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
1276 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); | 1270 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); |
1271 | *addr_len = sizeof(*sin); | ||
1277 | } | 1272 | } |
1278 | if (inet->cmsg_flags) | 1273 | if (inet->cmsg_flags) |
1279 | ip_cmsg_recv(msg, skb); | 1274 | ip_cmsg_recv(msg, skb); |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index eedff8ccded5..d3c01a601955 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -459,9 +459,6 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
459 | if (flags & MSG_OOB) | 459 | if (flags & MSG_OOB) |
460 | return -EOPNOTSUPP; | 460 | return -EOPNOTSUPP; |
461 | 461 | ||
462 | if (addr_len) | ||
463 | *addr_len=sizeof(*sin6); | ||
464 | |||
465 | if (flags & MSG_ERRQUEUE) | 462 | if (flags & MSG_ERRQUEUE) |
466 | return ipv6_recv_error(sk, msg, len); | 463 | return ipv6_recv_error(sk, msg, len); |
467 | 464 | ||
@@ -500,6 +497,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
500 | sin6->sin6_flowinfo = 0; | 497 | sin6->sin6_flowinfo = 0; |
501 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, | 498 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, |
502 | IP6CB(skb)->iif); | 499 | IP6CB(skb)->iif); |
500 | *addr_len = sizeof(*sin6); | ||
503 | } | 501 | } |
504 | 502 | ||
505 | sock_recv_ts_and_drops(msg, sk, skb); | 503 | sock_recv_ts_and_drops(msg, sk, skb); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index e7b28f9bb02b..f10f1186da0b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -373,9 +373,6 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
373 | int is_udp4; | 373 | int is_udp4; |
374 | bool slow; | 374 | bool slow; |
375 | 375 | ||
376 | if (addr_len) | ||
377 | *addr_len = sizeof(struct sockaddr_in6); | ||
378 | |||
379 | if (flags & MSG_ERRQUEUE) | 376 | if (flags & MSG_ERRQUEUE) |
380 | return ipv6_recv_error(sk, msg, len); | 377 | return ipv6_recv_error(sk, msg, len); |
381 | 378 | ||
@@ -461,7 +458,7 @@ try_again: | |||
461 | ipv6_iface_scope_id(&sin6->sin6_addr, | 458 | ipv6_iface_scope_id(&sin6->sin6_addr, |
462 | IP6CB(skb)->iif); | 459 | IP6CB(skb)->iif); |
463 | } | 460 | } |
464 | 461 | *addr_len = sizeof(*sin6); | |
465 | } | 462 | } |
466 | if (is_udp4) { | 463 | if (is_udp4) { |
467 | if (inet->cmsg_flags) | 464 | if (inet->cmsg_flags) |
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 571db8dd2292..da1a1cee1a08 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -518,9 +518,6 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
518 | if (flags & MSG_OOB) | 518 | if (flags & MSG_OOB) |
519 | goto out; | 519 | goto out; |
520 | 520 | ||
521 | if (addr_len) | ||
522 | *addr_len = sizeof(*sin); | ||
523 | |||
524 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 521 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
525 | if (!skb) | 522 | if (!skb) |
526 | goto out; | 523 | goto out; |
@@ -543,6 +540,7 @@ static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m | |||
543 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 540 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
544 | sin->sin_port = 0; | 541 | sin->sin_port = 0; |
545 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); | 542 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); |
543 | *addr_len = sizeof(*sin); | ||
546 | } | 544 | } |
547 | if (inet->cmsg_flags) | 545 | if (inet->cmsg_flags) |
548 | ip_cmsg_recv(msg, skb); | 546 | ip_cmsg_recv(msg, skb); |
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c index 12c30f3e643e..38946b26e471 100644 --- a/net/phonet/datagram.c +++ b/net/phonet/datagram.c | |||
@@ -139,9 +139,6 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
139 | MSG_CMSG_COMPAT)) | 139 | MSG_CMSG_COMPAT)) |
140 | goto out_nofree; | 140 | goto out_nofree; |
141 | 141 | ||
142 | if (addr_len) | ||
143 | *addr_len = sizeof(sa); | ||
144 | |||
145 | skb = skb_recv_datagram(sk, flags, noblock, &rval); | 142 | skb = skb_recv_datagram(sk, flags, noblock, &rval); |
146 | if (skb == NULL) | 143 | if (skb == NULL) |
147 | goto out_nofree; | 144 | goto out_nofree; |
@@ -162,8 +159,10 @@ static int pn_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
162 | 159 | ||
163 | rval = (flags & MSG_TRUNC) ? skb->len : copylen; | 160 | rval = (flags & MSG_TRUNC) ? skb->len : copylen; |
164 | 161 | ||
165 | if (msg->msg_name != NULL) | 162 | if (msg->msg_name != NULL) { |
166 | memcpy(msg->msg_name, &sa, sizeof(struct sockaddr_pn)); | 163 | memcpy(msg->msg_name, &sa, sizeof(sa)); |
164 | *addr_len = sizeof(sa); | ||
165 | } | ||
167 | 166 | ||
168 | out: | 167 | out: |
169 | skb_free_datagram(sk, skb); | 168 | skb_free_datagram(sk, skb); |