]> git.ipfire.org Git - thirdparty/git.git/commitdiff
add core.maxTreeDepth config
authorJeff King <peff@peff.net>
Thu, 31 Aug 2023 06:21:00 +0000 (02:21 -0400)
committerJunio C Hamano <gitster@pobox.com>
Thu, 31 Aug 2023 22:51:07 +0000 (15:51 -0700)
Most of our tree traversal algorithms use recursion to visit sub-trees.
For pathologically large trees, this can cause us to run out of stack
space and abort in an uncontrolled way. Let's put our own limit here so
that we can fail gracefully rather than segfaulting.

In similar cases where we recursed along the commit graph, we rewrote
the algorithms to avoid recursion and keep any stack data on the heap.
But the commit graph is meant to grow without bound, whereas it's not an
imposition to put a limit on the maximum size of tree we'll handle.

And this has a bonus side effect: coupled with a limit on individual
tree entry names, this limits the total size of a path we may encounter.
This gives us an extra protection against code handling long path names
which may suffer from integer overflows in the size (which could then be
exploited by malicious trees).

The default of 4096 is set to be much longer than anybody would care
about in the real world. Even with single-letter interior tree names
(like "a/b/c"), such a path is at least 8191 bytes. While most operating
systems will let you create such a path incrementally, trying to
reference the whole thing in a system call (as Git would do when
actually trying to access it) will result in ENAMETOOLONG. Coupled with
the recent fsck.largePathname warning, the maximum total pathname Git
will handle is (by default) 16MB.

This config option doesn't do anything yet; future patches will convert
various algorithms to respect the limit.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config/core.txt
config.c
environment.c
environment.h

index dfbdaf00b8bc2239e7e106c8b78a2dd90d44ac9b..0e8c2832bf9b8a5251c51f346ecfcf47c7e8d530 100644 (file)
@@ -736,3 +736,9 @@ core.abbrev::
        If set to "no", no abbreviation is made and the object names
        are shown in their full length.
        The minimum length is 4.
+
+core.maxTreeDepth::
+       The maximum depth Git is willing to recurse while traversing a
+       tree (e.g., "a/b/cde/f" has a depth of 4). This is a fail-safe
+       to allow Git to abort cleanly, and should not generally need to
+       be adjusted. The default is 4096.
index 3846a37be971c92153eb1ceeb65c6e612c8e173c..2ea39295cd6ee8060cab8b4822250bbc020d6d0a 100644 (file)
--- a/config.c
+++ b/config.c
@@ -1801,6 +1801,11 @@ static int git_default_core_config(const char *var, const char *value,
                return 0;
        }
 
+       if (!strcmp(var, "core.maxtreedepth")) {
+               max_allowed_tree_depth = git_config_int(var, value, ctx->kvi);
+               return 0;
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return platform_core_config(var, value, ctx, cb);
 }
index f98d76f08047f14f49e9d3c3d1a4232c500efbf1..8e25b5ef02acca38d27de800082c8ed65829be9b 100644 (file)
@@ -81,6 +81,7 @@ int merge_log_config = -1;
 int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
 unsigned long pack_size_limit_cfg;
 enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
+int max_allowed_tree_depth = 4096;
 
 #ifndef PROTECT_HFS_DEFAULT
 #define PROTECT_HFS_DEFAULT 0
index c5377473c683390992315f69a63c557b25c655bb..e5351c9dd95ea6e7afe77b1db466d6ab30310491 100644 (file)
@@ -132,6 +132,7 @@ extern size_t packed_git_limit;
 extern size_t delta_base_cache_limit;
 extern unsigned long big_file_threshold;
 extern unsigned long pack_size_limit_cfg;
+extern int max_allowed_tree_depth;
 
 /*
  * Accessors for the core.sharedrepository config which lazy-load the value