diff --git a/Documentation/RelNotes/2.30.9.txt b/Documentation/RelNotes/2.30.9.txt new file mode 100644 index 0000000000..708d626ce6 --- /dev/null +++ b/Documentation/RelNotes/2.30.9.txt @@ -0,0 +1,43 @@ +Git v2.30.9 Release Notes +========================= + +This release addresses the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007. + + +Fixes since v2.30.8 +------------------- + + * CVE-2023-25652: + + By feeding specially crafted input to `git apply --reject`, a + path outside the working tree can be overwritten with partially + controlled contents (corresponding to the rejected hunk(s) from + the given patch). + + * CVE-2023-25815: + + When Git is compiled with runtime prefix support and runs without + translated messages, it still used the gettext machinery to + display messages, which subsequently potentially looked for + translated messages in unexpected places. This allowed for + malicious placement of crafted messages. + + * CVE-2023-29007: + + When renaming or deleting a section from a configuration file, + certain malicious configuration values may be misinterpreted as + the beginning of a new configuration section, leading to arbitrary + configuration injection. + +Credit for finding CVE-2023-25652 goes to Ry0taK, and the fix was +developed by Taylor Blau, Junio C Hamano and Johannes Schindelin, +with the help of Linus Torvalds. + +Credit for finding CVE-2023-25815 goes to Maxime Escourbiac and +Yassine BENGANA of Michelin, and the fix was developed by Johannes +Schindelin. + +Credit for finding CVE-2023-29007 goes to André Baptista and Vítor Pinho +of Ethiack, and the fix was developed by Taylor Blau, and Johannes +Schindelin, with help from Jeff King, and Patrick Steinhardt. diff --git a/Documentation/RelNotes/2.31.8.txt b/Documentation/RelNotes/2.31.8.txt new file mode 100644 index 0000000000..0aa3080780 --- /dev/null +++ b/Documentation/RelNotes/2.31.8.txt @@ -0,0 +1,6 @@ +Git v2.31.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9 to address the +security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; +see the release notes for that version for details. diff --git a/Documentation/RelNotes/2.32.7.txt b/Documentation/RelNotes/2.32.7.txt new file mode 100644 index 0000000000..7bb35388b5 --- /dev/null +++ b/Documentation/RelNotes/2.32.7.txt @@ -0,0 +1,7 @@ +Git v2.32.7 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9 and v2.31.8 to +address the security issues CVE-2023-25652, CVE-2023-25815, and +CVE-2023-29007; see the release notes for these versions for +details. diff --git a/Documentation/RelNotes/2.33.8.txt b/Documentation/RelNotes/2.33.8.txt new file mode 100644 index 0000000000..d8cf4c7f3a --- /dev/null +++ b/Documentation/RelNotes/2.33.8.txt @@ -0,0 +1,7 @@ +Git v2.33.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8 and +v2.32.7 to address the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007; see the release notes for these +versions for details. diff --git a/Documentation/RelNotes/2.34.8.txt b/Documentation/RelNotes/2.34.8.txt new file mode 100644 index 0000000000..2b5bd7d9a3 --- /dev/null +++ b/Documentation/RelNotes/2.34.8.txt @@ -0,0 +1,7 @@ +Git v2.34.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7 and v2.33.8 to address the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007; see the release notes for these +versions for details. diff --git a/Documentation/RelNotes/2.35.8.txt b/Documentation/RelNotes/2.35.8.txt new file mode 100644 index 0000000000..3c9c094c2b --- /dev/null +++ b/Documentation/RelNotes/2.35.8.txt @@ -0,0 +1,7 @@ +Git v2.35.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7, v2.33.8 and v2.34.8 to address the security issues +CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; see the release +notes for these versions for details. diff --git a/Documentation/RelNotes/2.36.6.txt b/Documentation/RelNotes/2.36.6.txt new file mode 100644 index 0000000000..e1edebcc43 --- /dev/null +++ b/Documentation/RelNotes/2.36.6.txt @@ -0,0 +1,7 @@ +Git v2.36.6 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8 and v2.35.8 to address the security issues +CVE-2023-25652, CVS-2023-25815, and CVE-2023-29007; see the release +notes for these versions for details. diff --git a/Documentation/RelNotes/2.37.7.txt b/Documentation/RelNotes/2.37.7.txt new file mode 100644 index 0000000000..4b8165f4b5 --- /dev/null +++ b/Documentation/RelNotes/2.37.7.txt @@ -0,0 +1,7 @@ +Git v2.37.7 Release Notes +========================= + +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8 and v2.36.6 to address the +security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; +see the release notes for these versions for details. diff --git a/Documentation/RelNotes/2.38.5.txt b/Documentation/RelNotes/2.38.5.txt new file mode 100644 index 0000000000..2d1f3b1249 --- /dev/null +++ b/Documentation/RelNotes/2.38.5.txt @@ -0,0 +1,8 @@ +Git v2.38.5 Release Notes +========================= + +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6 and v2.37.7 to address +the security issues CVE-2023-25652, CVE-2023-25815, and +CVE-2023-29007; see the release notes for these versions for +details. diff --git a/apply.c b/apply.c index 8c7ae3f714..b17e8335b3 100644 --- a/apply.c +++ b/apply.c @@ -4576,7 +4576,7 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) FILE *rej; char namebuf[PATH_MAX]; struct fragment *frag; - int cnt = 0; + int fd, cnt = 0; struct strbuf sb = STRBUF_INIT; for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) { @@ -4616,7 +4616,17 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) memcpy(namebuf, patch->new_name, cnt); memcpy(namebuf + cnt, ".rej", 5); - rej = fopen(namebuf, "w"); + fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd < 0) { + if (errno != EEXIST) + return error_errno(_("cannot open %s"), namebuf); + if (unlink(namebuf)) + return error_errno(_("cannot unlink '%s'"), namebuf); + fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd < 0) + return error_errno(_("cannot open %s"), namebuf); + } + rej = fdopen(fd, "w"); if (!rej) return error_errno(_("cannot open %s"), namebuf); diff --git a/config.c b/config.c index 27f38283ad..8c1c4071f0 100644 --- a/config.c +++ b/config.c @@ -3487,9 +3487,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++) { @@ -3542,6 +3543,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, @@ -3551,11 +3554,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)); @@ -3592,16 +3596,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; /* @@ -3618,7 +3631,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) { @@ -3693,6 +3706,7 @@ out: out_no_rollback: free(filename_buf); config_store_data_clear(&store); + strbuf_release(&buf); return ret; } diff --git a/gettext.c b/gettext.c index f139008d0a..e81357f9ba 100644 --- a/gettext.c +++ b/gettext.c @@ -100,6 +100,8 @@ static void init_gettext_charset(const char *domain) setlocale(LC_CTYPE, "C"); } +int git_gettext_enabled = 0; + void git_setup_gettext(void) { const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT); @@ -119,6 +121,8 @@ void git_setup_gettext(void) init_gettext_charset("git"); textdomain("git"); + git_gettext_enabled = 1; + free(p); } diff --git a/gettext.h b/gettext.h index d209911ebb..484cafa562 100644 --- a/gettext.h +++ b/gettext.h @@ -29,9 +29,11 @@ #define FORMAT_PRESERVING(n) __attribute__((format_arg(n))) #ifndef NO_GETTEXT +extern int git_gettext_enabled; void git_setup_gettext(void); int gettext_width(const char *s); #else +#define git_gettext_enabled (0) static inline void git_setup_gettext(void) { } @@ -45,12 +47,16 @@ static inline FORMAT_PRESERVING(1) const char *_(const char *msgid) { if (!*msgid) return ""; + if (!git_gettext_enabled) + return msgid; return gettext(msgid); } static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2) const char *Q_(const char *msgid, const char *plu, unsigned long n) { + if (!git_gettext_enabled) + return n == 1 ? msgid : plu; return ngettext(msgid, plu, n); } diff --git a/t/t1300-config.sh b/t/t1300-config.sh index 2575279ab8..f1d42b62b0 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 && + grep "refusing to work with overly long line in .y. on line 2" err +' + cat >> .git/config << EOF [branch "zwei"] a = 1 [branch "vier"] EOF diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index 65ac7df2d7..e95e6d4e7d 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -126,4 +126,19 @@ test_expect_success SYMLINKS 'symlink escape when deleting file' ' test_path_is_file .git/delete-me ' +test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' ' + test_when_finished "git reset --hard && git clean -dfx" && + + test_commit file && + echo modified >file.t && + git diff -- file.t >patch && + echo modified-again >file.t && + + ln -s foo file.t.rej && + test_must_fail git apply patch --reject 2>err && + test_i18ngrep "Rejected hunk" err && + test_path_is_missing foo && + test_path_is_file file.t.rej +' + test_done