##// END OF EJS Templates
mpatch: avoid integer overflow in mpatch_decode (SEC)
Augie Fackler -
r38252:59837a16 stable
parent child Browse files
Show More
@@ -1,367 +1,372 b''
1 /*
1 /*
2 mpatch.c - efficient binary patching for Mercurial
2 mpatch.c - efficient binary patching for Mercurial
3
3
4 This implements a patch algorithm that's O(m + nlog n) where m is the
4 This implements a patch algorithm that's O(m + nlog n) where m is the
5 size of the output and n is the number of patches.
5 size of the output and n is the number of patches.
6
6
7 Given a list of binary patches, it unpacks each into a hunk list,
7 Given a list of binary patches, it unpacks each into a hunk list,
8 then combines the hunk lists with a treewise recursion to form a
8 then combines the hunk lists with a treewise recursion to form a
9 single hunk list. This hunk list is then applied to the original
9 single hunk list. This hunk list is then applied to the original
10 text.
10 text.
11
11
12 The text (or binary) fragments are copied directly from their source
12 The text (or binary) fragments are copied directly from their source
13 Python objects into a preallocated output string to avoid the
13 Python objects into a preallocated output string to avoid the
14 allocation of intermediate Python objects. Working memory is about 2x
14 allocation of intermediate Python objects. Working memory is about 2x
15 the total number of hunks.
15 the total number of hunks.
16
16
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
18
18
19 This software may be used and distributed according to the terms
19 This software may be used and distributed according to the terms
20 of the GNU General Public License, incorporated herein by reference.
20 of the GNU General Public License, incorporated herein by reference.
21 */
21 */
22
22
23 #include <limits.h>
23 #include <limits.h>
24 #include <stdlib.h>
24 #include <stdlib.h>
25 #include <string.h>
25 #include <string.h>
26
26
27 #include "bitmanipulation.h"
27 #include "bitmanipulation.h"
28 #include "compat.h"
28 #include "compat.h"
29 #include "mpatch.h"
29 #include "mpatch.h"
30
30
31 /* VC9 doesn't include bool and lacks stdbool.h based on cext/util.h */
31 /* VC9 doesn't include bool and lacks stdbool.h based on cext/util.h */
32 #if defined(_MSC_VER) || __STDC_VERSION__ < 199901L
32 #if defined(_MSC_VER) || __STDC_VERSION__ < 199901L
33 #define true 1
33 #define true 1
34 #define false 0
34 #define false 0
35 typedef unsigned char bool;
35 typedef unsigned char bool;
36 #else
36 #else
37 #include <stdbool.h>
37 #include <stdbool.h>
38 #endif
38 #endif
39
39
40 static struct mpatch_flist *lalloc(ssize_t size)
40 static struct mpatch_flist *lalloc(ssize_t size)
41 {
41 {
42 struct mpatch_flist *a = NULL;
42 struct mpatch_flist *a = NULL;
43
43
44 if (size < 1)
44 if (size < 1)
45 size = 1;
45 size = 1;
46
46
47 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist));
47 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist));
48 if (a) {
48 if (a) {
49 a->base = (struct mpatch_frag *)malloc(
49 a->base = (struct mpatch_frag *)malloc(
50 sizeof(struct mpatch_frag) * size);
50 sizeof(struct mpatch_frag) * size);
51 if (a->base) {
51 if (a->base) {
52 a->head = a->tail = a->base;
52 a->head = a->tail = a->base;
53 return a;
53 return a;
54 }
54 }
55 free(a);
55 free(a);
56 }
56 }
57 return NULL;
57 return NULL;
58 }
58 }
59
59
60 void mpatch_lfree(struct mpatch_flist *a)
60 void mpatch_lfree(struct mpatch_flist *a)
61 {
61 {
62 if (a) {
62 if (a) {
63 free(a->base);
63 free(a->base);
64 free(a);
64 free(a);
65 }
65 }
66 }
66 }
67
67
68 static ssize_t lsize(struct mpatch_flist *a)
68 static ssize_t lsize(struct mpatch_flist *a)
69 {
69 {
70 return a->tail - a->head;
70 return a->tail - a->head;
71 }
71 }
72
72
73 /* add helper to add src and *dest iff it won't overflow */
73 /* add helper to add src and *dest iff it won't overflow */
74 static inline bool safeadd(int src, int *dest)
74 static inline bool safeadd(int src, int *dest)
75 {
75 {
76 if ((src > 0) == (*dest > 0)) {
76 if ((src > 0) == (*dest > 0)) {
77 if (*dest > 0) {
77 if (*dest > 0) {
78 if (src > (INT_MAX - *dest)) {
78 if (src > (INT_MAX - *dest)) {
79 return false;
79 return false;
80 }
80 }
81 } else {
81 } else {
82 if (src < (INT_MIN - *dest)) {
82 if (src < (INT_MIN - *dest)) {
83 return false;
83 return false;
84 }
84 }
85 }
85 }
86 }
86 }
87 *dest += src;
87 *dest += src;
88 return true;
88 return true;
89 }
89 }
90
90
91 /* subtract src from dest and store result in dest */
91 /* subtract src from dest and store result in dest */
92 static inline bool safesub(int src, int *dest)
92 static inline bool safesub(int src, int *dest)
93 {
93 {
94 if (((src > 0) && (*dest < INT_MIN + src)) ||
94 if (((src > 0) && (*dest < INT_MIN + src)) ||
95 ((src < 0) && (*dest > INT_MAX + src))) {
95 ((src < 0) && (*dest > INT_MAX + src))) {
96 return false;
96 return false;
97 }
97 }
98 *dest -= src;
98 *dest -= src;
99 return true;
99 return true;
100 }
100 }
101
101
102 /* move hunks in source that are less cut to dest, compensating
102 /* move hunks in source that are less cut to dest, compensating
103 for changes in offset. the last hunk may be split if necessary.
103 for changes in offset. the last hunk may be split if necessary.
104 */
104 */
105 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut,
105 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut,
106 int offset)
106 int offset)
107 {
107 {
108 struct mpatch_frag *d = dest->tail, *s = src->head;
108 struct mpatch_frag *d = dest->tail, *s = src->head;
109 int postend, c, l;
109 int postend, c, l;
110
110
111 while (s != src->tail) {
111 while (s != src->tail) {
112 int soffset = s->start;
112 int soffset = s->start;
113 if (!safeadd(offset, &soffset))
113 if (!safeadd(offset, &soffset))
114 break; /* add would overflow, oh well */
114 break; /* add would overflow, oh well */
115 if (soffset >= cut)
115 if (soffset >= cut)
116 break; /* we've gone far enough */
116 break; /* we've gone far enough */
117
117
118 postend = offset;
118 postend = offset;
119 if (!safeadd(s->start, &postend) ||
119 if (!safeadd(s->start, &postend) ||
120 !safeadd(s->len, &postend)) {
120 !safeadd(s->len, &postend)) {
121 break;
121 break;
122 }
122 }
123 if (postend <= cut) {
123 if (postend <= cut) {
124 /* save this hunk */
124 /* save this hunk */
125 int tmp = s->start;
125 int tmp = s->start;
126 if (!safesub(s->end, &tmp)) {
126 if (!safesub(s->end, &tmp)) {
127 break;
127 break;
128 }
128 }
129 if (!safeadd(s->len, &tmp)) {
129 if (!safeadd(s->len, &tmp)) {
130 break;
130 break;
131 }
131 }
132 if (!safeadd(tmp, &offset)) {
132 if (!safeadd(tmp, &offset)) {
133 break; /* add would overflow, oh well */
133 break; /* add would overflow, oh well */
134 }
134 }
135 *d++ = *s++;
135 *d++ = *s++;
136 } else {
136 } else {
137 /* break up this hunk */
137 /* break up this hunk */
138 c = cut;
138 c = cut;
139 if (!safesub(offset, &c)) {
139 if (!safesub(offset, &c)) {
140 break;
140 break;
141 }
141 }
142 if (s->end < c)
142 if (s->end < c)
143 c = s->end;
143 c = s->end;
144 l = cut - offset - s->start;
144 l = cut - offset - s->start;
145 if (s->len < l)
145 if (s->len < l)
146 l = s->len;
146 l = s->len;
147
147
148 offset += s->start + l - c;
148 offset += s->start + l - c;
149
149
150 d->start = s->start;
150 d->start = s->start;
151 d->end = c;
151 d->end = c;
152 d->len = l;
152 d->len = l;
153 d->data = s->data;
153 d->data = s->data;
154 d++;
154 d++;
155 s->start = c;
155 s->start = c;
156 s->len = s->len - l;
156 s->len = s->len - l;
157 s->data = s->data + l;
157 s->data = s->data + l;
158
158
159 break;
159 break;
160 }
160 }
161 }
161 }
162
162
163 dest->tail = d;
163 dest->tail = d;
164 src->head = s;
164 src->head = s;
165 return offset;
165 return offset;
166 }
166 }
167
167
168 /* like gather, but with no output list */
168 /* like gather, but with no output list */
169 static int discard(struct mpatch_flist *src, int cut, int offset)
169 static int discard(struct mpatch_flist *src, int cut, int offset)
170 {
170 {
171 struct mpatch_frag *s = src->head;
171 struct mpatch_frag *s = src->head;
172 int postend, c, l;
172 int postend, c, l;
173
173
174 while (s != src->tail) {
174 while (s != src->tail) {
175 int cmpcut = s->start;
175 int cmpcut = s->start;
176 if (!safeadd(offset, &cmpcut)) {
176 if (!safeadd(offset, &cmpcut)) {
177 break;
177 break;
178 }
178 }
179 if (cmpcut >= cut)
179 if (cmpcut >= cut)
180 break;
180 break;
181
181
182 postend = offset;
182 postend = offset;
183 if (!safeadd(s->start, &postend)) {
183 if (!safeadd(s->start, &postend)) {
184 break;
184 break;
185 }
185 }
186 if (!safeadd(s->len, &postend)) {
186 if (!safeadd(s->len, &postend)) {
187 break;
187 break;
188 }
188 }
189 if (postend <= cut) {
189 if (postend <= cut) {
190 /* do the subtraction first to avoid UB integer overflow
190 /* do the subtraction first to avoid UB integer overflow
191 */
191 */
192 int tmp = s->start;
192 int tmp = s->start;
193 if (!safesub(s->end, &tmp)) {
193 if (!safesub(s->end, &tmp)) {
194 break;
194 break;
195 }
195 }
196 if (!safeadd(s->len, &tmp)) {
196 if (!safeadd(s->len, &tmp)) {
197 break;
197 break;
198 }
198 }
199 if (!safeadd(tmp, &offset)) {
199 if (!safeadd(tmp, &offset)) {
200 break;
200 break;
201 }
201 }
202 s++;
202 s++;
203 } else {
203 } else {
204 c = cut;
204 c = cut;
205 if (!safesub(offset, &c)) {
205 if (!safesub(offset, &c)) {
206 break;
206 break;
207 }
207 }
208 if (s->end < c)
208 if (s->end < c)
209 c = s->end;
209 c = s->end;
210 l = cut - offset - s->start;
210 l = cut - offset - s->start;
211 if (s->len < l)
211 if (s->len < l)
212 l = s->len;
212 l = s->len;
213
213
214 offset += s->start + l - c;
214 offset += s->start + l - c;
215 s->start = c;
215 s->start = c;
216 s->len = s->len - l;
216 s->len = s->len - l;
217 s->data = s->data + l;
217 s->data = s->data + l;
218
218
219 break;
219 break;
220 }
220 }
221 }
221 }
222
222
223 src->head = s;
223 src->head = s;
224 return offset;
224 return offset;
225 }
225 }
226
226
227 /* combine hunk lists a and b, while adjusting b for offset changes in a/
227 /* combine hunk lists a and b, while adjusting b for offset changes in a/
228 this deletes a and b and returns the resultant list. */
228 this deletes a and b and returns the resultant list. */
229 static struct mpatch_flist *combine(struct mpatch_flist *a,
229 static struct mpatch_flist *combine(struct mpatch_flist *a,
230 struct mpatch_flist *b)
230 struct mpatch_flist *b)
231 {
231 {
232 struct mpatch_flist *c = NULL;
232 struct mpatch_flist *c = NULL;
233 struct mpatch_frag *bh, *ct;
233 struct mpatch_frag *bh, *ct;
234 int offset = 0, post;
234 int offset = 0, post;
235
235
236 if (a && b)
236 if (a && b)
237 c = lalloc((lsize(a) + lsize(b)) * 2);
237 c = lalloc((lsize(a) + lsize(b)) * 2);
238
238
239 if (c) {
239 if (c) {
240
240
241 for (bh = b->head; bh != b->tail; bh++) {
241 for (bh = b->head; bh != b->tail; bh++) {
242 /* save old hunks */
242 /* save old hunks */
243 offset = gather(c, a, bh->start, offset);
243 offset = gather(c, a, bh->start, offset);
244
244
245 /* discard replaced hunks */
245 /* discard replaced hunks */
246 post = discard(a, bh->end, offset);
246 post = discard(a, bh->end, offset);
247
247
248 /* insert new hunk */
248 /* insert new hunk */
249 ct = c->tail;
249 ct = c->tail;
250 ct->start = bh->start - offset;
250 ct->start = bh->start - offset;
251 ct->end = bh->end - post;
251 ct->end = bh->end - post;
252 ct->len = bh->len;
252 ct->len = bh->len;
253 ct->data = bh->data;
253 ct->data = bh->data;
254 c->tail++;
254 c->tail++;
255 offset = post;
255 offset = post;
256 }
256 }
257
257
258 /* hold on to tail from a */
258 /* hold on to tail from a */
259 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a));
259 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a));
260 c->tail += lsize(a);
260 c->tail += lsize(a);
261 }
261 }
262
262
263 mpatch_lfree(a);
263 mpatch_lfree(a);
264 mpatch_lfree(b);
264 mpatch_lfree(b);
265 return c;
265 return c;
266 }
266 }
267
267
268 /* decode a binary patch into a hunk list */
268 /* decode a binary patch into a hunk list */
269 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
269 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
270 {
270 {
271 struct mpatch_flist *l;
271 struct mpatch_flist *l;
272 struct mpatch_frag *lt;
272 struct mpatch_frag *lt;
273 int pos = 0;
273 int pos = 0;
274
274
275 /* assume worst case size, we won't have many of these lists */
275 /* assume worst case size, we won't have many of these lists */
276 l = lalloc(len / 12 + 1);
276 l = lalloc(len / 12 + 1);
277 if (!l)
277 if (!l)
278 return MPATCH_ERR_NO_MEM;
278 return MPATCH_ERR_NO_MEM;
279
279
280 lt = l->tail;
280 lt = l->tail;
281
281
282 /* We check against len-11 to ensure we have at least 12 bytes
282 /* We check against len-11 to ensure we have at least 12 bytes
283 left in the patch so we can read our three be32s out of it. */
283 left in the patch so we can read our three be32s out of it. */
284 while (pos >= 0 && pos < (len - 11)) {
284 while (pos >= 0 && pos < (len - 11)) {
285 lt->start = getbe32(bin + pos);
285 lt->start = getbe32(bin + pos);
286 lt->end = getbe32(bin + pos + 4);
286 lt->end = getbe32(bin + pos + 4);
287 lt->len = getbe32(bin + pos + 8);
287 lt->len = getbe32(bin + pos + 8);
288 lt->data = bin + pos + 12;
288 if (lt->start < 0 || lt->start > lt->end || lt->len < 0)
289 pos += 12 + lt->len;
290 if (lt->start > lt->end || lt->len < 0)
291 break; /* sanity check */
289 break; /* sanity check */
290 if (!safeadd(12, &pos)) {
291 break;
292 }
293 lt->data = bin + pos;
294 if (!safeadd(lt->len, &pos)) {
295 break;
296 }
292 lt++;
297 lt++;
293 }
298 }
294
299
295 if (pos != len) {
300 if (pos != len) {
296 mpatch_lfree(l);
301 mpatch_lfree(l);
297 return MPATCH_ERR_CANNOT_BE_DECODED;
302 return MPATCH_ERR_CANNOT_BE_DECODED;
298 }
303 }
299
304
300 l->tail = lt;
305 l->tail = lt;
301 *res = l;
306 *res = l;
302 return 0;
307 return 0;
303 }
308 }
304
309
305 /* calculate the size of resultant text */
310 /* calculate the size of resultant text */
306 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
311 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
307 {
312 {
308 ssize_t outlen = 0, last = 0;
313 ssize_t outlen = 0, last = 0;
309 struct mpatch_frag *f = l->head;
314 struct mpatch_frag *f = l->head;
310
315
311 while (f != l->tail) {
316 while (f != l->tail) {
312 if (f->start < last || f->end > len) {
317 if (f->start < last || f->end > len) {
313 return MPATCH_ERR_INVALID_PATCH;
318 return MPATCH_ERR_INVALID_PATCH;
314 }
319 }
315 outlen += f->start - last;
320 outlen += f->start - last;
316 last = f->end;
321 last = f->end;
317 outlen += f->len;
322 outlen += f->len;
318 f++;
323 f++;
319 }
324 }
320
325
321 outlen += len - last;
326 outlen += len - last;
322 return outlen;
327 return outlen;
323 }
328 }
324
329
325 int mpatch_apply(char *buf, const char *orig, ssize_t len,
330 int mpatch_apply(char *buf, const char *orig, ssize_t len,
326 struct mpatch_flist *l)
331 struct mpatch_flist *l)
327 {
332 {
328 struct mpatch_frag *f = l->head;
333 struct mpatch_frag *f = l->head;
329 int last = 0;
334 int last = 0;
330 char *p = buf;
335 char *p = buf;
331
336
332 while (f != l->tail) {
337 while (f != l->tail) {
333 if (f->start < last || f->start > len || f->end > len ||
338 if (f->start < last || f->start > len || f->end > len ||
334 last < 0) {
339 last < 0) {
335 return MPATCH_ERR_INVALID_PATCH;
340 return MPATCH_ERR_INVALID_PATCH;
336 }
341 }
337 memcpy(p, orig + last, f->start - last);
342 memcpy(p, orig + last, f->start - last);
338 p += f->start - last;
343 p += f->start - last;
339 memcpy(p, f->data, f->len);
344 memcpy(p, f->data, f->len);
340 last = f->end;
345 last = f->end;
341 p += f->len;
346 p += f->len;
342 f++;
347 f++;
343 }
348 }
344 if (last < 0) {
349 if (last < 0) {
345 return MPATCH_ERR_INVALID_PATCH;
350 return MPATCH_ERR_INVALID_PATCH;
346 }
351 }
347 memcpy(p, orig + last, len - last);
352 memcpy(p, orig + last, len - last);
348 return 0;
353 return 0;
349 }
354 }
350
355
351 /* recursively generate a patch of all bins between start and end */
356 /* recursively generate a patch of all bins between start and end */
352 struct mpatch_flist *
357 struct mpatch_flist *
353 mpatch_fold(void *bins, struct mpatch_flist *(*get_next_item)(void *, ssize_t),
358 mpatch_fold(void *bins, struct mpatch_flist *(*get_next_item)(void *, ssize_t),
354 ssize_t start, ssize_t end)
359 ssize_t start, ssize_t end)
355 {
360 {
356 ssize_t len;
361 ssize_t len;
357
362
358 if (start + 1 == end) {
363 if (start + 1 == end) {
359 /* trivial case, output a decoded list */
364 /* trivial case, output a decoded list */
360 return get_next_item(bins, start);
365 return get_next_item(bins, start);
361 }
366 }
362
367
363 /* divide and conquer, memory management is elsewhere */
368 /* divide and conquer, memory management is elsewhere */
364 len = (end - start) / 2;
369 len = (end - start) / 2;
365 return combine(mpatch_fold(bins, get_next_item, start, start + len),
370 return combine(mpatch_fold(bins, get_next_item, start, start + len),
366 mpatch_fold(bins, get_next_item, start + len, end));
371 mpatch_fold(bins, get_next_item, start + len, end));
367 }
372 }
General Comments 0
You need to be logged in to leave comments. Login now