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 53579 884321cd26c30d4ea7a693b467c41270e612cde8
parent 53578 9cdd525d97b24812f525056d831ce456c8ba714a
child 53580 9b1d5eea07f9be73df44f70a65cbc511f8063f81
push id1079
push usergszorc@mozilla.com
push dateMon, 10 Dec 2018 19:44:59 +0000
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
+++ b/mercurial/cext/revlog.c
@@ -2309,26 +2309,36 @@ struct rustlazyancestorsObjectStruct {
 	/* Type-specific fields go here. */
 	indexObject *index;    /* Ref kept to avoid GC'ing the index */
 	void *iter;        /* Rust iterator */
 };
 
 /* 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,
 	long stoprev,
 	int inclusive);
 void rustlazyancestors_drop(rustlazyancestorsObject *self);
 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) {
 	PyObject *initrevsarg = NULL;
 	PyObject *inclusivearg = NULL;
 	long stoprev = 0;
 	long *initrevs = NULL;
 	int inclusive = 0;
@@ -2359,22 +2369,23 @@ static int rustla_init(rustlazyancestors
 
 	for (i=0; i<linit; i++) {
 		initrevs[i] = PyInt_AsLong(PyList_GET_ITEM(initrevsarg, i));
 	}
 	if (PyErr_Occurred())
 		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;
 	}
 
 	free(initrevs);
 	return 0;
 
 bail:
 	free(initrevs);