Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/crypto/dist/ipsec-tools/src/racoon PR/51682: Avoid DoS with ...



details:   https://anonhg.NetBSD.org/src/rev/96f50dc60a1c
branches:  trunk
changeset: 821099:96f50dc60a1c
user:      christos <christos%NetBSD.org@localhost>
date:      Tue Jan 24 19:23:31 2017 +0000

description:
PR/51682: Avoid DoS with fragment out of order insertion; keep fragments
sorted in the list.

diffstat:

 crypto/dist/ipsec-tools/src/racoon/handler.h     |   3 +-
 crypto/dist/ipsec-tools/src/racoon/isakmp.c      |   4 +-
 crypto/dist/ipsec-tools/src/racoon/isakmp_frag.c |  97 +++++++++++++++--------
 crypto/dist/ipsec-tools/src/racoon/isakmp_inf.c  |   3 +-
 4 files changed, 71 insertions(+), 36 deletions(-)

diffs (201 lines):

diff -r adbb73113774 -r 96f50dc60a1c crypto/dist/ipsec-tools/src/racoon/handler.h
--- a/crypto/dist/ipsec-tools/src/racoon/handler.h      Tue Jan 24 18:37:20 2017 +0000
+++ b/crypto/dist/ipsec-tools/src/racoon/handler.h      Tue Jan 24 19:23:31 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: handler.h,v 1.25 2010/11/17 10:40:41 tteras Exp $      */
+/*     $NetBSD: handler.h,v 1.26 2017/01/24 19:23:56 christos Exp $    */
 
 /* Id: handler.h,v 1.19 2006/02/25 08:25:12 manubsd Exp */
 
@@ -141,6 +141,7 @@
 #endif
 #ifdef ENABLE_FRAG
        int frag;                       /* IKE phase 1 fragmentation */
+       int frag_last_index;
        struct isakmp_frag_item *frag_chain;    /* Received fragments */
 #endif
 
diff -r adbb73113774 -r 96f50dc60a1c crypto/dist/ipsec-tools/src/racoon/isakmp.c
--- a/crypto/dist/ipsec-tools/src/racoon/isakmp.c       Tue Jan 24 18:37:20 2017 +0000
+++ b/crypto/dist/ipsec-tools/src/racoon/isakmp.c       Tue Jan 24 19:23:31 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: isakmp.c,v 1.75 2016/03/09 22:27:17 christos Exp $     */
+/*     $NetBSD: isakmp.c,v 1.76 2017/01/24 19:23:56 christos Exp $     */
 
 /* Id: isakmp.c,v 1.74 2006/05/07 21:32:59 manubsd Exp */
 
@@ -1077,6 +1077,7 @@
                iph1->frag = 1;
        else
                iph1->frag = 0;
+       iph1->frag_last_index = 0;
        iph1->frag_chain = NULL;
 #endif
        iph1->approval = NULL;
@@ -1181,6 +1182,7 @@
 #endif
 #ifdef ENABLE_FRAG
        iph1->frag = 0;
+       iph1->frag_last_index = 0;
        iph1->frag_chain = NULL;
 #endif
        iph1->approval = NULL;
diff -r adbb73113774 -r 96f50dc60a1c crypto/dist/ipsec-tools/src/racoon/isakmp_frag.c
--- a/crypto/dist/ipsec-tools/src/racoon/isakmp_frag.c  Tue Jan 24 18:37:20 2017 +0000
+++ b/crypto/dist/ipsec-tools/src/racoon/isakmp_frag.c  Tue Jan 24 19:23:31 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: isakmp_frag.c,v 1.5 2009/04/22 11:24:20 tteras Exp $   */
+/*     $NetBSD: isakmp_frag.c,v 1.6 2017/01/24 19:23:31 christos Exp $ */
 
 /* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */
 
@@ -173,6 +173,38 @@
        return ntohl(hp[MD5_DIGEST_LENGTH / sizeof(*hp)]);
 }
 
+static int 
+isakmp_frag_insert(struct ph1handle *iph1, struct isakmp_frag_item *item)
+{
+       struct isakmp_frag_item *pitem = NULL;
+       struct isakmp_frag_item *citem = iph1->frag_chain;
+
+       if (iph1->frag_chain == NULL) {
+               iph1->frag_chain = item;
+               return 0;
+       }
+
+       do {
+               if (citem->frag_num == item->frag_num)
+                       return -1;
+
+               if (citem->frag_num > item->frag_num) {
+                       if (pitem)
+                               pitem->frag_next = item;
+                       item->frag_next = citem;
+                       break;
+               }
+
+               pitem = citem;
+               citem = citem->frag_next;
+       } while (citem != NULL);
+
+       /* we reached the end of the list, insert */
+       if (citem == NULL)
+             pitem->frag_next = item;
+       return 0;
+}
+
 int 
 isakmp_frag_extract(iph1, msg)
        struct ph1handle *iph1;
@@ -224,39 +256,43 @@
        item->frag_next = NULL;
        item->frag_packet = buf;
 
-       /* Look for the last frag while inserting the new item in the chain */
-       if (item->frag_last)
-               last_frag = item->frag_num;
+       /* Check for the last frag before inserting the new item in the chain */
+       if (item->frag_last) {
+               /* if we have the last fragment, indices must match */
+               if (iph1->frag_last_index != 0 &&
+                   item->frag_last != iph1->frag_last_index) {
+                       plog(LLV_ERROR, LOCATION, NULL,
+                            "Repeated last fragment index mismatch\n");
+                       racoon_free(item);
+                       vfree(buf);
+                       return -1;
+               }
 
-       if (iph1->frag_chain == NULL) {
-               iph1->frag_chain = item;
-       } else {
-               struct isakmp_frag_item *current;
-
-               current = iph1->frag_chain;
-               while (current->frag_next) {
-                       if (current->frag_last)
-                               last_frag = item->frag_num;
-                       current = current->frag_next;
-               }
-               current->frag_next = item;
+               last_frag = iph1->frag_last_index = item->frag_num;
        }
 
-       /* If we saw the last frag, check if the chain is complete */
+       /* insert fragment into chain */
+       if (isakmp_frag_insert(iph1, item) == -1) {
+               plog(LLV_ERROR, LOCATION, NULL,
+                   "Repeated fragment index mismatch\n");
+               racoon_free(item);
+               vfree(buf);
+               return -1;
+       }
+
+       /* If we saw the last frag, check if the chain is complete
+        * we have a sorted list now, so just walk through */
        if (last_frag != 0) {
+               item = iph1->frag_chain;
                for (i = 1; i <= last_frag; i++) {
-                       item = iph1->frag_chain;
-                       do {
-                               if (item->frag_num == i)
-                                       break;
-                               item = item->frag_next;
-                       } while (item != NULL);
-
+                       if (item->frag_num != i)
+                               break;
+                       item = item->frag_next;
                        if (item == NULL) /* Not found */
                                break;
                }
 
-               if (item != NULL) /* It is complete */
+               if (i > last_frag) /* It is complete */
                        return 1;
        }
                
@@ -291,15 +327,9 @@
        }
        data = buf->v;
 
+       item = iph1->frag_chain;
        for (i = 1; i <= frag_count; i++) {
-               item = iph1->frag_chain;
-               do {
-                       if (item->frag_num == i)
-                               break;
-                       item = item->frag_next;
-               } while (item != NULL);
-
-               if (item == NULL) {
+               if (item->frag_num != i) {
                        plog(LLV_ERROR, LOCATION, NULL, 
                            "Missing fragment #%d\n", i);
                        vfree(buf);
@@ -308,6 +338,7 @@
                }
                memcpy(data, item->frag_packet->v, item->frag_packet->l);
                data += item->frag_packet->l;
+               item = item->frag_next;
        }
 
 out:
diff -r adbb73113774 -r 96f50dc60a1c crypto/dist/ipsec-tools/src/racoon/isakmp_inf.c
--- a/crypto/dist/ipsec-tools/src/racoon/isakmp_inf.c   Tue Jan 24 18:37:20 2017 +0000
+++ b/crypto/dist/ipsec-tools/src/racoon/isakmp_inf.c   Tue Jan 24 19:23:31 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: isakmp_inf.c,v 1.50 2013/04/12 09:53:10 tteras Exp $   */
+/*     $NetBSD: isakmp_inf.c,v 1.51 2017/01/24 19:23:56 christos Exp $ */
 
 /* Id: isakmp_inf.c,v 1.44 2006/05/06 20:45:52 manubsd Exp */
 
@@ -720,6 +720,7 @@
 #endif
 #ifdef ENABLE_FRAG
        iph1->frag = 0;
+       iph1->frag_last_index = 0;
        iph1->frag_chain = NULL;
 #endif
 



Home | Main Index | Thread Index | Old Index