]> git.ipfire.org Git - thirdparty/git.git/commitdiff
archive: expand only a single %(describe) per archive
authorRené Scharfe <l.s.r@web.de>
Sun, 28 Feb 2021 11:22:47 +0000 (12:22 +0100)
committerJunio C Hamano <gitster@pobox.com>
Thu, 11 Mar 2021 21:22:44 +0000 (13:22 -0800)
Every %(describe) placeholder in $Format:...$ strings in files with the
attribute export-subst is expanded by calling git describe.  This can
potentially result in a lot of such calls per archive.  That's OK for
local repositories under control of the user of git archive, but could
be a problem for hosted repositories.

Expand only a single %(describe) placeholder per archive for now to
avoid denial-of-service attacks.  We can make this limit configurable
later if needed, but let's start out simple.

Reported-by: Jeff King <peff@peff.net>
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/gitattributes.txt
archive.c
archive.h
pretty.c
pretty.h
t/t5001-archive-attr.sh

index e84e104f9325526bad7dca6043e897ad21b41906..0a60472bb599fa5cbaecd37cc75f959e75c0078f 100644 (file)
@@ -1174,7 +1174,8 @@ tag then no replacement will be done.  The placeholders are the same
 as those for the option `--pretty=format:` of linkgit:git-log[1],
 except that they need to be wrapped like this: `$Format:PLACEHOLDERS$`
 in the file.  E.g. the string `$Format:%H$` will be replaced by the
-commit hash.
+commit hash.  However, only one `%(describe)` placeholder is expanded
+per archive to avoid denial-of-service attacks.
 
 
 Packing objects
index 5919d9e505088420802c1fd20bcfcaee62072c06..2dd2236ae0cef9a2108e4c11365d7a4ac358c50c 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -37,13 +37,10 @@ void init_archivers(void)
 
 static void format_subst(const struct commit *commit,
                         const char *src, size_t len,
-                        struct strbuf *buf)
+                        struct strbuf *buf, struct pretty_print_context *ctx)
 {
        char *to_free = NULL;
        struct strbuf fmt = STRBUF_INIT;
-       struct pretty_print_context ctx = {0};
-       ctx.date_mode.type = DATE_NORMAL;
-       ctx.abbrev = DEFAULT_ABBREV;
 
        if (src == buf->buf)
                to_free = strbuf_detach(buf, NULL);
@@ -61,7 +58,7 @@ static void format_subst(const struct commit *commit,
                strbuf_add(&fmt, b + 8, c - b - 8);
 
                strbuf_add(buf, src, b - src);
-               format_commit_message(commit, fmt.buf, buf, &ctx);
+               format_commit_message(commit, fmt.buf, buf, ctx);
                len -= c + 1 - src;
                src  = c + 1;
        }
@@ -94,7 +91,7 @@ static void *object_file_to_archive(const struct archiver_args *args,
                strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
                convert_to_working_tree(args->repo->index, path, buf.buf, buf.len, &buf, &meta);
                if (commit)
-                       format_subst(commit, buf.buf, buf.len, &buf);
+                       format_subst(commit, buf.buf, buf.len, &buf, args->pretty_ctx);
                buffer = strbuf_detach(&buf, &size);
                *sizep = size;
        }
@@ -633,12 +630,19 @@ int write_archive(int argc, const char **argv, const char *prefix,
                  const char *name_hint, int remote)
 {
        const struct archiver *ar = NULL;
+       struct pretty_print_describe_status describe_status = {0};
+       struct pretty_print_context ctx = {0};
        struct archiver_args args;
        int rc;
 
        git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
        git_config(git_default_config, NULL);
 
+       describe_status.max_invocations = 1;
+       ctx.date_mode.type = DATE_NORMAL;
+       ctx.abbrev = DEFAULT_ABBREV;
+       ctx.describe_status = &describe_status;
+       args.pretty_ctx = &ctx;
        args.repo = repo;
        args.prefix = prefix;
        string_list_init(&args.extra_files, 1);
index 33551b7ee17be6adf9c16221ef1f605dbf8d477c..49fab71aaf649e1d5576f359eec8dcc0c096bf22 100644 (file)
--- a/archive.h
+++ b/archive.h
@@ -5,6 +5,7 @@
 #include "pathspec.h"
 
 struct repository;
+struct pretty_print_context;
 
 struct archiver_args {
        struct repository *repo;
@@ -22,6 +23,7 @@ struct archiver_args {
        unsigned int convert : 1;
        int compression_level;
        struct string_list extra_files;
+       struct pretty_print_context *pretty_ctx;
 };
 
 /* main api */
index c612d2ac9b0be150647632871823b3e5158d6f3c..032e89cd4e2a2319751cf004c183141a95d70a5a 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -1247,6 +1247,14 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
                struct child_process cmd = CHILD_PROCESS_INIT;
                struct strbuf out = STRBUF_INIT;
                struct strbuf err = STRBUF_INIT;
+               struct pretty_print_describe_status *describe_status;
+
+               describe_status = c->pretty_ctx->describe_status;
+               if (describe_status) {
+                       if (!describe_status->max_invocations)
+                               return 0;
+                       describe_status->max_invocations--;
+               }
 
                cmd.git_cmd = 1;
                strvec_push(&cmd.args, "describe");
index 7ce6c0b437b448b7f384ac3680de5c3e8983d8fb..27b15947ffdce38f65dd88073c40f918ee2ae610 100644 (file)
--- a/pretty.h
+++ b/pretty.h
@@ -23,6 +23,10 @@ enum cmit_fmt {
        CMIT_FMT_UNSPECIFIED
 };
 
+struct pretty_print_describe_status {
+       unsigned int max_invocations;
+};
+
 struct pretty_print_context {
        /*
         * Callers should tweak these to change the behavior of pp_* functions.
@@ -44,6 +48,7 @@ struct pretty_print_context {
        int color;
        struct ident_split *from_ident;
        unsigned encode_email_headers:1;
+       struct pretty_print_describe_status *describe_status;
 
        /*
         * Fields below here are manipulated internally by pp_* functions and
index e9aa97117ab41beab708f4ded34628b015021e4e..712ae52299431c3d31038123a02f895708086bdd 100755 (executable)
@@ -128,4 +128,18 @@ test_expect_success 'export-subst' '
        test_cmp substfile2 archive/substfile2
 '
 
+test_expect_success 'export-subst expands %(describe) once' '
+       echo "\$Format:%(describe)\$" >substfile3 &&
+       echo "\$Format:%(describe)\$" >>substfile3 &&
+       echo "\$Format:%(describe)${LF}%(describe)\$" >substfile4 &&
+       git add substfile[34] &&
+       git commit -m export-subst-describe &&
+       git tag -m export-subst-describe export-subst-describe &&
+       git archive HEAD >archive-describe.tar &&
+       extract_tar_to_dir archive-describe &&
+       desc=$(git describe) &&
+       grep -F "$desc" archive-describe/substfile[34] >substituted &&
+       test_line_count = 1 substituted
+'
+
 test_done