rust: fix possible out-of-bounds read through index_get_parents() stable
authorYuya Nishihara <yuya@tcha.org>
Sun, 28 Oct 2018 21:29:04 +0900
branchstable
changeset 40813 884321cd26c3
parent 40812 9cdd525d97b2
child 40814 9b1d5eea07f9
rust: fix possible out-of-bounds read through index_get_parents() index_get_parents() is an internal function, which doesn't check if the specified rev is valid. If rustlazyancestors() were instantiated with an invalid stoprev, it would access to invalid memory region. This is NOT a security fix as there's no Python code triggering the bug, but included in this series to not give a notion about the memory issue fixed by the previous patch.
mercurial/cext/revlog.c
--- a/mercurial/cext/revlog.c	Thu Nov 01 20:32:59 2018 +0900
+++ b/mercurial/cext/revlog.c	Sun Oct 28 21:29:04 2018 +0900
@@ -2314,7 +2314,7 @@
 /* FFI exposed from Rust code */
 rustlazyancestorsObject *rustlazyancestors_init(
 	indexObject *index,
-	/* to pass index_get_parents() */
+	/* to pass index_get_parents_checked() */
 	int (*)(indexObject *, Py_ssize_t, int*, int),
 	/* intrevs vector */
 	Py_ssize_t initrevslen, long *initrevs,
@@ -2324,6 +2324,16 @@
 int rustlazyancestors_next(rustlazyancestorsObject *self);
 int rustlazyancestors_contains(rustlazyancestorsObject *self, long rev);
 
+static int index_get_parents_checked(indexObject *self, Py_ssize_t rev,
+                                     int *ps, int maxrev)
+{
+	if (rev < 0 || rev >= index_length(self)) {
+		PyErr_SetString(PyExc_ValueError, "rev out of range");
+		return -1;
+	}
+	return index_get_parents(self, rev, ps, maxrev);
+}
+
 /* CPython instance methods */
 static int rustla_init(rustlazyancestorsObject *self,
                        PyObject *args) {
@@ -2364,12 +2374,13 @@
 		goto bail;
 
 	self->iter = rustlazyancestors_init(index,
-		                            index_get_parents,
+		                            index_get_parents_checked,
 		                            linit, initrevs,
 		                            stoprev, inclusive);
 	if (self->iter == NULL) {
 		/* if this is because of GraphError::ParentOutOfRange
-		 * index_get_parents() has already set the proper ValueError */
+		 * index_get_parents_checked() has already set the proper
+		 * ValueError */
 		goto bail;
 	}