at 22.05-pre 193 lines 5.4 kB view raw
1From: Antoine_Beaupre <anarcat@orangeseeds.org> 2Acked-by: Jiri Bohac <jbohac@suse.cz> 3Subject: PR/51682: Avoid DoS with fragment out of order insertion; keep fragments sorted in the list. 4References: bsc#1047443, CVE-2016-10396 5 6 7 8Index: a/src/racoon/handler.h 9=================================================================== 10--- a/src/racoon/handler.h.orig 2018-01-26 18:05:21.114764376 +0100 11+++ a/src/racoon/handler.h 2018-01-26 18:05:33.986741103 +0100 12@@ -141,6 +141,7 @@ struct ph1handle { 13 #endif 14 #ifdef ENABLE_FRAG 15 int frag; /* IKE phase 1 fragmentation */ 16+ int frag_last_index; 17 struct isakmp_frag_item *frag_chain; /* Received fragments */ 18 #endif 19 20Index: a/src/racoon/isakmp.c 21=================================================================== 22--- a/src/racoon/isakmp.c.orig 2018-01-26 18:05:21.118764369 +0100 23+++ a/src/racoon/isakmp.c 2018-01-26 18:05:33.986741103 +0100 24@@ -1069,6 +1069,7 @@ isakmp_ph1begin_i(rmconf, remote, local) 25 iph1->frag = 1; 26 else 27 iph1->frag = 0; 28+ iph1->frag_last_index = 0; 29 iph1->frag_chain = NULL; 30 #endif 31 iph1->approval = NULL; 32@@ -1173,6 +1174,7 @@ isakmp_ph1begin_r(msg, remote, local, et 33 #endif 34 #ifdef ENABLE_FRAG 35 iph1->frag = 0; 36+ iph1->frag_last_index = 0; 37 iph1->frag_chain = NULL; 38 #endif 39 iph1->approval = NULL; 40Index: a/src/racoon/isakmp_frag.c 41=================================================================== 42--- a/src/racoon/isakmp_frag.c.orig 2018-01-26 18:05:21.118764369 +0100 43+++ a/src/racoon/isakmp_frag.c 2018-01-26 18:05:33.986741103 +0100 44@@ -173,6 +173,43 @@ vendorid_frag_cap(gen) 45 return ntohl(hp[MD5_DIGEST_LENGTH / sizeof(*hp)]); 46 } 47 48+static int 49+isakmp_frag_insert(struct ph1handle *iph1, struct isakmp_frag_item *item) 50+{ 51+ struct isakmp_frag_item *pitem = NULL; 52+ struct isakmp_frag_item *citem = iph1->frag_chain; 53+ 54+ /* no frag yet, just insert at beginning of list */ 55+ if (iph1->frag_chain == NULL) { 56+ iph1->frag_chain = item; 57+ return 0; 58+ } 59+ 60+ do { 61+ /* duplicate fragment number, abort (CVE-2016-10396) */ 62+ if (citem->frag_num == item->frag_num) 63+ return -1; 64+ 65+ /* need to insert before current item */ 66+ if (citem->frag_num > item->frag_num) { 67+ if (pitem != NULL) 68+ pitem->frag_next = item; 69+ else 70+ /* insert at the beginning of the list */ 71+ iph1->frag_chain = item; 72+ item->frag_next = citem; 73+ return 0; 74+ } 75+ 76+ pitem = citem; 77+ citem = citem->frag_next; 78+ } while (citem != NULL); 79+ 80+ /* we reached the end of the list, insert */ 81+ pitem->frag_next = item; 82+ return 0; 83+} 84+ 85 int 86 isakmp_frag_extract(iph1, msg) 87 struct ph1handle *iph1; 88@@ -224,39 +261,43 @@ isakmp_frag_extract(iph1, msg) 89 item->frag_next = NULL; 90 item->frag_packet = buf; 91 92- /* Look for the last frag while inserting the new item in the chain */ 93- if (item->frag_last) 94- last_frag = item->frag_num; 95+ /* Check for the last frag before inserting the new item in the chain */ 96+ if (item->frag_last) { 97+ /* if we have the last fragment, indices must match */ 98+ if (iph1->frag_last_index != 0 && 99+ item->frag_last != iph1->frag_last_index) { 100+ plog(LLV_ERROR, LOCATION, NULL, 101+ "Repeated last fragment index mismatch\n"); 102+ racoon_free(item); 103+ vfree(buf); 104+ return -1; 105+ } 106 107- if (iph1->frag_chain == NULL) { 108- iph1->frag_chain = item; 109- } else { 110- struct isakmp_frag_item *current; 111+ last_frag = iph1->frag_last_index = item->frag_num; 112+ } 113 114- current = iph1->frag_chain; 115- while (current->frag_next) { 116- if (current->frag_last) 117- last_frag = item->frag_num; 118- current = current->frag_next; 119- } 120- current->frag_next = item; 121+ /* insert fragment into chain */ 122+ if (isakmp_frag_insert(iph1, item) == -1) { 123+ plog(LLV_ERROR, LOCATION, NULL, 124+ "Repeated fragment index mismatch\n"); 125+ racoon_free(item); 126+ vfree(buf); 127+ return -1; 128 } 129 130- /* If we saw the last frag, check if the chain is complete */ 131+ /* If we saw the last frag, check if the chain is complete 132+ * we have a sorted list now, so just walk through */ 133 if (last_frag != 0) { 134+ item = iph1->frag_chain; 135 for (i = 1; i <= last_frag; i++) { 136- item = iph1->frag_chain; 137- do { 138- if (item->frag_num == i) 139- break; 140- item = item->frag_next; 141- } while (item != NULL); 142- 143+ if (item->frag_num != i) 144+ break; 145+ item = item->frag_next; 146 if (item == NULL) /* Not found */ 147 break; 148 } 149 150- if (item != NULL) /* It is complete */ 151+ if (i > last_frag) /* It is complete */ 152 return 1; 153 } 154 155@@ -291,15 +332,9 @@ isakmp_frag_reassembly(iph1) 156 } 157 data = buf->v; 158 159+ item = iph1->frag_chain; 160 for (i = 1; i <= frag_count; i++) { 161- item = iph1->frag_chain; 162- do { 163- if (item->frag_num == i) 164- break; 165- item = item->frag_next; 166- } while (item != NULL); 167- 168- if (item == NULL) { 169+ if (item->frag_num != i) { 170 plog(LLV_ERROR, LOCATION, NULL, 171 "Missing fragment #%d\n", i); 172 vfree(buf); 173@@ -308,6 +343,7 @@ isakmp_frag_reassembly(iph1) 174 } 175 memcpy(data, item->frag_packet->v, item->frag_packet->l); 176 data += item->frag_packet->l; 177+ item = item->frag_next; 178 } 179 180 out: 181 182 183diff -u -p -r1.50 -r1.51 184--- a/src/racoon/isakmp_inf.c 2013/04/12 09:53:10 1.50 185+++ a/src/racoon/isakmp_inf.c 2017/01/24 19:23:56 1.51 186@@ -720,6 +720,7 @@ isakmp_info_send_nx(isakmp, remote, loca 187 #endif 188 #ifdef ENABLE_FRAG 189 iph1->frag = 0; 190+ iph1->frag_last_index = 0; 191 iph1->frag_chain = NULL; 192 #endif 193