Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()
authorThomas Arendsen Hein <thomas@intevation.de>
Sat, 27 Jan 2007 23:07:06 +0100
changeset 4358 11dc22eb8e8d
parent 4357 3f1b0c0fb4fd
child 4359 80d3f6f0d8e5
child 4377 4759da3e4dc8
Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize() - fix off by 11 when checking if there are more hunks (found by Maris Fogels) - bail out if start is greater than end - check if new hunk starts after start/end/len block of current hunk as the pointer can wrap around on very large values, reproducible with import mpatch; mpatch.patchedsize(12, 'x'*12)
mercurial/mpatch.c
--- a/mercurial/mpatch.c	Tue Apr 24 10:44:13 2007 -0700
+++ b/mercurial/mpatch.c	Sat Jan 27 23:07:06 2007 +0100
@@ -221,7 +221,7 @@
 {
 	struct flist *l;
 	struct frag *lt;
-	char *end = bin + len;
+	char *data = bin + 12, *end = bin + len;
 	char decode[12]; /* for dealing with alignment issues */
 
 	/* assume worst case size, we won't have many of these lists */
@@ -231,13 +231,18 @@
 
 	lt = l->tail;
 
-	while (bin < end) {
+	while (data <= end) {
 		memcpy(decode, bin, 12);
 		lt->start = ntohl(*(uint32_t *)decode);
 		lt->end = ntohl(*(uint32_t *)(decode + 4));
 		lt->len = ntohl(*(uint32_t *)(decode + 8));
-		lt->data = bin + 12;
-		bin += 12 + lt->len;
+		if (lt->start > lt->end)
+			break; /* sanity check */
+		bin = data + lt->len;
+		if (bin < data)
+			break; /* big data + big (bogus) len can wrap around */
+		lt->data = data;
+		data = bin + 12;
 		lt++;
 	}
 
@@ -367,20 +372,26 @@
 {
 	long orig, start, end, len, outlen = 0, last = 0;
 	int patchlen;
-	char *bin, *binend;
+	char *bin, *binend, *data;
 	char decode[12]; /* for dealing with alignment issues */
 
 	if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen))
 		return NULL;
 
 	binend = bin + patchlen;
+	data = bin + 12;
 
-	while (bin < binend) {
+	while (data <= binend) {
 		memcpy(decode, bin, 12);
 		start = ntohl(*(uint32_t *)decode);
 		end = ntohl(*(uint32_t *)(decode + 4));
 		len = ntohl(*(uint32_t *)(decode + 8));
-		bin += 12 + len;
+		if (start > end)
+			break; /* sanity check */
+		bin = data + len;
+		if (bin < data)
+			break; /* big data + big (bogus) len can wrap around */
+		data = bin + 12;
 		outlen += start - last;
 		last = end;
 		outlen += len;