| From 057c07a7b1fae22fdeef26c243f4cfbe3afc90ce Mon Sep 17 00:00:00 2001 |
| From: Taylor Blau <me@ttaylorr.com> |
| Date: Fri, 14 Apr 2023 11:46:59 -0400 |
| Subject: [PATCH] Merge branch 'tb/config-copy-or-rename-in-file-injection' |
| |
| Avoids issues with renaming or deleting sections with long lines, where |
| configuration values may be interpreted as sections, leading to |
| configuration injection. Addresses CVE-2023-29007. |
| |
| * tb/config-copy-or-rename-in-file-injection: |
| config.c: disallow overly-long lines in `copy_or_rename_section_in_file()` |
| config.c: avoid integer truncation in `copy_or_rename_section_in_file()` |
| config: avoid fixed-sized buffer when renaming/deleting a section |
| t1300: demonstrate failure when renaming sections with long lines |
| |
| Signed-off-by: Taylor Blau <me@ttaylorr.com> |
| |
| Upstream-Status: Backport |
| CVE: CVE-2023-29007 |
| |
| Reference to upstream patch: |
| https://github.com/git/git/commit/528290f8c61222433a8cf02fb7cfffa8438432b4 |
| |
| Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com> |
| --- |
| config.c | 36 +++++++++++++++++++++++++----------- |
| t/t1300-config.sh | 30 ++++++++++++++++++++++++++++++ |
| 2 files changed, 55 insertions(+), 11 deletions(-) |
| |
| diff --git a/config.c b/config.c |
| index 2bffa8d..6a01938 100644 |
| --- a/config.c |
| +++ b/config.c |
| @@ -3192,9 +3192,10 @@ void git_config_set_multivar(const char *key, const char *value, |
| flags); |
| } |
| |
| -static int section_name_match (const char *buf, const char *name) |
| +static size_t section_name_match (const char *buf, const char *name) |
| { |
| - int i = 0, j = 0, dot = 0; |
| + size_t i = 0, j = 0; |
| + int dot = 0; |
| if (buf[i] != '[') |
| return 0; |
| for (i = 1; buf[i] && buf[i] != ']'; i++) { |
| @@ -3247,6 +3248,8 @@ static int section_name_is_ok(const char *name) |
| return 1; |
| } |
| |
| +#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024) |
| + |
| /* if new_name == NULL, the section is removed instead */ |
| static int git_config_copy_or_rename_section_in_file(const char *config_filename, |
| const char *old_name, |
| @@ -3256,11 +3259,12 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename |
| char *filename_buf = NULL; |
| struct lock_file lock = LOCK_INIT; |
| int out_fd; |
| - char buf[1024]; |
| + struct strbuf buf = STRBUF_INIT; |
| FILE *config_file = NULL; |
| struct stat st; |
| struct strbuf copystr = STRBUF_INIT; |
| struct config_store_data store; |
| + uint32_t line_nr = 0; |
| |
| memset(&store, 0, sizeof(store)); |
| |
| @@ -3297,16 +3301,25 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename |
| goto out; |
| } |
| |
| - while (fgets(buf, sizeof(buf), config_file)) { |
| - unsigned i; |
| - int length; |
| + while (!strbuf_getwholeline(&buf, config_file, '\n')) { |
| + size_t i, length; |
| int is_section = 0; |
| - char *output = buf; |
| - for (i = 0; buf[i] && isspace(buf[i]); i++) |
| + char *output = buf.buf; |
| + |
| + line_nr++; |
| + |
| + if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) { |
| + ret = error(_("refusing to work with overly long line " |
| + "in '%s' on line %"PRIuMAX), |
| + config_filename, (uintmax_t)line_nr); |
| + goto out; |
| + } |
| + |
| + for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++) |
| ; /* do nothing */ |
| - if (buf[i] == '[') { |
| + if (buf.buf[i] == '[') { |
| /* it's a section */ |
| - int offset; |
| + size_t offset; |
| is_section = 1; |
| |
| /* |
| @@ -3323,7 +3336,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename |
| strbuf_reset(©str); |
| } |
| |
| - offset = section_name_match(&buf[i], old_name); |
| + offset = section_name_match(&buf.buf[i], old_name); |
| if (offset > 0) { |
| ret++; |
| if (new_name == NULL) { |
| @@ -3398,6 +3411,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename |
| out_no_rollback: |
| free(filename_buf); |
| config_store_data_clear(&store); |
| + strbuf_release(&buf); |
| return ret; |
| } |
| |
| diff --git a/t/t1300-config.sh b/t/t1300-config.sh |
| index 78359f1..b07feb1 100755 |
| --- a/t/t1300-config.sh |
| +++ b/t/t1300-config.sh |
| @@ -617,6 +617,36 @@ test_expect_success 'renaming to bogus section is rejected' ' |
| test_must_fail git config --rename-section branch.zwei "bogus name" |
| ' |
| |
| +test_expect_success 'renaming a section with a long line' ' |
| + { |
| + printf "[b]\\n" && |
| + printf " c = d %1024s [a] e = f\\n" " " && |
| + printf "[a] g = h\\n" |
| + } >y && |
| + git config -f y --rename-section a xyz && |
| + test_must_fail git config -f y b.e |
| +' |
| + |
| +test_expect_success 'renaming an embedded section with a long line' ' |
| + { |
| + printf "[b]\\n" && |
| + printf " c = d %1024s [a] [foo] e = f\\n" " " && |
| + printf "[a] g = h\\n" |
| + } >y && |
| + git config -f y --rename-section a xyz && |
| + test_must_fail git config -f y foo.e |
| +' |
| + |
| +test_expect_success 'renaming a section with an overly-long line' ' |
| + { |
| + printf "[b]\\n" && |
| + printf " c = d %525000s e" " " && |
| + printf "[a] g = h\\n" |
| + } >y && |
| + test_must_fail git config -f y --rename-section a xyz 2>err && |
| + test_i18ngrep "refusing to work with overly long line in .y. on line 2" err |
| +' |
| + |
| cat >> .git/config << EOF |
| [branch "zwei"] a = 1 [branch "vier"] |
| EOF |
| -- |
| 2.40.0 |