Skip to content

Commit 670a1da

Browse files
peffgitster
authored andcommitted
list-objects: respect max_allowed_tree_depth
The tree traversal in list-objects.c, which is used by "rev-list --objects", etc, uses recursion and may run out of stack space. Let's teach it about the new core.maxTreeDepth config option. We unfortunately can't return an error here, as this code doesn't produce an error return at all. We'll die() instead, which matches the behavior when we see an otherwise broken tree. Note that this will also generally reject such deep trees from entering the repository from a fetch or push, due to the use of rev-list in the connectivity check. But it's not foolproof! We stop traversing when we see an UNINTERESTING object, and the connectivity check marks existing ref tips as UNINTERESTING. So imagine commit X has a tree with maximum depth N. If you then create a new commit Y with a tree entry "Y:subdir" that points to "X^{tree}", then the depth of Y will be N+1. But a connectivity check running "git rev-list --objects Y --not X" won't realize that; it will stop traversing at X^{tree}, since that was already reachable. So this will stop naive pushes of too-deep trees, but not carefully crafted malicious ones. Doing it robustly and efficiently would require caching the maximum depth of each tree (i.e., the longest path to any leaf entry). That's much more complex and not strictly needed. If each recursive algorithm limits itself already, then that's sufficient. Blocking the objects from entering the repo would be a nice belt-and-suspenders addition, but it's not worth the extra cost. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1ee7a5c commit 670a1da

File tree

2 files changed

+17
-0
lines changed

2 files changed

+17
-0
lines changed

list-objects.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
#include "packfile.h"
1515
#include "object-store-ll.h"
1616
#include "trace.h"
17+
#include "environment.h"
1718

1819
struct traversal_context {
1920
struct rev_info *revs;
2021
show_object_fn show_object;
2122
show_commit_fn show_commit;
2223
void *show_data;
2324
struct filter *filter;
25+
int depth;
2426
};
2527

2628
static void show_commit(struct traversal_context *ctx,
@@ -118,7 +120,9 @@ static void process_tree_contents(struct traversal_context *ctx,
118120
entry.path, oid_to_hex(&tree->object.oid));
119121
}
120122
t->object.flags |= NOT_USER_GIVEN;
123+
ctx->depth++;
121124
process_tree(ctx, t, base, entry.path);
125+
ctx->depth--;
122126
}
123127
else if (S_ISGITLINK(entry.mode))
124128
; /* ignore gitlink */
@@ -156,6 +160,9 @@ static void process_tree(struct traversal_context *ctx,
156160
!revs->include_check_obj(&tree->object, revs->include_check_data))
157161
return;
158162

163+
if (ctx->depth > max_allowed_tree_depth)
164+
die("exceeded maximum allowed tree depth");
165+
159166
failed_parse = parse_tree_gently(tree, 1);
160167
if (failed_parse) {
161168
if (revs->ignore_missing_links)
@@ -349,6 +356,7 @@ static void traverse_non_commits(struct traversal_context *ctx,
349356
if (!path)
350357
path = "";
351358
if (obj->type == OBJ_TREE) {
359+
ctx->depth = 0;
352360
process_tree(ctx, (struct tree *)obj, base, path);
353361
continue;
354362
}

t/t6700-tree-depth.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,13 @@ test_expect_success 'default limit for ls-tree fails gracefully' '
7272
test_must_fail git ls-tree -r big >/dev/null
7373
'
7474

75+
test_expect_success 'limit recursion of rev-list --objects' '
76+
git $small_ok rev-list --objects small >/dev/null &&
77+
test_must_fail git $small_no rev-list --objects small >/dev/null
78+
'
79+
80+
test_expect_success 'default limit for rev-list fails gracefully' '
81+
test_must_fail git rev-list --objects big >/dev/null
82+
'
83+
7584
test_done

0 commit comments

Comments
 (0)