[PATCH] Fix segfaults when parsing bdiff hunks in mpatch.decode() and .patchedsize()

Thomas Arendsen Hein thomas at intevation.de
Sat Jan 27 16:09:01 CST 2007


Hi!

I plan to push this to crew-stable, but like to have comments first.
Is this problem security relevant? (Segfaults, but only reads)
Does the patch make decode and patchedsize bullet proof?

Thomas

# HG changeset patch
# User Thomas Arendsen Hein <thomas at intevation.de>
# Date 1169935626 -3600
# Node ID ebe50232cc21a14500749322618c8a2653e68f04
# Parent  a8a8ecf909db17bcbbbc4eb36c7e70f622b0d09a
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)

diff -r a8a8ecf909db -r ebe50232cc21 mercurial/mpatch.c
--- a/mercurial/mpatch.c	Thu Jan 25 17:57:51 2007 +0100
+++ b/mercurial/mpatch.c	Sat Jan 27 23:07:06 2007 +0100
@@ -221,7 +221,7 @@ static struct flist *decode(char *bin, i
 {
 	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 @@ static struct flist *decode(char *bin, i
 
 	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 @@ patchedsize(PyObject *self, PyObject *ar
 {
 	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;
-
-	while (bin < binend) {
+	data = bin + 12;
+
+	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;

-- 
Email: thomas at intevation.de
http://intevation.de/~thomas/


More information about the Mercurial-devel mailing list