diff --git a/mercurial/cext/dirs.c b/mercurial/cext/dirs.c --- a/mercurial/cext/dirs.c +++ b/mercurial/cext/dirs.c @@ -9,6 +9,7 @@ #define PY_SSIZE_T_CLEAN #include +#include #include "util.h" @@ -48,12 +49,19 @@ return pos; } +/* Mercurial will fail to run on directory hierarchies deeper than + * this constant, so we should try and keep this constant as big as + * possible. + */ +#define MAX_DIRS_DEPTH 2048 + static int _addpath(PyObject *dirs, PyObject *path) { const char *cpath = PyBytes_AS_STRING(path); Py_ssize_t pos = PyBytes_GET_SIZE(path); PyObject *key = NULL; int ret = -1; + size_t num_slashes = 0; /* This loop is super critical for performance. That's why we inline * access to Python structs instead of going through a supported API. @@ -65,6 +73,12 @@ * unnoticed. */ while ((pos = _finddir(cpath, pos - 1)) != -1) { PyObject *val; + ++num_slashes; + if (num_slashes > MAX_DIRS_DEPTH) { + PyErr_SetString(PyExc_ValueError, + "Directory hierarchy too deep."); + goto bail; + } /* Sniff for trailing slashes, a marker of an invalid input. */ if (pos > 0 && cpath[pos - 1] == '/') {