]>
Commit | Line | Data |
---|---|---|
531d7425 GKH |
1 | From foo@baz Sun 09 Jun 2019 09:44:19 AM CEST |
2 | From: Olivier Matz <olivier.matz@6wind.com> | |
3 | Date: Thu, 6 Jun 2019 09:15:19 +0200 | |
4 | Subject: ipv6: fix EFAULT on sendto with icmpv6 and hdrincl | |
5 | ||
6 | From: Olivier Matz <olivier.matz@6wind.com> | |
7 | ||
8 | [ Upstream commit b9aa52c4cb457e7416cc0c95f475e72ef4a61336 ] | |
9 | ||
10 | The following code returns EFAULT (Bad address): | |
11 | ||
12 | s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); | |
13 | setsockopt(s, SOL_IPV6, IPV6_HDRINCL, 1); | |
14 | sendto(ipv6_icmp6_packet, addr); /* returns -1, errno = EFAULT */ | |
15 | ||
16 | The IPv4 equivalent code works. A workaround is to use IPPROTO_RAW | |
17 | instead of IPPROTO_ICMPV6. | |
18 | ||
19 | The failure happens because 2 bytes are eaten from the msghdr by | |
20 | rawv6_probe_proto_opt() starting from commit 19e3c66b52ca ("ipv6 | |
21 | equivalent of "ipv4: Avoid reading user iov twice after | |
22 | raw_probe_proto_opt""), but at that time it was not a problem because | |
23 | IPV6_HDRINCL was not yet introduced. | |
24 | ||
25 | Only eat these 2 bytes if hdrincl == 0. | |
26 | ||
27 | Fixes: 715f504b1189 ("ipv6: add IPV6_HDRINCL option for raw sockets") | |
28 | Signed-off-by: Olivier Matz <olivier.matz@6wind.com> | |
29 | Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> | |
30 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
31 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
32 | --- | |
33 | net/ipv6/raw.c | 13 ++++++++----- | |
34 | 1 file changed, 8 insertions(+), 5 deletions(-) | |
35 | ||
36 | --- a/net/ipv6/raw.c | |
37 | +++ b/net/ipv6/raw.c | |
38 | @@ -889,11 +889,14 @@ static int rawv6_sendmsg(struct sock *sk | |
39 | opt = ipv6_fixup_options(&opt_space, opt); | |
40 | ||
41 | fl6.flowi6_proto = proto; | |
42 | - rfv.msg = msg; | |
43 | - rfv.hlen = 0; | |
44 | - err = rawv6_probe_proto_opt(&rfv, &fl6); | |
45 | - if (err) | |
46 | - goto out; | |
47 | + | |
48 | + if (!hdrincl) { | |
49 | + rfv.msg = msg; | |
50 | + rfv.hlen = 0; | |
51 | + err = rawv6_probe_proto_opt(&rfv, &fl6); | |
52 | + if (err) | |
53 | + goto out; | |
54 | + } | |
55 | ||
56 | if (!ipv6_addr_any(daddr)) | |
57 | fl6.daddr = *daddr; |