diff --git a/sparse-index.c b/sparse-index.c index 1fdb07a9e6..3578feb283 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -391,7 +391,7 @@ void expand_index(struct index_state *istate, struct pattern_list *pl) strbuf_setlen(&base, 0); strbuf_add(&base, ce->name, strlen(ce->name)); - read_tree_at(istate->repo, tree, &base, &ps, + read_tree_at(istate->repo, tree, &base, 0, &ps, add_path_to_index, &ctx); /* free directory entries. full entries are re-used */ diff --git a/t/t6700-tree-depth.sh b/t/t6700-tree-depth.sh index d4d17db2ae..93ec41df03 100755 --- a/t/t6700-tree-depth.sh +++ b/t/t6700-tree-depth.sh @@ -63,4 +63,13 @@ test_expect_success 'default limit for git-archive fails gracefully' ' test_must_fail git archive big >/dev/null ' +test_expect_success 'limit recursion of ls-tree -r' ' + git $small_ok ls-tree -r small && + test_must_fail git $small_no ls-tree -r small +' + +test_expect_success 'default limit for ls-tree fails gracefully' ' + test_must_fail git ls-tree -r big >/dev/null +' + test_done diff --git a/tree.c b/tree.c index c745462f96..990f9c9854 100644 --- a/tree.c +++ b/tree.c @@ -10,11 +10,13 @@ #include "alloc.h" #include "tree-walk.h" #include "repository.h" +#include "environment.h" const char *tree_type = "tree"; int read_tree_at(struct repository *r, struct tree *tree, struct strbuf *base, + int depth, const struct pathspec *pathspec, read_tree_fn_t fn, void *context) { @@ -24,6 +26,9 @@ int read_tree_at(struct repository *r, int len, oldlen = base->len; enum interesting retval = entry_not_interesting; + if (depth > max_allowed_tree_depth) + return error("exceeded maximum allowed tree depth"); + if (parse_tree(tree)) return -1; @@ -74,7 +79,7 @@ int read_tree_at(struct repository *r, strbuf_add(base, entry.path, len); strbuf_addch(base, '/'); retval = read_tree_at(r, lookup_tree(r, &oid), - base, pathspec, + base, depth + 1, pathspec, fn, context); strbuf_setlen(base, oldlen); if (retval) @@ -89,7 +94,7 @@ int read_tree(struct repository *r, read_tree_fn_t fn, void *context) { struct strbuf sb = STRBUF_INIT; - int ret = read_tree_at(r, tree, &sb, pathspec, fn, context); + int ret = read_tree_at(r, tree, &sb, 0, pathspec, fn, context); strbuf_release(&sb); return ret; } diff --git a/tree.h b/tree.h index 1b5ecbda6b..cc6ddf51b3 100644 --- a/tree.h +++ b/tree.h @@ -44,6 +44,7 @@ typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const c int read_tree_at(struct repository *r, struct tree *tree, struct strbuf *base, + int depth, const struct pathspec *pathspec, read_tree_fn_t fn, void *context); diff --git a/wt-status.c b/wt-status.c index 5b1378965c..996f8635c3 100644 --- a/wt-status.c +++ b/wt-status.c @@ -739,7 +739,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s) ps.max_depth = -1; strbuf_add(&base, ce->name, ce->ce_namelen); - read_tree_at(istate->repo, tree, &base, &ps, + read_tree_at(istate->repo, tree, &base, 0, &ps, add_file_to_list, s); continue; }