diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2013-11-17 22:20:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-11-18 15:12:03 -0500 |
commit | bceaa90240b6019ed73b49965eac7d167610be69 (patch) | |
tree | f68c10948efff147a7b987369f1e720ad76f411b | |
parent | bcd081a3aef1f7f3786067ae8dd26aaa1cf85153 (diff) |
inet: prevent leakage of uninitialized memory to user in recv syscalls
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>
-rw-r--r-- | net/ieee802154/dgram.c | 3 | ||||
-rw-r--r-- | net/ipv4/ping.c | 19 | ||||
-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, 17 insertions, 38 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 9afbdb19f4a2..aacefa0caa36 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -830,8 +830,6 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
830 | { | 830 | { |
831 | struct inet_sock *isk = inet_sk(sk); | 831 | struct inet_sock *isk = inet_sk(sk); |
832 | int family = sk->sk_family; | 832 | int family = sk->sk_family; |
833 | struct sockaddr_in *sin; | ||
834 | struct sockaddr_in6 *sin6; | ||
835 | struct sk_buff *skb; | 833 | struct sk_buff *skb; |
836 | int copied, err; | 834 | int copied, err; |
837 | 835 | ||
@@ -841,13 +839,6 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
841 | if (flags & MSG_OOB) | 839 | if (flags & MSG_OOB) |
842 | goto out; | 840 | goto out; |
843 | 841 | ||
844 | if (addr_len) { | ||
845 | if (family == AF_INET) | ||
846 | *addr_len = sizeof(*sin); | ||
847 | else if (family == AF_INET6 && addr_len) | ||
848 | *addr_len = sizeof(*sin6); | ||
849 | } | ||
850 | |||
851 | if (flags & MSG_ERRQUEUE) { | 842 | if (flags & MSG_ERRQUEUE) { |
852 | if (family == AF_INET) { | 843 | if (family == AF_INET) { |
853 | return ip_recv_error(sk, msg, len); | 844 | return ip_recv_error(sk, msg, len); |
@@ -877,11 +868,13 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
877 | 868 | ||
878 | /* Copy the address and add cmsg data. */ | 869 | /* Copy the address and add cmsg data. */ |
879 | if (family == AF_INET) { | 870 | if (family == AF_INET) { |
880 | sin = (struct sockaddr_in *) msg->msg_name; | 871 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; |
872 | |||
881 | sin->sin_family = AF_INET; | 873 | sin->sin_family = AF_INET; |
882 | sin->sin_port = 0 /* skb->h.uh->source */; | 874 | sin->sin_port = 0 /* skb->h.uh->source */; |
883 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 875 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
884 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); | 876 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); |
877 | *addr_len = sizeof(*sin); | ||
885 | 878 | ||
886 | if (isk->cmsg_flags) | 879 | if (isk->cmsg_flags) |
887 | ip_cmsg_recv(msg, skb); | 880 | ip_cmsg_recv(msg, skb); |
@@ -890,17 +883,19 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
890 | } else if (family == AF_INET6) { | 883 | } else if (family == AF_INET6) { |
891 | struct ipv6_pinfo *np = inet6_sk(sk); | 884 | struct ipv6_pinfo *np = inet6_sk(sk); |
892 | struct ipv6hdr *ip6 = ipv6_hdr(skb); | 885 | struct ipv6hdr *ip6 = ipv6_hdr(skb); |
893 | sin6 = (struct sockaddr_in6 *) msg->msg_name; | 886 | struct sockaddr_in6 *sin6 = |
887 | (struct sockaddr_in6 *)msg->msg_name; | ||
888 | |||
894 | sin6->sin6_family = AF_INET6; | 889 | sin6->sin6_family = AF_INET6; |
895 | sin6->sin6_port = 0; | 890 | sin6->sin6_port = 0; |
896 | sin6->sin6_addr = ip6->saddr; | 891 | sin6->sin6_addr = ip6->saddr; |
897 | |||
898 | sin6->sin6_flowinfo = 0; | 892 | sin6->sin6_flowinfo = 0; |
899 | if (np->sndflow) | 893 | if (np->sndflow) |
900 | sin6->sin6_flowinfo = ip6_flowinfo(ip6); | 894 | sin6->sin6_flowinfo = ip6_flowinfo(ip6); |
901 | 895 | ||
902 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, | 896 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, |
903 | IP6CB(skb)->iif); | 897 | IP6CB(skb)->iif); |
898 | *addr_len = sizeof(*sin6); | ||
904 | 899 | ||
905 | if (inet6_sk(sk)->rxopt.all) | 900 | if (inet6_sk(sk)->rxopt.all) |
906 | pingv6_ops.ip6_datagram_recv_ctl(sk, msg, skb); | 901 | pingv6_ops.ip6_datagram_recv_ctl(sk, msg, skb); |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 41e1d2845c8f..5cb8ddb505ee 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -696,9 +696,6 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
696 | if (flags & MSG_OOB) | 696 | if (flags & MSG_OOB) |
697 | goto out; | 697 | goto out; |
698 | 698 | ||
699 | if (addr_len) | ||
700 | *addr_len = sizeof(*sin); | ||
701 | |||
702 | if (flags & MSG_ERRQUEUE) { | 699 | if (flags & MSG_ERRQUEUE) { |
703 | err = ip_recv_error(sk, msg, len); | 700 | err = ip_recv_error(sk, msg, len); |
704 | goto out; | 701 | goto out; |
@@ -726,6 +723,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
726 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 723 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
727 | sin->sin_port = 0; | 724 | sin->sin_port = 0; |
728 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); | 725 | memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); |
726 | *addr_len = sizeof(*sin); | ||
729 | } | 727 | } |
730 | if (inet->cmsg_flags) | 728 | if (inet->cmsg_flags) |
731 | ip_cmsg_recv(msg, skb); | 729 | ip_cmsg_recv(msg, skb); |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 89909dd730dd..998431cd471a 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1235,12 +1235,6 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1235 | int is_udplite = IS_UDPLITE(sk); | 1235 | int is_udplite = IS_UDPLITE(sk); |
1236 | bool slow; | 1236 | bool slow; |
1237 | 1237 | ||
1238 | /* | ||
1239 | * Check any passed addresses | ||
1240 | */ | ||
1241 | if (addr_len) | ||
1242 | *addr_len = sizeof(*sin); | ||
1243 | |||
1244 | if (flags & MSG_ERRQUEUE) | 1238 | if (flags & MSG_ERRQUEUE) |
1245 | return ip_recv_error(sk, msg, len); | 1239 | return ip_recv_error(sk, msg, len); |
1246 | 1240 | ||
@@ -1302,6 +1296,7 @@ try_again: | |||
1302 | sin->sin_port = udp_hdr(skb)->source; | 1296 | sin->sin_port = udp_hdr(skb)->source; |
1303 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 1297 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
1304 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); | 1298 | memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); |
1299 | *addr_len = sizeof(*sin); | ||
1305 | } | 1300 | } |
1306 | if (inet->cmsg_flags) | 1301 | if (inet->cmsg_flags) |
1307 | ip_cmsg_recv(msg, skb); | 1302 | ip_cmsg_recv(msg, skb); |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 3c00842b0079..e24ff1df0401 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -465,9 +465,6 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
465 | if (flags & MSG_OOB) | 465 | if (flags & MSG_OOB) |
466 | return -EOPNOTSUPP; | 466 | return -EOPNOTSUPP; |
467 | 467 | ||
468 | if (addr_len) | ||
469 | *addr_len=sizeof(*sin6); | ||
470 | |||
471 | if (flags & MSG_ERRQUEUE) | 468 | if (flags & MSG_ERRQUEUE) |
472 | return ipv6_recv_error(sk, msg, len); | 469 | return ipv6_recv_error(sk, msg, len); |
473 | 470 | ||
@@ -506,6 +503,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
506 | sin6->sin6_flowinfo = 0; | 503 | sin6->sin6_flowinfo = 0; |
507 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, | 504 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, |
508 | IP6CB(skb)->iif); | 505 | IP6CB(skb)->iif); |
506 | *addr_len = sizeof(*sin6); | ||
509 | } | 507 | } |
510 | 508 | ||
511 | sock_recv_ts_and_drops(msg, sk, skb); | 509 | sock_recv_ts_and_drops(msg, sk, skb); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index f3893e897f72..81eb8cf8389b 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -392,9 +392,6 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
392 | int is_udp4; | 392 | int is_udp4; |
393 | bool slow; | 393 | bool slow; |
394 | 394 | ||
395 | if (addr_len) | ||
396 | *addr_len = sizeof(struct sockaddr_in6); | ||
397 | |||
398 | if (flags & MSG_ERRQUEUE) | 395 | if (flags & MSG_ERRQUEUE) |
399 | return ipv6_recv_error(sk, msg, len); | 396 | return ipv6_recv_error(sk, msg, len); |
400 | 397 | ||
@@ -480,7 +477,7 @@ try_again: | |||
480 | ipv6_iface_scope_id(&sin6->sin6_addr, | 477 | ipv6_iface_scope_id(&sin6->sin6_addr, |
481 | IP6CB(skb)->iif); | 478 | IP6CB(skb)->iif); |
482 | } | 479 | } |
483 | 480 | *addr_len = sizeof(*sin6); | |
484 | } | 481 | } |
485 | if (is_udp4) { | 482 | if (is_udp4) { |
486 | if (inet->cmsg_flags) | 483 | 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); |