summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorOlivier Matz <olivier.matz@6wind.com>2019-06-06 09:15:19 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-06-11 12:21:46 +0200
commit4b83a95655b800350281421f0e64c6d17b3d18db (patch)
tree5cd27116ac1ce68dc1dda004922a37c426f3d174 /net
parentb23be64f1e05da4ba3f37414f3422b5c2fb0d551 (diff)
ipv6: fix EFAULT on sendto with icmpv6 and hdrincl
[ Upstream commit b9aa52c4cb457e7416cc0c95f475e72ef4a61336 ] The following code returns EFAULT (Bad address): s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); setsockopt(s, SOL_IPV6, IPV6_HDRINCL, 1); sendto(ipv6_icmp6_packet, addr); /* returns -1, errno = EFAULT */ The IPv4 equivalent code works. A workaround is to use IPPROTO_RAW instead of IPPROTO_ICMPV6. The failure happens because 2 bytes are eaten from the msghdr by rawv6_probe_proto_opt() starting from commit 19e3c66b52ca ("ipv6 equivalent of "ipv4: Avoid reading user iov twice after raw_probe_proto_opt""), but at that time it was not a problem because IPV6_HDRINCL was not yet introduced. Only eat these 2 bytes if hdrincl == 0. Fixes: 715f504b1189 ("ipv6: add IPV6_HDRINCL option for raw sockets") Signed-off-by: Olivier Matz <olivier.matz@6wind.com> Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/raw.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 8f409031d245..ab315fe26a05 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -889,11 +889,14 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
opt = ipv6_fixup_options(&opt_space, opt);
fl6.flowi6_proto = proto;
- rfv.msg = msg;
- rfv.hlen = 0;
- err = rawv6_probe_proto_opt(&rfv, &fl6);
- if (err)
- goto out;
+
+ if (!hdrincl) {
+ rfv.msg = msg;
+ rfv.hlen = 0;
+ err = rawv6_probe_proto_opt(&rfv, &fl6);
+ if (err)
+ goto out;
+ }
if (!ipv6_addr_any(daddr))
fl6.daddr = *daddr;