Blame SOURCES/mercurial-cve-2018-13346-cve-2018-13347.patch

7d0f2b
diff -ru mercurial-2.6.2/mercurial/mpatch.c mercurial-2.6.2_patched/mercurial/mpatch.c
7d0f2b
--- mercurial-2.6.2/mercurial/mpatch.c	2013-06-02 00:10:16.000000000 +0200
7d0f2b
+++ mercurial-2.6.2_patched/mercurial/mpatch.c	2019-05-07 16:51:13.631774481 +0200
7d0f2b
@@ -74,6 +74,35 @@
7d0f2b
 	return a->tail - a->head;
7d0f2b
 }
7d0f2b
 
7d0f2b
+/* add helper to add src and *dest iff it won't overflow */
7d0f2b
+static inline int safeadd(int src, int *dest)
7d0f2b
+{
7d0f2b
+	if ((src > 0) == (*dest > 0)) {
7d0f2b
+		if (*dest > 0) {
7d0f2b
+			if (src > (INT_MAX - *dest)) {
7d0f2b
+				return 0;
7d0f2b
+			}
7d0f2b
+		} else {
7d0f2b
+			if (src < (INT_MIN - *dest)) {
7d0f2b
+				return 0;
7d0f2b
+			}
7d0f2b
+		}
7d0f2b
+	}
7d0f2b
+	*dest += src;
7d0f2b
+	return 1;
7d0f2b
+}
7d0f2b
+
7d0f2b
+/* subtract src from dest and store result in dest */
7d0f2b
+static inline int safesub(int src, int *dest)
7d0f2b
+{
7d0f2b
+	if (((src > 0) && (*dest < INT_MIN + src)) ||
7d0f2b
+	    ((src < 0) && (*dest > INT_MAX + src))) {
7d0f2b
+		return 0;
7d0f2b
+	}
7d0f2b
+	*dest -= src;
7d0f2b
+	return 1;
7d0f2b
+}
7d0f2b
+
7d0f2b
 /* move hunks in source that are less cut to dest, compensating
7d0f2b
    for changes in offset. the last hunk may be split if necessary.
7d0f2b
 */
7d0f2b
@@ -83,18 +112,37 @@
7d0f2b
 	int postend, c, l;
7d0f2b
 
7d0f2b
 	while (s != src->tail) {
7d0f2b
-		if (s->start + offset >= cut)
7d0f2b
+		int soffset = s->start;
7d0f2b
+		if (!safeadd(offset, &soffset))
7d0f2b
+			break; /* add would overflow, oh well */
7d0f2b
+		if (soffset >= cut)
7d0f2b
 			break; /* we've gone far enough */
7d0f2b
 
7d0f2b
-		postend = offset + s->start + s->len;
7d0f2b
+		postend = offset;
7d0f2b
+		if (!safeadd(s->start, &postend) ||
7d0f2b
+		    !safeadd(s->len, &postend)) {
7d0f2b
+			break;
7d0f2b
+		}
7d0f2b
 		if (postend <= cut) {
7d0f2b
 			/* save this hunk */
7d0f2b
-			offset += s->start + s->len - s->end;
7d0f2b
+			int tmp = s->start;
7d0f2b
+			if (!safesub(s->end, &tmp)) {
7d0f2b
+				break;
7d0f2b
+			}
7d0f2b
+			if (!safeadd(s->len, &tmp)) {
7d0f2b
+				break;
7d0f2b
+			}
7d0f2b
+			if (!safeadd(tmp, &offset)) {
7d0f2b
+				break; /* add would overflow, oh well */
7d0f2b
+			}
7d0f2b
 			*d++ = *s++;
7d0f2b
 		}
7d0f2b
 		else {
7d0f2b
 			/* break up this hunk */
7d0f2b
-			c = cut - offset;
7d0f2b
+			c = cut;
7d0f2b
+			if (!safesub(offset, &c)) {
7d0f2b
+				break;
7d0f2b
+			}
7d0f2b
 			if (s->end < c)
7d0f2b
 				c = s->end;
7d0f2b
 			l = cut - offset - s->start;
7d0f2b
@@ -128,16 +176,40 @@
7d0f2b
 	int postend, c, l;
7d0f2b
 
7d0f2b
 	while (s != src->tail) {
7d0f2b
-		if (s->start + offset >= cut)
7d0f2b
+		int cmpcut = s->start;
7d0f2b
+		if (!safeadd(offset, &cmpcut)) {
7d0f2b
+			break;
7d0f2b
+		}
7d0f2b
+		if (cmpcut >= cut)
7d0f2b
 			break;
7d0f2b
 
7d0f2b
-		postend = offset + s->start + s->len;
7d0f2b
+		postend = offset;
7d0f2b
+		if (!safeadd(s->start, &postend)) {
7d0f2b
+			break;
7d0f2b
+		}
7d0f2b
+		if (!safeadd(s->len, &postend)) {
7d0f2b
+			break;
7d0f2b
+		}
7d0f2b
 		if (postend <= cut) {
7d0f2b
-			offset += s->start + s->len - s->end;
7d0f2b
+			/* do the subtraction first to avoid UB integer overflow
7d0f2b
+			 */
7d0f2b
+			int tmp = s->start;
7d0f2b
+			if (!safesub(s->end, &tmp)) {
7d0f2b
+				break;
7d0f2b
+			}
7d0f2b
+			if (!safeadd(s->len, &tmp)) {
7d0f2b
+				break;
7d0f2b
+			}
7d0f2b
+			if (!safeadd(tmp, &offset)) {
7d0f2b
+				break;
7d0f2b
+			}
7d0f2b
 			s++;
7d0f2b
 		}
7d0f2b
 		else {
7d0f2b
-			c = cut - offset;
7d0f2b
+			c = cut;
7d0f2b
+			if (!safesub(offset, &c)) {
7d0f2b
+				break;
7d0f2b
+			}
7d0f2b
 			if (s->end < c)
7d0f2b
 				c = s->end;
7d0f2b
 			l = cut - offset - s->start;
7d0f2b
@@ -179,8 +251,18 @@
7d0f2b
 
7d0f2b
 			/* insert new hunk */
7d0f2b
 			ct = c->tail;
7d0f2b
-			ct->start = bh->start - offset;
7d0f2b
-			ct->end = bh->end - post;
7d0f2b
+			ct->start = bh->start;
7d0f2b
+			ct->end = bh->end;
7d0f2b
+			if (!safesub(offset, &(ct->start)) ||
7d0f2b
+			    !safesub(post, &(ct->end))) {
7d0f2b
+				/* It was already possible to exit
7d0f2b
+				 * this function with a return value
7d0f2b
+				 * of NULL before the safesub()s were
7d0f2b
+				 * added, so this should be fine. */
7d0f2b
+				lfree(c);
7d0f2b
+				c = NULL;
7d0f2b
+				goto done;
7d0f2b
+			}
7d0f2b
 			ct->len = bh->len;
7d0f2b
 			ct->data = bh->data;
7d0f2b
 			c->tail++;
7d0f2b
@@ -191,7 +273,7 @@
7d0f2b
 		memcpy(c->tail, a->head, sizeof(struct frag) * lsize(a));
7d0f2b
 		c->tail += lsize(a);
7d0f2b
 	}
7d0f2b
-
7d0f2b
+done:
7d0f2b
 	lfree(a);
7d0f2b
 	lfree(b);
7d0f2b
 	return c;
7d0f2b
@@ -215,13 +297,17 @@
7d0f2b
 		lt->start = getbe32(bin);
7d0f2b
 		lt->end = getbe32(bin + 4);
7d0f2b
 		lt->len = getbe32(bin + 8);
7d0f2b
-		if (lt->start > lt->end)
7d0f2b
-			break; /* sanity check */
7d0f2b
-		bin = data + lt->len;
7d0f2b
-		if (bin < data)
7d0f2b
+		if (lt->start < 0 || lt->start > lt->end || lt->len < 0)
7d0f2b
+ 			break; /* sanity check */
7d0f2b
+		bin = data;
7d0f2b
+		if (!safeadd(lt->len, &bin)) {
7d0f2b
 			break; /* big data + big (bogus) len can wrap around */
7d0f2b
+		}
7d0f2b
 		lt->data = data;
7d0f2b
-		data = bin + 12;
7d0f2b
+		data = bin;
7d0f2b
+		if (!safeadd(12, &data)) {
7d0f2b
+			break;
7d0f2b
+		}
7d0f2b
 		lt++;
7d0f2b
 	}
7d0f2b
 
7d0f2b
@@ -266,7 +352,8 @@
7d0f2b
 	char *p = buf;
7d0f2b
 
7d0f2b
 	while (f != l->tail) {
7d0f2b
-		if (f->start < last || f->end > len) {
7d0f2b
+		if (f->start < last || f->start > len || f->end > len ||
7d0f2b
+            last < 0) {
7d0f2b
 			if (!PyErr_Occurred())
7d0f2b
 				PyErr_SetString(mpatch_Error,
7d0f2b
 				                "invalid patch");
7d0f2b
@@ -279,6 +366,12 @@
7d0f2b
 		p += f->len;
7d0f2b
 		f++;
7d0f2b
 	}
7d0f2b
+	if (last < 0) {
7d0f2b
+		if (!PyErr_Occurred())
7d0f2b
+			PyErr_SetString(mpatch_Error,
7d0f2b
+			                "invalid patch");
7d0f2b
+		return 0;
7d0f2b
+	}
7d0f2b
 	memcpy(p, orig + last, len - last);
7d0f2b
 	return 1;
7d0f2b
 }