diff --git a/backport-CVE-2025-48384-config-quote-values-containing-CR-character.patch b/backport-CVE-2025-48384-config-quote-values-containing-CR-character.patch new file mode 100644 index 0000000000000000000000000000000000000000..fb140837944f2974982e364e39b2a7558261f944 --- /dev/null +++ b/backport-CVE-2025-48384-config-quote-values-containing-CR-character.patch @@ -0,0 +1,123 @@ +From 05e9cd64ee23bbadcea6bcffd6660ed02b8eab89 Mon Sep 17 00:00:00 2001 +From: Justin Tobler +Date: Mon, 19 May 2025 21:26:04 -0500 +Subject: [PATCH] config: quote values containing CR character + +When reading the config, values that contain a trailing CRLF are +stripped. If the value itself has a trailing CR, the normal LF that +follows results in the CR being unintentionally stripped. This may lead +to unintended behavior due to the config value written being different +when it gets read. + +One such issue involves a repository with a submodule path containing a +trailing CR. When the submodule gets initialized, the submodule is +cloned without being checked out and has "core.worktree" set to the +submodule path. The git-checkout(1) that gets spawned later reads the +"core.worktree" config value, but without the trailing CR, and +consequently attempts to checkout to a different path than intended. + +If the repository contains a matching path that is a symlink, it is +possible for the submodule repository to be checked out in arbitrary +locations. This is extra bad when the symlink points to the submodule +hooks directory and the submodule repository contains an executable +"post-checkout" hook. Once the submodule repository checkout completes, +the "post-checkout" hook immediately executes. + +To prevent mismatched config state due to misinterpreting a trailing CR, +wrap config values containing CR in double quotes when writing the +entry. This ensures a trailing CR is always separated for an LF and thus +prevented from getting stripped. + +Note that this problem cannot be addressed by just quoting each CR with +"\r". The reading side of the config interprets only a few backslash +escapes, and "\r" is not among them. This fix is sufficient though +because it only affects the CR at the end of a line and any literal CR +in the interior is already preserved. + +Co-authored-by: David Leadbeater +Signed-off-by: Justin Tobler +Signed-off-by: Taylor Blau +--- + config.c | 2 +- + t/t1300-config.sh | 11 +++++++++++ + t/t7415-submodule-names.sh | 33 +++++++++++++++++++++++++++++++++ + 3 files changed, 45 insertions(+), 1 deletion(-) + +diff --git a/config.c b/config.c +index 9ff6ae1cb9..629981451d 100644 +--- a/config.c ++++ b/config.c +@@ -2999,7 +2999,7 @@ static ssize_t write_pair(int fd, const char *key, const char *value, + if (value[0] == ' ') + quote = "\""; + for (i = 0; value[i]; i++) +- if (value[i] == ';' || value[i] == '#') ++ if (value[i] == ';' || value[i] == '#' || value[i] == '\r') + quote = "\""; + if (i && value[i - 1] == ' ') + quote = "\""; +diff --git a/t/t1300-config.sh b/t/t1300-config.sh +index f4e2752134..1010410b7e 100755 +--- a/t/t1300-config.sh ++++ b/t/t1300-config.sh +@@ -2590,4 +2590,15 @@ test_expect_success '--replace-all does not invent newlines' ' + test_cmp expect .git/config + ' + ++test_expect_success 'writing value with trailing CR not stripped on read' ' ++ test_when_finished "rm -rf cr-test" && ++ ++ printf "bar\r\n" >expect && ++ git init cr-test && ++ git -C cr-test config --add core.foo $(printf "bar\r") && ++ git -C cr-test config --get core.foo >actual && ++ ++ test_cmp expect actual ++' ++ + test_done +diff --git a/t/t7415-submodule-names.sh b/t/t7415-submodule-names.sh +index 5b845e899b..2026285566 100755 +--- a/t/t7415-submodule-names.sh ++++ b/t/t7415-submodule-names.sh +@@ -347,4 +347,37 @@ test_expect_success 'git dirs of sibling submodules must not be nested' ' + test_i18ngrep "is inside git dir" err + ' + ++test_expect_success SYMLINKS,!WINDOWS,!MINGW 'submodule must not checkout into different directory' ' ++ test_when_finished "rm -rf sub repo bad-clone" && ++ ++ git init sub && ++ write_script sub/post-checkout <<-\EOF && ++ touch "$PWD/foo" ++ EOF ++ git -C sub add post-checkout && ++ git -C sub commit -m hook && ++ ++ git init repo && ++ git -C repo -c protocol.file.allow=always submodule add "$PWD/sub" sub && ++ git -C repo mv sub $(printf "sub\r") && ++ ++ # Ensure config values containing CR are wrapped in quotes. ++ git config --unset -f repo/.gitmodules submodule.sub.path && ++ printf "\tpath = \"sub\r\"\n" >>repo/.gitmodules && ++ ++ git config --unset -f repo/.git/modules/sub/config core.worktree && ++ { ++ printf "[core]\n" && ++ printf "\tworktree = \"../../../sub\r\"\n" ++ } >>repo/.git/modules/sub/config && ++ ++ ln -s .git/modules/sub/hooks repo/sub && ++ git -C repo add -A && ++ git -C repo commit -m submodule && ++ ++ git -c protocol.file.allow=always clone --recurse-submodules repo bad-clone && ++ ! test -f "$PWD/foo" && ++ test -f $(printf "bad-clone/sub\r/post-checkout") ++' ++ + test_done +-- +2.33.0 + diff --git a/backport-CVE-2025-48386-wincred-avoid-buffer-overflow-in-wcsncat.patch b/backport-CVE-2025-48386-wincred-avoid-buffer-overflow-in-wcsncat.patch new file mode 100644 index 0000000000000000000000000000000000000000..f82ba1996d9f856f03a44adb69e8f006a3cd93f5 --- /dev/null +++ b/backport-CVE-2025-48386-wincred-avoid-buffer-overflow-in-wcsncat.patch @@ -0,0 +1,93 @@ +From 9de345cb273cc7faaeda279c7e07149d8a15a319 Mon Sep 17 00:00:00 2001 +From: Taylor Blau +Date: Mon, 19 May 2025 18:30:29 -0400 +Subject: [PATCH] wincred: avoid buffer overflow in wcsncat() + +The wincred credential helper uses a static buffer ("target") as a +unique key for storing and comparing against internal storage. It does +this by building up a string is supposed to look like: + + git:$PROTOCOL://$USERNAME@$HOST/@PATH + +However, the static "target" buffer is declared as a wide string with no +more than 1,024 wide characters. The first call to wcsncat() is almost +correct (it copies no more than ARRAY_SIZE(target) wchar_t's), but does +not account for the trailing NUL, introducing an off-by-one error. + +But subsequent calls to wcsncat() have an additional problem on top of +the off-by-one. They do not account for the length of the existing +wide string being built up in 'target'. So the following: + + $ perl -e ' + my $x = "x" x 1_000; + print "protocol=$x\nhost=$x\nusername=$x\npath=$x\n" + ' | + C\:/Program\ Files/Git/mingw64/libexec/git-core/git-credential-wincred.exe get + +will result in a segmentation fault from over-filling buffer. + +This bug is as old as the wincred helper itself, dating back to +a6253da0f3 (contrib: add win32 credential-helper, 2012-07-27). Commit +8b2d219a3d (wincred: improve compatibility with windows versions, +2013-01-10) replaced the use of strncat() with wcsncat(), but retained +the buggy behavior. + +Fix this by using a "target_append()" helper which accounts for both the +length of the existing string within the buffer, as well as the trailing +NUL character. + +Reported-by: David Leadbeater +Helped-by: David Leadbeater +Helped-by: Jeff King +Signed-off-by: Taylor Blau +--- + .../wincred/git-credential-wincred.c | 22 +++++++++++++------ + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c +index 4cd56c42e2..ceff44207a 100644 +--- a/contrib/credential/wincred/git-credential-wincred.c ++++ b/contrib/credential/wincred/git-credential-wincred.c +@@ -37,6 +37,14 @@ static void *xmalloc(size_t size) + + static WCHAR *wusername, *password, *protocol, *host, *path, target[1024]; + ++static void target_append(const WCHAR *src) ++{ ++ size_t avail = ARRAY_SIZE(target) - wcslen(target) - 1; /* -1 for NUL */ ++ if (avail < wcslen(src)) ++ die("target buffer overflow"); ++ wcsncat(target, src, avail); ++} ++ + static void write_item(const char *what, LPCWSTR wbuf, int wlen) + { + char *buf; +@@ -294,17 +302,17 @@ int main(int argc, char *argv[]) + + /* prepare 'target', the unique key for the credential */ + wcscpy(target, L"git:"); +- wcsncat(target, protocol, ARRAY_SIZE(target)); +- wcsncat(target, L"://", ARRAY_SIZE(target)); ++ target_append(protocol); ++ target_append(L"://"); + if (wusername) { +- wcsncat(target, wusername, ARRAY_SIZE(target)); +- wcsncat(target, L"@", ARRAY_SIZE(target)); ++ target_append(wusername); ++ target_append(L"@"); + } + if (host) +- wcsncat(target, host, ARRAY_SIZE(target)); ++ target_append(host); + if (path) { +- wcsncat(target, L"/", ARRAY_SIZE(target)); +- wcsncat(target, path, ARRAY_SIZE(target)); ++ target_append(L"/"); ++ target_append(path); + } + + if (!strcmp(argv[1], "get")) +-- +2.33.0 + diff --git a/git.spec b/git.spec index b73efbabb69f158ffecd304aa0f9154835321726..46fad7c600a0d7449f16faa2cf3bc5118a5b5972 100644 --- a/git.spec +++ b/git.spec @@ -1,7 +1,7 @@ %global gitexecdir %{_libexecdir}/git-core Name: git Version: 2.27.0 -Release: 23 +Release: 24 Summary: A popular and widely used Version Control System License: GPLv2+ or LGPLv2.1 URL: https://git-scm.com/ @@ -80,6 +80,8 @@ Patch65: backport-CVE-2024-50349-credential_format-also-encode-host-port.patc Patch66: backport-CVE-2024-50349-credential-sanitize-the-user-prompt.patch Patch67: backport-CVE-2024-52006-credential-disallow-Carriage-Returns-in-the-protocol.patch Patch68: backport-CVE-2024-52005.patch +Patch69: backport-CVE-2025-48384-config-quote-values-containing-CR-character.patch +Patch70: backport-CVE-2025-48386-wincred-avoid-buffer-overflow-in-wcsncat.patch BuildRequires: gcc gettext BuildRequires: openssl-devel libcurl-devel expat-devel systemd asciidoc xmlto glib2-devel libsecret-devel pcre2-devel desktop-file-utils @@ -329,6 +331,12 @@ make %{?_smp_mflags} test %{_mandir}/man7/git*.7.* %changelog +* Wed Jul 9 2025 fuanan - 2.27.0-24 +- Type:CVE +- ID:CVE-2025-48384 CVE-2025-48386 +- SUG:NA +- DESC:Fix CVE-2025-48384 CVE-2025-48386 + * Thu Jan 23 2025 fuanan - 2.27.0-23 - Type:bugfix - ID:NA