| From: Eric Dumazet <edumazet@google.com> |
| Date: Wed, 2 Oct 2019 09:38:55 -0700 |
| Subject: ipv6: drop incoming packets having a v4mapped source address |
| |
| commit 6af1799aaf3f1bc8defedddfa00df3192445bbf3 upstream. |
| |
| This began with a syzbot report. syzkaller was injecting |
| IPv6 TCP SYN packets having a v4mapped source address. |
| |
| After an unsuccessful 4-tuple lookup, TCP creates a request |
| socket (SYN_RECV) and calls reqsk_queue_hash_req() |
| |
| reqsk_queue_hash_req() calls sk_ehashfn(sk) |
| |
| At this point we have AF_INET6 sockets, and the heuristic |
| used by sk_ehashfn() to either hash the IPv4 or IPv6 addresses |
| is to use ipv6_addr_v4mapped(&sk->sk_v6_daddr) |
| |
| For the particular spoofed packet, we end up hashing V4 addresses |
| which were not initialized by the TCP IPv6 stack, so KMSAN fired |
| a warning. |
| |
| I first fixed sk_ehashfn() to test both source and destination addresses, |
| but then faced various problems, including user-space programs |
| like packetdrill that had similar assumptions. |
| |
| Instead of trying to fix the whole ecosystem, it is better |
| to admit that we have a dual stack behavior, and that we |
| can not build linux kernels without V4 stack anyway. |
| |
| The dual stack API automatically forces the traffic to be IPv4 |
| if v4mapped addresses are used at bind() or connect(), so it makes |
| no sense to allow IPv6 traffic to use the same v4mapped class. |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Cc: Florian Westphal <fw@strlen.de> |
| Cc: Hannes Frederic Sowa <hannes@stressinduktion.org> |
| Reported-by: syzbot <syzkaller@googlegroups.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| net/ipv6/ip6_input.c | 10 ++++++++++ |
| 1 file changed, 10 insertions(+) |
| |
| --- a/net/ipv6/ip6_input.c |
| +++ b/net/ipv6/ip6_input.c |
| @@ -151,6 +151,16 @@ int ipv6_rcv(struct sk_buff *skb, struct |
| if (ipv6_addr_is_multicast(&hdr->saddr)) |
| goto err; |
| |
| + /* While RFC4291 is not explicit about v4mapped addresses |
| + * in IPv6 headers, it seems clear linux dual-stack |
| + * model can not deal properly with these. |
| + * Security models could be fooled by ::ffff:127.0.0.1 for example. |
| + * |
| + * https://tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02 |
| + */ |
| + if (ipv6_addr_v4mapped(&hdr->saddr)) |
| + goto err; |
| + |
| skb->transport_header = skb->network_header + sizeof(*hdr); |
| IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); |
| |