| From foo@baz Thu Jan 12 21:36:14 CET 2017 |
| From: Dave Jones <davej@codemonkey.org.uk> |
| Date: Thu, 22 Dec 2016 11:16:22 -0500 |
| Subject: ipv6: handle -EFAULT from skb_copy_bits |
| |
| From: Dave Jones <davej@codemonkey.org.uk> |
| |
| |
| [ Upstream commit a98f91758995cb59611e61318dddd8a6956b52c3 ] |
| |
| By setting certain socket options on ipv6 raw sockets, we can confuse the |
| length calculation in rawv6_push_pending_frames triggering a BUG_ON. |
| |
| RIP: 0010:[<ffffffff817c6390>] [<ffffffff817c6390>] rawv6_sendmsg+0xc30/0xc40 |
| RSP: 0018:ffff881f6c4a7c18 EFLAGS: 00010282 |
| RAX: 00000000fffffff2 RBX: ffff881f6c681680 RCX: 0000000000000002 |
| RDX: ffff881f6c4a7cf8 RSI: 0000000000000030 RDI: ffff881fed0f6a00 |
| RBP: ffff881f6c4a7da8 R08: 0000000000000000 R09: 0000000000000009 |
| R10: ffff881fed0f6a00 R11: 0000000000000009 R12: 0000000000000030 |
| R13: ffff881fed0f6a00 R14: ffff881fee39ba00 R15: ffff881fefa93a80 |
| |
| Call Trace: |
| [<ffffffff8118ba23>] ? unmap_page_range+0x693/0x830 |
| [<ffffffff81772697>] inet_sendmsg+0x67/0xa0 |
| [<ffffffff816d93f8>] sock_sendmsg+0x38/0x50 |
| [<ffffffff816d982f>] SYSC_sendto+0xef/0x170 |
| [<ffffffff816da27e>] SyS_sendto+0xe/0x10 |
| [<ffffffff81002910>] do_syscall_64+0x50/0xa0 |
| [<ffffffff817f7cbc>] entry_SYSCALL64_slow_path+0x25/0x25 |
| |
| Handle by jumping to the failure path if skb_copy_bits gets an EFAULT. |
| |
| Reproducer: |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| |
| #define LEN 504 |
| |
| int main(int argc, char* argv[]) |
| { |
| int fd; |
| int zero = 0; |
| char buf[LEN]; |
| |
| memset(buf, 0, LEN); |
| |
| fd = socket(AF_INET6, SOCK_RAW, 7); |
| |
| setsockopt(fd, SOL_IPV6, IPV6_CHECKSUM, &zero, 4); |
| setsockopt(fd, SOL_IPV6, IPV6_DSTOPTS, &buf, LEN); |
| |
| sendto(fd, buf, 1, 0, (struct sockaddr *) buf, 110); |
| } |
| |
| Signed-off-by: Dave Jones <davej@codemonkey.org.uk> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv6/raw.c | 6 +++++- |
| 1 file changed, 5 insertions(+), 1 deletion(-) |
| |
| --- a/net/ipv6/raw.c |
| +++ b/net/ipv6/raw.c |
| @@ -589,7 +589,11 @@ static int rawv6_push_pending_frames(str |
| } |
| |
| offset += skb_transport_offset(skb); |
| - BUG_ON(skb_copy_bits(skb, offset, &csum, 2)); |
| + err = skb_copy_bits(skb, offset, &csum, 2); |
| + if (err < 0) { |
| + ip6_flush_pending_frames(sk); |
| + goto out; |
| + } |
| |
| /* in case cksum was not initialized */ |
| if (unlikely(csum)) |