70 lines
2.2 KiB
Diff
70 lines
2.2 KiB
Diff
# HG changeset patch
|
|
# User Augie Fackler <augie@google.com>
|
|
# Date 1573571879 18000
|
|
# Node ID 0796e266d26bdc4e116012bb1f8039ee76f2e9c3
|
|
# Parent 38387f9e4d22056b5b75cb9918152447f739dd7d
|
|
dirs: resolve fuzzer OOM situation by disallowing deep directory hierarchies
|
|
|
|
It seems like 2048 directories ought to be enough for any reasonable
|
|
use of Mercurial?
|
|
|
|
A previous version of this patch scanned for slashes before any allocations
|
|
occurred. That approach is slower than this in the happy path, but much faster
|
|
than this in the case that too many slashes are encountered. We may want to
|
|
revisit it in the future using memchr() so it'll be well-optimized by the libc
|
|
we're using.
|
|
|
|
.. bc:
|
|
|
|
Mercurial will now defend against OOMs by refusing to operate on
|
|
paths with 2048 or more components. This means that _extremely_
|
|
deep path hierarchies will be rejected, but we anticipate nobody
|
|
is using hierarchies this deep.
|
|
|
|
Differential Revision: https://phab.mercurial-scm.org/D7411
|
|
|
|
diff -r 38387f9e4d22 -r 0796e266d26b mercurial/cext/dirs.c
|
|
--- a/mercurial/cext/dirs.c Thu Nov 14 14:14:11 2019 -0800
|
|
+++ b/mercurial/cext/dirs.c Tue Nov 12 10:17:59 2019 -0500
|
|
@@ -9,6 +9,7 @@
|
|
|
|
#define PY_SSIZE_T_CLEAN
|
|
#include <Python.h>
|
|
+#include <string.h>
|
|
|
|
#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] == '/') {
|