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.
--- 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;
}