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 /net/ipv4/ping.c | |
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>
Diffstat (limited to 'net/ipv4/ping.c')
-rw-r--r-- | net/ipv4/ping.c | 9 |
1 files changed, 4 insertions, 5 deletions
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); |