63 lines
2.0 KiB
Diff
63 lines
2.0 KiB
Diff
From: Eric Dumazet <edumazet@google.com>
|
|
Date: Fri, 19 May 2017 14:17:48 -0700
|
|
Subject: ipv6: fix out of bound writes in __ip6_append_data()
|
|
Origin: https://git.kernel.org/linus/232cd35d0804cc241eb887bb8d4d9b3b9881c64a
|
|
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2017-9242
|
|
|
|
Andrey Konovalov and idaifish@gmail.com reported crashes caused by
|
|
one skb shared_info being overwritten from __ip6_append_data()
|
|
|
|
Andrey program lead to following state :
|
|
|
|
copy -4200 datalen 2000 fraglen 2040
|
|
maxfraglen 2040 alloclen 2048 transhdrlen 0 offset 0 fraggap 6200
|
|
|
|
The skb_copy_and_csum_bits(skb_prev, maxfraglen, data + transhdrlen,
|
|
fraggap, 0); is overwriting skb->head and skb_shared_info
|
|
|
|
Since we apparently detect this rare condition too late, move the
|
|
code earlier to even avoid allocating skb and risking crashes.
|
|
|
|
Once again, many thanks to Andrey and syzkaller team.
|
|
|
|
Signed-off-by: Eric Dumazet <edumazet@google.com>
|
|
Reported-by: Andrey Konovalov <andreyknvl@google.com>
|
|
Tested-by: Andrey Konovalov <andreyknvl@google.com>
|
|
Reported-by: <idaifish@gmail.com>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
net/ipv6/ip6_output.c | 15 ++++++++-------
|
|
1 file changed, 8 insertions(+), 7 deletions(-)
|
|
|
|
--- a/net/ipv6/ip6_output.c
|
|
+++ b/net/ipv6/ip6_output.c
|
|
@@ -1448,6 +1448,11 @@ alloc_new_skb:
|
|
*/
|
|
alloclen += sizeof(struct frag_hdr);
|
|
|
|
+ copy = datalen - transhdrlen - fraggap;
|
|
+ if (copy < 0) {
|
|
+ err = -EINVAL;
|
|
+ goto error;
|
|
+ }
|
|
if (transhdrlen) {
|
|
skb = sock_alloc_send_skb(sk,
|
|
alloclen + hh_len,
|
|
@@ -1497,13 +1502,9 @@ alloc_new_skb:
|
|
data += fraggap;
|
|
pskb_trim_unique(skb_prev, maxfraglen);
|
|
}
|
|
- copy = datalen - transhdrlen - fraggap;
|
|
-
|
|
- if (copy < 0) {
|
|
- err = -EINVAL;
|
|
- kfree_skb(skb);
|
|
- goto error;
|
|
- } else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
|
|
+ if (copy > 0 &&
|
|
+ getfrag(from, data + transhdrlen, offset,
|
|
+ copy, fraggap, skb) < 0) {
|
|
err = -EFAULT;
|
|
kfree_skb(skb);
|
|
goto error;
|