aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2017-05-19 17:17:48 -0400
committerDavid S. Miller <davem@davemloft.net>2017-05-22 11:47:44 -0400
commit232cd35d0804cc241eb887bb8d4d9b3b9881c64a (patch)
treec4c562db86e7f3c60775748ce696efc2a0b8b54b
parent6d18c732b95c0a9d35e9f978b4438bba15412284 (diff)
ipv6: fix out of bound writes in __ip6_append_data()
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>
-rw-r--r--net/ipv6/ip6_output.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index d4a31becbd25..bf8a58a1c32d 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1466,6 +1466,11 @@ alloc_new_skb:
1466 */ 1466 */
1467 alloclen += sizeof(struct frag_hdr); 1467 alloclen += sizeof(struct frag_hdr);
1468 1468
1469 copy = datalen - transhdrlen - fraggap;
1470 if (copy < 0) {
1471 err = -EINVAL;
1472 goto error;
1473 }
1469 if (transhdrlen) { 1474 if (transhdrlen) {
1470 skb = sock_alloc_send_skb(sk, 1475 skb = sock_alloc_send_skb(sk,
1471 alloclen + hh_len, 1476 alloclen + hh_len,
@@ -1515,13 +1520,9 @@ alloc_new_skb:
1515 data += fraggap; 1520 data += fraggap;
1516 pskb_trim_unique(skb_prev, maxfraglen); 1521 pskb_trim_unique(skb_prev, maxfraglen);
1517 } 1522 }
1518 copy = datalen - transhdrlen - fraggap; 1523 if (copy > 0 &&
1519 1524 getfrag(from, data + transhdrlen, offset,
1520 if (copy < 0) { 1525 copy, fraggap, skb) < 0) {
1521 err = -EINVAL;
1522 kfree_skb(skb);
1523 goto error;
1524 } else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
1525 err = -EFAULT; 1526 err = -EFAULT;
1526 kfree_skb(skb); 1527 kfree_skb(skb);
1527 goto error; 1528 goto error;