ip: zero sockaddr returned on error queue
authorWillem de Bruijn <willemb@google.com>
Thu, 15 Jan 2015 18:18:40 +0000 (13:18 -0500)
committerBen Hutchings <ben@decadent.org.uk>
Sat, 9 May 2015 22:16:36 +0000 (23:16 +0100)
[ Upstream commit f812116b174e59a350acc8e4856213a166a91222 ]

The sockaddr is returned in IP(V6)_RECVERR as part of errhdr. That
structure is defined and allocated on the stack as

    struct {
            struct sock_extended_err ee;
            struct sockaddr_in(6)    offender;
    } errhdr;

The second part is only initialized for certain SO_EE_ORIGIN values.
Always initialize it completely.

An MTU exceeded error on a SOCK_RAW/IPPROTO_RAW is one example that
would return uninitialized bytes.

Signed-off-by: Willem de Bruijn <willemb@google.com>
----

Also verified that there is no padding between errhdr.ee and
errhdr.offender that could leak additional kernel data.
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
net/ipv4/ip_sockglue.c
net/ipv6/datagram.c

index 542a9c1..043d882 100644 (file)
@@ -416,15 +416,11 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
 
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
-       sin->sin_family = AF_UNSPEC;
+       memset(sin, 0, sizeof(*sin));
        if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
        if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
-               struct inet_sock *inet = inet_sk(sk);
-
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
-               sin->sin_port = 0;
-               memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
-               if (inet->cmsg_flags)
+               if (inet_sk(sk)->cmsg_flags)
                        ip_cmsg_recv(msg, skb);
        }
 
                        ip_cmsg_recv(msg, skb);
        }
 
index 3c7c948..33719b7 100644 (file)
@@ -371,12 +371,10 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
 
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
-       sin->sin6_family = AF_UNSPEC;
+       memset(sin, 0, sizeof(*sin));
+
        if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
                sin->sin6_family = AF_INET6;
        if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
                sin->sin6_family = AF_INET6;
-               sin->sin6_flowinfo = 0;
-               sin->sin6_port = 0;
-               sin->sin6_scope_id = 0;
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr);
                        if (np->rxopt.all)
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr);
                        if (np->rxopt.all)
@@ -384,11 +382,9 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
                        if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
                                sin->sin6_scope_id = IP6CB(skb)->iif;
                } else {
                        if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
                                sin->sin6_scope_id = IP6CB(skb)->iif;
                } else {
-                       struct inet_sock *inet = inet_sk(sk);
-
                        ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
                                               &sin->sin6_addr);
                        ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
                                               &sin->sin6_addr);
-                       if (inet->cmsg_flags)
+                       if (inet_sk(sk)->cmsg_flags)
                                ip_cmsg_recv(msg, skb);
                }
        }
                                ip_cmsg_recv(msg, skb);
                }
        }