diff options
-rw-r--r-- | Documentation/git-fast-import.txt | 14 | ||||
-rw-r--r-- | fast-import.c | 25 | ||||
-rwxr-xr-x | t/t9300-fast-import.sh | 23 | ||||
-rw-r--r-- | transport-helper.c | 1 |
4 files changed, 55 insertions, 8 deletions
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 3d3d219e58..fbb3f914f2 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -50,6 +50,20 @@ OPTIONS memory used by fast-import during this run. Showing this output is currently the default, but can be disabled with --quiet. +--allow-unsafe-features:: + Many command-line options can be provided as part of the + fast-import stream itself by using the `feature` or `option` + commands. However, some of these options are unsafe (e.g., + allowing fast-import to access the filesystem outside of the + repository). These options are disabled by default, but can be + allowed by providing this option on the command line. This + currently impacts only the `feature export-marks` command. ++ + Only enable this option if you trust the program generating the + fast-import stream! This option is enabled automatically for + remote-helpers that use the `import` capability, as they are + already trusted to run their own code. + Options for Frontends ~~~~~~~~~~~~~~~~~~~~~ diff --git a/fast-import.c b/fast-import.c index d64609b083..967077ad0b 100644 --- a/fast-import.c +++ b/fast-import.c @@ -366,6 +366,7 @@ static uintmax_t next_mark; static struct strbuf new_data = STRBUF_INIT; static int seen_data_command; static int require_explicit_termination; +static int allow_unsafe_features; /* Signal handling */ static volatile sig_atomic_t checkpoint_requested; @@ -3320,6 +3321,8 @@ static int parse_one_option(const char *option) show_stats = 0; } else if (!strcmp(option, "stats")) { show_stats = 1; + } else if (!strcmp(option, "allow-unsafe-features")) { + ; /* already handled during early option parsing */ } else { return 0; } @@ -3327,6 +3330,13 @@ static int parse_one_option(const char *option) return 1; } +static void check_unsafe_feature(const char *feature, int from_stream) +{ + if (from_stream && !allow_unsafe_features) + die(_("feature '%s' forbidden in input without --allow-unsafe-features"), + feature); +} + static int parse_one_feature(const char *feature, int from_stream) { const char *arg; @@ -3338,6 +3348,7 @@ static int parse_one_feature(const char *feature, int from_stream) } else if (skip_prefix(feature, "import-marks-if-exists=", &arg)) { option_import_marks(arg, from_stream, 1); } else if (skip_prefix(feature, "export-marks=", &arg)) { + check_unsafe_feature(feature, from_stream); option_export_marks(arg); } else if (!strcmp(feature, "get-mark")) { ; /* Don't die - this feature is supported */ @@ -3464,6 +3475,20 @@ int cmd_main(int argc, const char **argv) avail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*)); marks = pool_calloc(1, sizeof(struct mark_set)); + /* + * We don't parse most options until after we've seen the set of + * "feature" lines at the start of the stream (which allows the command + * line to override stream data). But we must do an early parse of any + * command-line options that impact how we interpret the feature lines. + */ + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (*arg != '-' || !strcmp(arg, "--")) + break; + if (!strcmp(arg, "--allow-unsafe-features")) + allow_unsafe_features = 1; + } + global_argc = argc; global_argv = argv; diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 1ba20c1f1a..ba5a35c32c 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -2117,6 +2117,11 @@ test_expect_success 'R: only one import-marks feature allowed per stream' ' test_must_fail git fast-import <input ' +test_expect_success 'R: export-marks feature forbidden by default' ' + echo "feature export-marks=git.marks" >input && + test_must_fail git fast-import <input +' + test_expect_success 'R: export-marks feature results in a marks file being created' ' cat >input <<-EOF && feature export-marks=git.marks @@ -2127,7 +2132,7 @@ test_expect_success 'R: export-marks feature results in a marks file being creat EOF - git fast-import <input && + git fast-import --allow-unsafe-features <input && grep :1 git.marks ' @@ -2140,7 +2145,8 @@ test_expect_success 'R: export-marks options can be overridden by commandline op hi EOF - git fast-import --export-marks=cmdline-sub/other.marks <input && + git fast-import --allow-unsafe-features \ + --export-marks=cmdline-sub/other.marks <input && grep :1 cmdline-sub/other.marks && test_path_is_missing feature-sub ' @@ -2148,7 +2154,7 @@ test_expect_success 'R: export-marks options can be overridden by commandline op test_expect_success 'R: catch typo in marks file name' ' test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null && echo "feature import-marks=nonexistent.marks" | - test_must_fail git fast-import + test_must_fail git fast-import --allow-unsafe-features ' test_expect_success 'R: import and output marks can be the same file' ' @@ -2253,7 +2259,7 @@ test_expect_success 'R: import to output marks works without any content' ' feature export-marks=marks.new EOF - git fast-import <input && + git fast-import --allow-unsafe-features <input && test_cmp marks.out marks.new ' @@ -2263,7 +2269,7 @@ test_expect_success 'R: import marks prefers commandline marks file over the str feature export-marks=marks.new EOF - git fast-import --import-marks=marks.out <input && + git fast-import --import-marks=marks.out --allow-unsafe-features <input && test_cmp marks.out marks.new ' @@ -2276,7 +2282,8 @@ test_expect_success 'R: multiple --import-marks= should be honoured' ' head -n2 marks.out > one.marks && tail -n +3 marks.out > two.marks && - git fast-import --import-marks=one.marks --import-marks=two.marks <input && + git fast-import --import-marks=one.marks --import-marks=two.marks \ + --allow-unsafe-features <input && test_cmp marks.out combined.marks ' @@ -2289,7 +2296,7 @@ test_expect_success 'R: feature relative-marks should be honoured' ' mkdir -p .git/info/fast-import/ && cp marks.new .git/info/fast-import/relative.in && - git fast-import <input && + git fast-import --allow-unsafe-features <input && test_cmp marks.new .git/info/fast-import/relative.out ' @@ -2301,7 +2308,7 @@ test_expect_success 'R: feature no-relative-marks should be honoured' ' feature export-marks=non-relative.out EOF - git fast-import <input && + git fast-import --allow-unsafe-features <input && test_cmp marks.new non-relative.out ' diff --git a/transport-helper.c b/transport-helper.c index a72ed18efb..af519c1ff7 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -431,6 +431,7 @@ static int get_importer(struct transport *transport, struct child_process *fasti child_process_init(fastimport); fastimport->in = helper->out; argv_array_push(&fastimport->args, "fast-import"); + argv_array_push(&fastimport->args, "--allow-unsafe-features"); argv_array_push(&fastimport->args, debug ? "--stats" : "--quiet"); if (data->bidi_import) { |