diff --git a/SOURCES/git-2.27.0-cve-2023-25652-cve-2023-25815-cve-2023-29007.patch b/SOURCES/git-2.27.0-cve-2023-25652-cve-2023-25815-cve-2023-29007.patch new file mode 100644 index 0000000..ecdeb5c --- /dev/null +++ b/SOURCES/git-2.27.0-cve-2023-25652-cve-2023-25815-cve-2023-29007.patch @@ -0,0 +1,348 @@ +diff -ur b/apply.c a/apply.c +--- b/apply.c 2020-06-01 17:49:27.000000000 +0200 ++++ a/apply.c 2023-05-03 13:53:00.200547081 +0200 +@@ -4516,7 +4516,7 @@ + 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) { +@@ -4556,7 +4556,17 @@ + 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 -ur b/builtin/clone.c a/builtin/clone.c +--- b/builtin/clone.c 2020-06-01 17:49:27.000000000 +0200 ++++ a/builtin/clone.c 2023-05-03 13:52:23.803339233 +0200 +@@ -248,6 +248,15 @@ + while (start < end && is_dir_sep(end[-1])) + end--; + } ++ ++ /* ++ * It should not be possible to overflow `ptrdiff_t` by passing in an ++ * insanely long URL, but GCC does not know that and will complain ++ * without this check. ++ */ ++ if (end - start < 0) ++ die(_("No directory name could be guessed.\n" ++ "Please specify a directory on the command line")); + + /* + * Strip trailing port number if we've got only a +diff -ur b/compat/nedmalloc/nedmalloc.c a/compat/nedmalloc/nedmalloc.c +--- b/compat/nedmalloc/nedmalloc.c 2020-06-01 17:49:27.000000000 +0200 ++++ a/compat/nedmalloc/nedmalloc.c 2023-05-03 13:51:33.546052246 +0200 +@@ -323,7 +323,6 @@ + } + static void DestroyCaches(nedpool *p) THROWSPEC + { +- if(p->caches) + { + threadcache *tc; + int n; +diff -ur b/compat/win32/syslog.c a/compat/win32/syslog.c +--- b/compat/win32/syslog.c 2020-06-01 17:49:27.000000000 +0200 ++++ a/compat/win32/syslog.c 2023-05-03 13:51:35.154061429 +0200 +@@ -43,6 +43,7 @@ + va_end(ap); + + while ((pos = strstr(str, "%1")) != NULL) { ++ size_t offset = pos - str; + char *oldstr = str; + str = realloc(str, st_add(++str_len, 1)); + if (!str) { +@@ -50,6 +51,7 @@ + warning_errno("realloc failed"); + return; + } ++ pos = str + offset; + memmove(pos + 2, pos + 1, strlen(pos)); + pos[1] = ' '; + } +diff -ur b/config.c a/config.c +--- b/config.c 2020-06-01 17:49:27.000000000 +0200 ++++ a/config.c 2023-05-03 13:50:49.378800030 +0200 +@@ -3009,9 +3009,10 @@ + multi_replace); + } + +-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++) { +@@ -3064,6 +3065,8 @@ + 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, +@@ -3073,11 +3076,12 @@ + 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)); + +@@ -3114,16 +3118,25 @@ + goto out; + } + +- while (fgets(buf, sizeof(buf), config_file)) { +- int 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; + + /* +@@ -3140,7 +3153,7 @@ + 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) { +@@ -3215,6 +3228,7 @@ + out_no_rollback: + free(filename_buf); + config_store_data_clear(&store); ++ strbuf_release(&buf); + return ret; + } + +diff -ur b/gettext.c a/gettext.c +--- b/gettext.c 2020-06-01 17:49:27.000000000 +0200 ++++ a/gettext.c 2023-05-03 13:47:46.953758294 +0200 +@@ -173,6 +173,8 @@ + setlocale(LC_CTYPE, "C"); + } + ++int git_gettext_enabled = 0; ++ + void git_setup_gettext(void) + { + const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT); +@@ -194,6 +196,8 @@ + init_gettext_charset("git"); + textdomain("git"); + ++ git_gettext_enabled = 1; ++ + free(p); + } + +diff -ur b/gettext.h a/gettext.h +--- b/gettext.h 2020-06-01 17:49:27.000000000 +0200 ++++ a/gettext.h 2023-05-03 13:46:54.234457247 +0200 +@@ -31,9 +31,11 @@ + int use_gettext_poison(void); + + #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) + { + use_gettext_poison(); /* getenv() reentrancy paranoia */ +@@ -48,7 +50,8 @@ + { + if (!*msgid) + return ""; +- return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid); ++ return use_gettext_poison() ? "# GETTEXT POISON #" : ++ !git_gettext_enabled ? msgid : gettext(msgid); + } + + static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2) +@@ -56,6 +59,8 @@ + { + if (use_gettext_poison()) + return "# GETTEXT POISON #"; ++ if (!git_gettext_enabled) ++ return n == 1 ? msgid : plu; + return ngettext(msgid, plu, n); + } + +diff -ur b/range-diff.c a/range-diff.c +--- b/range-diff.c 2020-06-01 17:49:27.000000000 +0200 ++++ a/range-diff.c 2023-05-03 13:44:54.980776256 +0200 +@@ -25,17 +25,6 @@ + struct object_id oid; + }; + +-static size_t find_end_of_line(char *buffer, unsigned long size) +-{ +- char *eol = memchr(buffer, '\n', size); +- +- if (!eol) +- return size; +- +- *eol = '\0'; +- return eol + 1 - buffer; +-} +- + /* + * Reads the patches into a string list, with the `util` field being populated + * as struct object_id (will need to be free()d). +@@ -48,7 +37,7 @@ + struct patch_util *util = NULL; + int in_header = 1; + char *line, *current_filename = NULL; +- int offset, len; ++ ssize_t len; + size_t size; + + argv_array_pushl(&cp.args, "log", "--no-color", "-p", "--no-merges", +@@ -83,11 +72,18 @@ + + line = contents.buf; + size = contents.len; +- for (offset = 0; size > 0; offset += len, size -= len, line += len) { ++ for (; size > 0; size -= len, line += len) { + const char *p; ++ char *eol; ++ ++ eol = memchr(line, '\n', size); ++ if (eol) { ++ *eol = '\0'; ++ len = eol + 1 - line; ++ } else { ++ len = size; ++ } + +- len = find_end_of_line(line, size); +- line[len - 1] = '\0'; + if (skip_prefix(line, "commit ", &p)) { + if (util) { + string_list_append(list, buf.buf)->util = util; +@@ -129,7 +125,8 @@ + strbuf_addch(&buf, '\n'); + if (!util->diff_offset) + util->diff_offset = buf.len; +- line[len - 1] = '\n'; ++ if (eol) ++ *eol = '\n'; + orig_len = len; + len = parse_git_diff_header(&root, &linenr, 0, line, + len, size, &patch); +diff -ur b/t/t1300-config.sh a/t/t1300-config.sh +--- b/t/t1300-config.sh 2020-06-01 17:49:27.000000000 +0200 ++++ a/t/t1300-config.sh 2023-05-03 13:39:43.864071831 +0200 +@@ -616,6 +616,36 @@ + 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 +diff -ur b/t/t4115-apply-symlink.sh a/t/t4115-apply-symlink.sh +--- b/t/t4115-apply-symlink.sh 2020-06-01 17:49:27.000000000 +0200 ++++ a/t/t4115-apply-symlink.sh 2023-05-03 13:39:01.453839938 +0200 +@@ -44,4 +44,17 @@ + + ' + ++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 +Only in a: .vscode diff --git a/SPECS/git.spec b/SPECS/git.spec index ac75ec7..8a08e84 100644 --- a/SPECS/git.spec +++ b/SPECS/git.spec @@ -103,7 +103,7 @@ Name: %{?scl_prefix}git Version: 2.27.0 -Release: 4%{?rcrev}%{?dist} +Release: 6%{?rcrev}%{?dist} Summary: Fast Version Control System License: GPLv2 URL: https://git-scm.com/ @@ -150,6 +150,12 @@ Patch5: 0002-t-lib-git-daemon-try-harder-to-find-a-port.patch # https://github.com/tmzullinger/git/commit/aa5105dc11 Patch6: t-lib-git-svn-try-harder-to-find-a-port-2.31.1.patch +# This patch backports most of the changes that appear in +# https://github.com/git/git/compare/v2.30.8..v2.30.9 +# apart from ci/ and CURL changes +Patch7: git-2.27.0-cve-2023-25652-cve-2023-25815-cve-2023-29007.patch + + %if %{with docs} # pod2man is needed to build Git.3pm BuildRequires: %{?scl:%{_root_bindir}}%{!?scl:%{_bindir}}/pod2man @@ -1073,6 +1079,14 @@ rmdir --ignore-fail-on-non-empty "$testdir" %{?with_docs:%{_pkgdocdir}/git-svn.html} %changelog +* Mon May 22 2023 Ondřej Pohořelský - 2.27.0-6 +- Fixes CVE-2023-25652 +- Resolves: #2188368 + +* Wed May 17 2023 Ondřej Pohořelský - 2.27.0-5 +- Fixes CVE-2023-25815 and CVE-2023-29007 +- Resolves: #2188375 + * Mon Jan 30 2023 Ondřej Pohořelský - 2.27.0-4 - Fixes CVE-2022-23521 and CVE-2022-41903 - Tests: try harder to find open ports for apache, git, and svn