ipv6: fix EFAULT on sendto with icmpv6 and hdrincl

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 19e3c66b52 ("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: 715f504b11 ("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>
This commit is contained in:
Olivier Matz 2019-06-06 09:15:19 +02:00 committed by David S. Miller
parent 59e3e4b526
commit b9aa52c4cb
1 changed files with 8 additions and 5 deletions

View File

@ -895,11 +895,14 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
opt = ipv6_fixup_options(&opt_space, opt); opt = ipv6_fixup_options(&opt_space, opt);
fl6.flowi6_proto = proto; fl6.flowi6_proto = proto;
rfv.msg = msg;
rfv.hlen = 0; if (!hdrincl) {
err = rawv6_probe_proto_opt(&rfv, &fl6); rfv.msg = msg;
if (err) rfv.hlen = 0;
goto out; err = rawv6_probe_proto_opt(&rfv, &fl6);
if (err)
goto out;
}
if (!ipv6_addr_any(daddr)) if (!ipv6_addr_any(daddr))
fl6.daddr = *daddr; fl6.daddr = *daddr;