]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.14.34/ipv6-the-entire-ipv6-header-chain-must-fit-the-first-fragment.patch
Linux 4.14.95
[thirdparty/kernel/stable-queue.git] / releases / 4.14.34 / ipv6-the-entire-ipv6-header-chain-must-fit-the-first-fragment.patch
CommitLineData
07ff4eea
GKH
1From foo@baz Tue Apr 10 23:20:08 CEST 2018
2From: Paolo Abeni <pabeni@redhat.com>
3Date: Fri, 23 Mar 2018 14:47:30 +0100
4Subject: ipv6: the entire IPv6 header chain must fit the first fragment
5
6From: Paolo Abeni <pabeni@redhat.com>
7
8
9[ Upstream commit 10b8a3de603df7b96004179b1b33b1708c76d144 ]
10
11While building ipv6 datagram we currently allow arbitrary large
12extheaders, even beyond pmtu size. The syzbot has found a way
13to exploit the above to trigger the following splat:
14
15kernel BUG at ./include/linux/skbuff.h:2073!
16invalid opcode: 0000 [#1] SMP KASAN
17Dumping ftrace buffer:
18 (ftrace buffer empty)
19Modules linked in:
20CPU: 1 PID: 4230 Comm: syzkaller672661 Not tainted 4.16.0-rc2+ #326
21Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
22Google 01/01/2011
23RIP: 0010:__skb_pull include/linux/skbuff.h:2073 [inline]
24RIP: 0010:__ip6_make_skb+0x1ac8/0x2190 net/ipv6/ip6_output.c:1636
25RSP: 0018:ffff8801bc18f0f0 EFLAGS: 00010293
26RAX: ffff8801b17400c0 RBX: 0000000000000738 RCX: ffffffff84f01828
27RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8801b415ac18
28RBP: ffff8801bc18f360 R08: ffff8801b4576844 R09: 0000000000000000
29R10: ffff8801bc18f380 R11: ffffed00367aee4e R12: 00000000000000d6
30R13: ffff8801b415a740 R14: dffffc0000000000 R15: ffff8801b45767c0
31FS: 0000000001535880(0000) GS:ffff8801db300000(0000) knlGS:0000000000000000
32CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
33CR2: 000000002000b000 CR3: 00000001b4123001 CR4: 00000000001606e0
34DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
35DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
36Call 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
49RIP: 0033:0x4404c9
50RSP: 002b:00007ffdce35f948 EFLAGS: 00000217 ORIG_RAX: 0000000000000133
51RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 00000000004404c9
52RDX: 0000000000000003 RSI: 0000000020001f00 RDI: 0000000000000003
53RBP: 00000000006cb018 R08: 00000000004002c8 R09: 00000000004002c8
54R10: 0000000020000080 R11: 0000000000000217 R12: 0000000000401df0
55R13: 0000000000401e80 R14: 0000000000000000 R15: 0000000000000000
56Code: ff e8 1d 5e b9 fc e9 15 e9 ff ff e8 13 5e b9 fc e9 44 e8 ff ff e8 29
575e b9 fc e9 c0 e6 ff ff e8 3f f3 80 fc 0f 0b e8 38 f3 80 fc <0f> 0b 49 8d
5887 80 00 00 00 4d 8d 87 84 00 00 00 48 89 85 20 fe
59RIP: __skb_pull include/linux/skbuff.h:2073 [inline] RSP: ffff8801bc18f0f0
60RIP: __ip6_make_skb+0x1ac8/0x2190 net/ipv6/ip6_output.c:1636 RSP:
61ffff8801bc18f0f0
62
63As 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
68So this patch addresses the issue dropping datagrams with excessive
69extheader length. It also updates the error path to report to the
70calling socket nonnegative pmtu values.
71
72The issue apparently predates git history.
73
74v1 -> v2: cleanup error path, as per Eric's suggestion
75
76Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
77Reported-by: syzbot+91e6f9932ff122fa4410@syzkaller.appspotmail.com
78Signed-off-by: Paolo Abeni <pabeni@redhat.com>
79Reviewed-by: Eric Dumazet <edumazet@google.com>
80Signed-off-by: David S. Miller <davem@davemloft.net>
81Signed-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