revlog: catch revlog corruption in index_baserev stable
authorBoris Feld <boris.feld@octobus.net>
Thu, 27 Dec 2018 23:34:37 +0100
branchstable
changeset 41018 f4113489e4d4
parent 41017 d7d3164e6a31
child 41019 7542466b94e2
child 41078 46e0563c67db
revlog: catch revlog corruption in index_baserev A revision cannot use a base above itself, it can only happens one corrupted repository. Ignoring such corrupted could lead to infinite loop.
mercurial/cext/revlog.c
--- a/mercurial/cext/revlog.c	Fri Dec 21 17:36:12 2018 -0500
+++ b/mercurial/cext/revlog.c	Thu Dec 27 23:34:37 2018 +0100
@@ -842,10 +842,11 @@
 static inline int index_baserev(indexObject *self, int rev)
 {
 	const char *data;
+	int result;
 
 	if (rev >= self->length) {
 		PyObject *tuple = PyList_GET_ITEM(self->added, rev - self->length);
-		return (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3));
+		result = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 3));
 	}
 	else {
 		data = index_deref(self, rev);
@@ -853,8 +854,16 @@
 			return -2;
 		}
 
-		return getbe32(data + 16);
+		result = getbe32(data + 16);
 	}
+	if (result > rev) {
+		PyErr_Format(
+		    PyExc_ValueError,
+		    "corrupted revlog, revision base above revision: %d, %d",
+		    rev, result);
+		return -2;
+	}
+	return result;
 }
 
 static PyObject *index_deltachain(indexObject *self, PyObject *args)