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