]>
Commit | Line | Data |
---|---|---|
07ff4eea GKH |
1 | From foo@baz Tue Apr 10 23:20:08 CEST 2018 |
2 | From: Paolo Abeni <pabeni@redhat.com> | |
3 | Date: Fri, 23 Mar 2018 14:47:30 +0100 | |
4 | Subject: ipv6: the entire IPv6 header chain must fit the first fragment | |
5 | ||
6 | From: Paolo Abeni <pabeni@redhat.com> | |
7 | ||
8 | ||
9 | [ Upstream commit 10b8a3de603df7b96004179b1b33b1708c76d144 ] | |
10 | ||
11 | While building ipv6 datagram we currently allow arbitrary large | |
12 | extheaders, even beyond pmtu size. The syzbot has found a way | |
13 | to exploit the above to trigger the following splat: | |
14 | ||
15 | kernel BUG at ./include/linux/skbuff.h:2073! | |
16 | invalid opcode: 0000 [#1] SMP KASAN | |
17 | Dumping ftrace buffer: | |
18 | (ftrace buffer empty) | |
19 | Modules linked in: | |
20 | CPU: 1 PID: 4230 Comm: syzkaller672661 Not tainted 4.16.0-rc2+ #326 | |
21 | Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS | |
22 | Google 01/01/2011 | |
23 | RIP: 0010:__skb_pull include/linux/skbuff.h:2073 [inline] | |
24 | RIP: 0010:__ip6_make_skb+0x1ac8/0x2190 net/ipv6/ip6_output.c:1636 | |
25 | RSP: 0018:ffff8801bc18f0f0 EFLAGS: 00010293 | |
26 | RAX: ffff8801b17400c0 RBX: 0000000000000738 RCX: ffffffff84f01828 | |
27 | RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8801b415ac18 | |
28 | RBP: ffff8801bc18f360 R08: ffff8801b4576844 R09: 0000000000000000 | |
29 | R10: ffff8801bc18f380 R11: ffffed00367aee4e R12: 00000000000000d6 | |
30 | R13: ffff8801b415a740 R14: dffffc0000000000 R15: ffff8801b45767c0 | |
31 | FS: 0000000001535880(0000) GS:ffff8801db300000(0000) knlGS:0000000000000000 | |
32 | CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | |
33 | CR2: 000000002000b000 CR3: 00000001b4123001 CR4: 00000000001606e0 | |
34 | DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 | |
35 | DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 | |
36 | Call Trace: | |
37 | ip6_finish_skb include/net/ipv6.h:969 [inline] | |
38 | udp_v6_push_pending_frames+0x269/0x3b0 net/ipv6/udp.c:1073 | |
39 | udpv6_sendmsg+0x2a96/0x3400 net/ipv6/udp.c:1343 | |
40 | inet_sendmsg+0x11f/0x5e0 net/ipv4/af_inet.c:764 | |
41 | sock_sendmsg_nosec net/socket.c:630 [inline] | |
42 | sock_sendmsg+0xca/0x110 net/socket.c:640 | |
43 | ___sys_sendmsg+0x320/0x8b0 net/socket.c:2046 | |
44 | __sys_sendmmsg+0x1ee/0x620 net/socket.c:2136 | |
45 | SYSC_sendmmsg net/socket.c:2167 [inline] | |
46 | SyS_sendmmsg+0x35/0x60 net/socket.c:2162 | |
47 | do_syscall_64+0x280/0x940 arch/x86/entry/common.c:287 | |
48 | entry_SYSCALL_64_after_hwframe+0x42/0xb7 | |
49 | RIP: 0033:0x4404c9 | |
50 | RSP: 002b:00007ffdce35f948 EFLAGS: 00000217 ORIG_RAX: 0000000000000133 | |
51 | RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 00000000004404c9 | |
52 | RDX: 0000000000000003 RSI: 0000000020001f00 RDI: 0000000000000003 | |
53 | RBP: 00000000006cb018 R08: 00000000004002c8 R09: 00000000004002c8 | |
54 | R10: 0000000020000080 R11: 0000000000000217 R12: 0000000000401df0 | |
55 | R13: 0000000000401e80 R14: 0000000000000000 R15: 0000000000000000 | |
56 | Code: ff e8 1d 5e b9 fc e9 15 e9 ff ff e8 13 5e b9 fc e9 44 e8 ff ff e8 29 | |
57 | 5e b9 fc e9 c0 e6 ff ff e8 3f f3 80 fc 0f 0b e8 38 f3 80 fc <0f> 0b 49 8d | |
58 | 87 80 00 00 00 4d 8d 87 84 00 00 00 48 89 85 20 fe | |
59 | RIP: __skb_pull include/linux/skbuff.h:2073 [inline] RSP: ffff8801bc18f0f0 | |
60 | RIP: __ip6_make_skb+0x1ac8/0x2190 net/ipv6/ip6_output.c:1636 RSP: | |
61 | ffff8801bc18f0f0 | |
62 | ||
63 | As stated by RFC 7112 section 5: | |
64 | ||
65 | When a host fragments an IPv6 datagram, it MUST include the entire | |
66 | IPv6 Header Chain in the First Fragment. | |
67 | ||
68 | So this patch addresses the issue dropping datagrams with excessive | |
69 | extheader length. It also updates the error path to report to the | |
70 | calling socket nonnegative pmtu values. | |
71 | ||
72 | The issue apparently predates git history. | |
73 | ||
74 | v1 -> v2: cleanup error path, as per Eric's suggestion | |
75 | ||
76 | Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") | |
77 | Reported-by: syzbot+91e6f9932ff122fa4410@syzkaller.appspotmail.com | |
78 | Signed-off-by: Paolo Abeni <pabeni@redhat.com> | |
79 | Reviewed-by: Eric Dumazet <edumazet@google.com> | |
80 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
81 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
82 | --- | |
83 | net/ipv6/ip6_output.c | 13 +++++++++---- | |
84 | 1 file changed, 9 insertions(+), 4 deletions(-) | |
85 | ||
86 | --- a/net/ipv6/ip6_output.c | |
87 | +++ b/net/ipv6/ip6_output.c | |
88 | @@ -1245,7 +1245,7 @@ static int __ip6_append_data(struct sock | |
89 | const struct sockcm_cookie *sockc) | |
90 | { | |
91 | struct sk_buff *skb, *skb_prev = NULL; | |
92 | - unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; | |
93 | + unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu; | |
94 | int exthdrlen = 0; | |
95 | int dst_exthdrlen = 0; | |
96 | int hh_len; | |
97 | @@ -1281,6 +1281,12 @@ static int __ip6_append_data(struct sock | |
98 | sizeof(struct frag_hdr) : 0) + | |
99 | rt->rt6i_nfheader_len; | |
100 | ||
101 | + /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit | |
102 | + * the first fragment | |
103 | + */ | |
104 | + if (headersize + transhdrlen > mtu) | |
105 | + goto emsgsize; | |
106 | + | |
107 | if (cork->length + length > mtu - headersize && ipc6->dontfrag && | |
108 | (sk->sk_protocol == IPPROTO_UDP || | |
109 | sk->sk_protocol == IPPROTO_RAW)) { | |
110 | @@ -1296,9 +1302,8 @@ static int __ip6_append_data(struct sock | |
111 | ||
112 | if (cork->length + length > maxnonfragsize - headersize) { | |
113 | emsgsize: | |
114 | - ipv6_local_error(sk, EMSGSIZE, fl6, | |
115 | - mtu - headersize + | |
116 | - sizeof(struct ipv6hdr)); | |
117 | + pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0); | |
118 | + ipv6_local_error(sk, EMSGSIZE, fl6, pmtu); | |
119 | return -EMSGSIZE; | |
120 | } | |
121 |