Skip to content

Commit b6551fe

Browse files
derrickstoleegitster
authored andcommitted
merge-tree: load default git config
The 'git merge-tree' command handles creating root trees for merges without using the worktree. This is a critical operation in many Git hosts, as they typically store bare repositories. This builtin does not load the default Git config, which can have several important ramifications. In particular, one config that is loaded by default is core.useReplaceRefs. This is typically disabled in Git hosts due to the ability to spoof commits in strange ways. Since this config is not loaded specifically during merge-tree, users were previously able to use refs/replace/ references to make pull requests that looked valid but introduced malicious content. The resulting merge commit would have the correct commit history, but the malicious content would exist in the root tree of the merge. The fix is simple: load the default Git config in cmd_merge_tree(). This may also fix other behaviors that are effected by reading default config. The only possible downside is a little extra computation time spent reading config. The config parsing is placed after basic argument parsing so it does not slow down usage errors. Helped-by: Johannes Schindelin <[email protected]> Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0d1bd1d commit b6551fe

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

builtin/merge-tree.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "exec-cmd.h"
1414
#include "merge-blobs.h"
1515
#include "quote.h"
16+
#include "config.h"
1617

1718
static int line_termination = '\n';
1819

@@ -620,6 +621,8 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
620621
if (argc != expected_remaining_argc)
621622
usage_with_options(merge_tree_usage, mt_options);
622623

624+
git_config(git_default_config, NULL);
625+
623626
/* Do the relevant type of merge */
624627
if (o.mode == MODE_REAL)
625628
return real_merge(&o, merge_base, argv[0], argv[1], prefix);

t/t4300-merge-tree.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,4 +334,22 @@ test_expect_success 'turn tree to file' '
334334
test_cmp expect actual
335335
'
336336

337+
test_expect_success 'merge-tree respects core.useReplaceRefs=false' '
338+
test_commit merge-to &&
339+
test_commit valid base &&
340+
git reset --hard HEAD^ &&
341+
test_commit malicious base &&
342+
343+
test_when_finished "git replace -d $(git rev-parse valid^0)" &&
344+
git replace valid^0 malicious^0 &&
345+
346+
tree=$(git -c core.useReplaceRefs=true merge-tree --write-tree merge-to valid) &&
347+
merged=$(git cat-file -p $tree:base) &&
348+
test malicious = $merged &&
349+
350+
tree=$(git -c core.useReplaceRefs=false merge-tree --write-tree merge-to valid) &&
351+
merged=$(git cat-file -p $tree:base) &&
352+
test valid = $merged
353+
'
354+
337355
test_done

0 commit comments

Comments
 (0)