Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
f76993c5a4
!190 [sync] PR-185: Fix CVE-2024-52005
From: @openeuler-sync-bot 
Reviewed-by: @dillon_chen 
Signed-off-by: @dillon_chen
2025-01-20 01:24:48 +00:00
fly_fzc
82c376fb9b Fix CVE-2024-52005
(cherry picked from commit f18ec62789fa2e3b713d4e488968cf0d1b4f1606)
2025-01-17 18:23:09 +08:00
openeuler-ci-bot
32f1379e74
!181 [sync] PR-178: Fix CVE-2024-50349 CVE-2024-52006
From: @openeuler-sync-bot 
Reviewed-by: @jiayi0118 
Signed-off-by: @jiayi0118
2025-01-16 11:07:28 +00:00
fly_fzc
11064c8bff Fix CVE-2024-50349 CVE-2024-52006
(cherry picked from commit 4e2c535ff3ce589984162f1a548799f5d92fe2d6)
2025-01-16 15:26:04 +08:00
openeuler-ci-bot
9cdb4bec4c
!154 Fix CVE-2024-32021 CVE-2024-32004 CVE-2024-32020 CVE-2024-32465
From: @fly_fzc 
Reviewed-by: @dillon_chen 
Signed-off-by: @dillon_chen
2024-05-17 03:25:22 +00:00
fly_fzc
ac09e19f00 Fix CVE-2024-32021 CVE-2024-32004 CVE-2024-32020 CVE-2024-32465 2024-05-17 10:27:24 +08:00
openeuler-ci-bot
7ffd11bad4
!140 Fix CVE-2024-32002
From: @kylin-qiaojijun 
Reviewed-by: @dillon_chen 
Signed-off-by: @dillon_chen
2024-05-16 14:50:51 +00:00
qiaojijun
ea9184ed90 Fix CVE-2024-32002
Signed-off-by: qiaojijun <qiaojijun@kylinos.cn>
2024-05-15 11:55:32 +08:00
openeuler-ci-bot
2084bc5915
!137 [sync] PR-136: Fix t9001-send-email.sh test error
From: @openeuler-sync-bot 
Reviewed-by: @openeuler-basic 
Signed-off-by: @openeuler-basic
2024-04-08 11:37:50 +00:00
fly_fzc
77c39c2253 Fix t9001-send-email.sh test error
(cherry picked from commit dc828813390e7735d4bf9a9f8dd9c44a72a739cb)
2024-04-08 19:12:29 +08:00
13 changed files with 1994 additions and 1 deletions

View File

@ -0,0 +1,164 @@
From 6393e6afd414ab9ebeffe069726440d397cae268 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Fri, 22 Mar 2024 11:19:22 +0100
Subject: [PATCH] backport CVE-2024-32002 submodules: submodule paths must not
contain symlinks
mainline inclusion
from v2.43.4
commit 97065761333fd62db1912d81b489db938d8c991d
category: bugfix
bugzilla: https://nvd.nist.gov/vuln/detail/CVE-2024-32002
CVE: CVE-2024-32002
When creating a submodule path, we must be careful not to follow
symbolic links. Otherwise we may follow a symbolic link pointing to
a gitdir (which are valid symbolic links!) e.g. while cloning.
On case-insensitive filesystems, however, we blindly replace a directory
that has been created as part of the `clone` operation with a symlink
when the path to the latter differs only in case from the former's path.
Let's simply avoid this situation by expecting not ever having to
overwrite any existing file/directory/symlink upon cloning. That way, we
won't even replace a directory that we just created.
This addresses CVE-2024-32002.
confliects:
t/t7406-submodule-update.sh
Reported-by: Filip Hejsek <filip.hejsek@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: qiaojijun <qiaojijun@kylinos.cn>
---
builtin/submodule--helper.c | 35 +++++++++++++++++++++++++++
t/t7406-submodule-update.sh | 48 +++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index cce4645..c46d420 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1663,12 +1663,35 @@ static char *clone_submodule_sm_gitdir(const char *name)
return sm_gitdir;
}
+static int dir_contains_only_dotgit(const char *path)
+{
+ DIR *dir = opendir(path);
+ struct dirent *e;
+ int ret = 1;
+
+ if (!dir)
+ return 0;
+
+ e = readdir_skip_dot_and_dotdot(dir);
+ if (!e)
+ ret = 0;
+ else if (strcmp(DEFAULT_GIT_DIR_ENVIRONMENT, e->d_name) ||
+ (e = readdir_skip_dot_and_dotdot(dir))) {
+ error("unexpected item '%s' in '%s'", e->d_name, path);
+ ret = 0;
+ }
+
+ closedir(dir);
+ return ret;
+}
+
static int clone_submodule(const struct module_clone_data *clone_data,
struct string_list *reference)
{
char *p;
char *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);
char *sm_alternate = NULL, *error_strategy = NULL;
+ struct stat st;
struct child_process cp = CHILD_PROCESS_INIT;
const char *clone_data_path = clone_data->path;
char *to_free = NULL;
@@ -1682,6 +1705,10 @@ static int clone_submodule(const struct module_clone_data *clone_data,
"git dir"), sm_gitdir);
if (!file_exists(sm_gitdir)) {
+ if (clone_data->require_init && !stat(clone_data_path, &st) &&
+ !is_empty_dir(clone_data_path))
+ die(_("directory not empty: '%s'"), clone_data_path);
+
if (safe_create_leading_directories_const(sm_gitdir) < 0)
die(_("could not create directory '%s'"), sm_gitdir);
@@ -1726,6 +1753,14 @@ static int clone_submodule(const struct module_clone_data *clone_data,
if(run_command(&cp))
die(_("clone of '%s' into submodule path '%s' failed"),
clone_data->url, clone_data_path);
+
+ if (clone_data->require_init && !stat(clone_data_path, &st) &&
+ !dir_contains_only_dotgit(clone_data_path)) {
+ char *dot_git = xstrfmt("%s/.git", clone_data_path);
+ unlink(dot_git);
+ free(dot_git);
+ die(_("directory not empty: '%s'"), clone_data_path);
+ }
} else {
char *path;
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 8491b8c..1f98b01 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -1179,6 +1179,54 @@ test_expect_success 'submodule update --recursive skip submodules with strategy=
test_cmp expect.err actual.err
'
+test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \
+ 'submodule paths must not follow symlinks' '
+
+ # This is only needed because we want to run this in a self-contained
+ # test without having to spin up an HTTP server; However, it would not
+ # be needed in a real-world scenario where the submodule is simply
+ # hosted on a public site.
+ test_config_global protocol.file.allow always &&
+
+ # Make sure that Git tries to use symlinks on Windows
+ test_config_global core.symlinks true &&
+
+ tell_tale_path="$PWD/tell.tale" &&
+ git init hook &&
+ (
+ cd hook &&
+ mkdir -p y/hooks &&
+ write_script y/hooks/post-checkout <<-EOF &&
+ echo HOOK-RUN >&2
+ echo hook-run >"$tell_tale_path"
+ EOF
+ git add y/hooks/post-checkout &&
+ test_tick &&
+ git commit -m post-checkout
+ ) &&
+
+ hook_repo_path="$(pwd)/hook" &&
+ git init captain &&
+ (
+ cd captain &&
+ git submodule add --name x/y "$hook_repo_path" A/modules/x &&
+ test_tick &&
+ git commit -m add-submodule &&
+
+ printf .git >dotgit.txt &&
+ git hash-object -w --stdin <dotgit.txt >dot-git.hash &&
+ printf "120000 %s 0\ta\n" "$(cat dot-git.hash)" >index.info &&
+ git update-index --index-info <index.info &&
+ test_tick &&
+ git commit -m add-symlink
+ ) &&
+
+ test_path_is_missing "$tell_tale_path" &&
+ test_must_fail git clone --recursive captain hooked 2>err &&
+ grep "directory not empty" err &&
+ test_path_is_missing "$tell_tale_path"
+'
+
add_submodule_commit_and_validate () {
HASH=$(git rev-parse HEAD) &&
git update-index --add --cacheinfo 160000,$HASH,sub &&
--
2.20.1

View File

@ -0,0 +1,153 @@
From f4aa8c8bb11dae6e769cd930565173808cbb69c8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Wed, 10 Apr 2024 14:39:37 +0200
Subject: [PATCH] fetch/clone: detect dubious ownership of local repositories
When cloning from somebody else's repositories, it is possible that,
say, the `upload-pack` command is overridden in the repository that is
about to be cloned, which would then be run in the user's context who
started the clone.
To remind the user that this is a potentially unsafe operation, let's
extend the ownership checks we have already established for regular
gitdir discovery to extend also to local repositories that are about to
be cloned.
This protection extends also to file:// URLs.
The fixes in this commit address CVE-2024-32004.
Note: This commit does not touch the `fetch`/`clone` code directly, but
instead the function used implicitly by both: `enter_repo()`. This
function is also used by `git receive-pack` (i.e. pushes), by `git
upload-archive`, by `git daemon` and by `git http-backend`. In setups
that want to serve repositories owned by different users than the
account running the service, this will require `safe.*` settings to be
configured accordingly.
Also note: there are tiny time windows where a time-of-check-time-of-use
("TOCTOU") race is possible. The real solution to those would be to work
with `fstat()` and `openat()`. However, the latter function is not
available on Windows (and would have to be emulated with rather
expensive low-level `NtCreateFile()` calls), and the changes would be
quite extensive, for my taste too extensive for the little gain given
that embargoed releases need to pay extra attention to avoid introducing
inadvertent bugs.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
setup.h | 12 ++++++++++++
path.c | 2 ++
setup.c | 21 +++++++++++++++++++++
t/t0411-clone-from-partial.sh | 6 +++---
4 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/setup.h b/setup.h
index fcf49706a..a46a3e4b6 100644
--- a/setup.h
+++ b/setup.h
@@ -41,6 +41,18 @@ const char *read_gitfile_gently(const char *path, int *return_error_code);
const char *resolve_gitdir_gently(const char *suspect, int *return_error_code);
#define resolve_gitdir(path) resolve_gitdir_gently((path), NULL)
+/*
+ * Check if a repository is safe and die if it is not, by verifying the
+ * ownership of the worktree (if any), the git directory, and the gitfile (if
+ * any).
+ *
+ * Exemptions for known-safe repositories can be added via `safe.directory`
+ * config settings; for non-bare repositories, their worktree needs to be
+ * added, for bare ones their git directory.
+ */
+void die_upon_dubious_ownership(const char *gitfile, const char *worktree,
+ const char *gitdir);
+
void setup_work_tree(void);
/*
diff --git a/path.c b/path.c
index 492e17ad1..d61f70e87 100644
--- a/path.c
+++ b/path.c
@@ -840,6 +840,7 @@ const char *enter_repo(const char *path, int strict)
if (!suffix[i])
return NULL;
gitfile = read_gitfile(used_path.buf);
+ die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
if (gitfile) {
strbuf_reset(&used_path);
strbuf_addstr(&used_path, gitfile);
@@ -850,6 +851,7 @@ const char *enter_repo(const char *path, int strict)
}
else {
const char *gitfile = read_gitfile(path);
+ die_upon_dubious_ownership(gitfile, NULL, path);
if (gitfile)
path = gitfile;
if (chdir(path))
diff --git a/setup.c b/setup.c
index cefd5f63c..9d401ae4c 100644
--- a/setup.c
+++ b/setup.c
@@ -1165,6 +1165,27 @@ static int ensure_valid_ownership(const char *gitfile,
return data.is_safe;
}
+void die_upon_dubious_ownership(const char *gitfile, const char *worktree,
+ const char *gitdir)
+{
+ struct strbuf report = STRBUF_INIT, quoted = STRBUF_INIT;
+ const char *path;
+
+ if (ensure_valid_ownership(gitfile, worktree, gitdir, &report))
+ return;
+
+ strbuf_complete(&report, '\n');
+ path = gitfile ? gitfile : gitdir;
+ sq_quote_buf_pretty(&quoted, path);
+
+ die(_("detected dubious ownership in repository at '%s'\n"
+ "%s"
+ "To add an exception for this directory, call:\n"
+ "\n"
+ "\tgit config --global --add safe.directory %s"),
+ path, report.buf, quoted.buf);
+}
+
static int allowed_bare_repo_cb(const char *key, const char *value,
const struct config_context *ctx UNUSED,
void *d)
diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
index fb72a0a9f..eb3360dbc 100755
--- a/t/t0411-clone-from-partial.sh
+++ b/t/t0411-clone-from-partial.sh
@@ -23,7 +23,7 @@ test_expect_success 'create evil repo' '
>evil/.git/shallow
'
-test_expect_failure 'local clone must not fetch from promisor remote and execute script' '
+test_expect_success 'local clone must not fetch from promisor remote and execute script' '
rm -f script-executed &&
test_must_fail git clone \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
@@ -32,7 +32,7 @@ test_expect_failure 'local clone must not fetch from promisor remote and execute
test_path_is_missing script-executed
'
-test_expect_failure 'clone from file://... must not fetch from promisor remote and execute script' '
+test_expect_success 'clone from file://... must not fetch from promisor remote and execute script' '
rm -f script-executed &&
test_must_fail git clone \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
@@ -41,7 +41,7 @@ test_expect_failure 'clone from file://... must not fetch from promisor remote a
test_path_is_missing script-executed
'
-test_expect_failure 'fetch from file://... must not fetch from promisor remote and execute script' '
+test_expect_success 'fetch from file://... must not fetch from promisor remote and execute script' '
rm -f script-executed &&
test_must_fail git fetch \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
--
2.33.0

View File

@ -0,0 +1,90 @@
From 5c5a4a1c05932378d259b1fdd9526cab971656a2 Mon Sep 17 00:00:00 2001
From: Filip Hejsek <filip.hejsek@gmail.com>
Date: Sun, 28 Jan 2024 04:29:33 +0100
Subject: [PATCH] t0411: add tests for cloning from partial repo
Cloning from a partial repository must not fetch missing objects into
the partial repository, because that can lead to arbitrary code
execution.
Add a couple of test cases, pretending to the `upload-pack` command (and
to that command only) that it is working on a repository owned by
someone else.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Filip Hejsek <filip.hejsek@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
t/t0411-clone-from-partial.sh | 60 +++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100755 t/t0411-clone-from-partial.sh
diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
new file mode 100755
index 000000000..fb72a0a9f
--- /dev/null
+++ b/t/t0411-clone-from-partial.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+test_description='check that local clone does not fetch from promisor remotes'
+
+. ./test-lib.sh
+
+test_expect_success 'create evil repo' '
+ git init tmp &&
+ test_commit -C tmp a &&
+ git -C tmp config uploadpack.allowfilter 1 &&
+ git clone --filter=blob:none --no-local --no-checkout tmp evil &&
+ rm -rf tmp &&
+
+ git -C evil config remote.origin.uploadpack \"\$TRASH_DIRECTORY/fake-upload-pack\" &&
+ write_script fake-upload-pack <<-\EOF &&
+ echo >&2 "fake-upload-pack running"
+ >"$TRASH_DIRECTORY/script-executed"
+ exit 1
+ EOF
+ export TRASH_DIRECTORY &&
+
+ # empty shallow file disables local clone optimization
+ >evil/.git/shallow
+'
+
+test_expect_failure 'local clone must not fetch from promisor remote and execute script' '
+ rm -f script-executed &&
+ test_must_fail git clone \
+ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+ evil clone1 2>err &&
+ ! grep "fake-upload-pack running" err &&
+ test_path_is_missing script-executed
+'
+
+test_expect_failure 'clone from file://... must not fetch from promisor remote and execute script' '
+ rm -f script-executed &&
+ test_must_fail git clone \
+ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+ "file://$(pwd)/evil" clone2 2>err &&
+ ! grep "fake-upload-pack running" err &&
+ test_path_is_missing script-executed
+'
+
+test_expect_failure 'fetch from file://... must not fetch from promisor remote and execute script' '
+ rm -f script-executed &&
+ test_must_fail git fetch \
+ --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
+ "file://$(pwd)/evil" 2>err &&
+ ! grep "fake-upload-pack running" err &&
+ test_path_is_missing script-executed
+'
+
+test_expect_success 'pack-objects should fetch from promisor remote and execute script' '
+ rm -f script-executed &&
+ echo "HEAD" | test_must_fail git -C evil pack-objects --revs --stdout >/dev/null 2>err &&
+ grep "fake-upload-pack running" err &&
+ test_path_is_file script-executed
+'
+
+test_done
--
2.33.0

View File

@ -0,0 +1,109 @@
From 1204e1a824c34071019fe106348eaa6d88f9528d Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@pks.im>
Date: Mon, 15 Apr 2024 13:30:41 +0200
Subject: [PATCH] builtin/clone: refuse local clones of unsafe repositories
When performing a local clone of a repository we end up either copying
or hardlinking the source repository into the target repository. This is
significantly more performant than if we were to use git-upload-pack(1)
and git-fetch-pack(1) to create the new repository and preserves both
disk space and compute time.
Unfortunately though, performing such a local clone of a repository that
is not owned by the current user is inherently unsafe:
- It is possible that source files get swapped out underneath us while
we are copying or hardlinking them. While we do perform some checks
here to assert that we hardlinked the expected file, they cannot
reliably thwart time-of-check-time-of-use (TOCTOU) style races. It
is thus possible for an adversary to make us copy or hardlink
unexpected files into the target directory.
Ideally, we would address this by starting to use openat(3P),
fstatat(3P) and friends. Due to platform compatibility with Windows
we cannot easily do that though. Furthermore, the scope of these
fixes would likely be quite broad and thus not fit for an embargoed
security release.
- Even if we handled TOCTOU-style races perfectly, hardlinking files
owned by a different user into the target repository is not a good
idea in general. It is possible for an adversary to rewrite those
files to contain whatever data they want even after the clone has
completed.
Address these issues by completely refusing local clones of a repository
that is not owned by the current user. This reuses our existing infra we
have in place via `ensure_valid_ownership()` and thus allows a user to
override the safety guard by adding the source repository path to the
"safe.directory" configuration.
This addresses CVE-2024-32020.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
builtin/clone.c | 14 ++++++++++++++
t/t0033-safe-directory.sh | 24 ++++++++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/builtin/clone.c b/builtin/clone.c
index 4b80fa087..9ec500d42 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -321,6 +321,20 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
struct dir_iterator *iter;
int iter_status;
+ /*
+ * Refuse copying directories by default which aren't owned by us. The
+ * code that performs either the copying or hardlinking is not prepared
+ * to handle various edge cases where an adversary may for example
+ * racily swap out files for symlinks. This can cause us to
+ * inadvertently use the wrong source file.
+ *
+ * Furthermore, even if we were prepared to handle such races safely,
+ * creating hardlinks across user boundaries is an inherently unsafe
+ * operation as the hardlinked files can be rewritten at will by the
+ * potentially-untrusted user. We thus refuse to do so by default.
+ */
+ die_upon_dubious_ownership(NULL, NULL, src_repo);
+
mkdir_if_missing(dest->buf, 0777);
iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC);
diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
index dc3496897..11c3e8f28 100755
--- a/t/t0033-safe-directory.sh
+++ b/t/t0033-safe-directory.sh
@@ -80,4 +80,28 @@ test_expect_success 'safe.directory in included file' '
git status
'
+test_expect_success 'local clone of unowned repo refused in unsafe directory' '
+ test_when_finished "rm -rf source" &&
+ git init source &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit -C source initial
+ ) &&
+ test_must_fail git clone --local source target &&
+ test_path_is_missing target
+'
+
+test_expect_success 'local clone of unowned repo accepted in safe directory' '
+ test_when_finished "rm -rf source" &&
+ git init source &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit -C source initial
+ ) &&
+ test_must_fail git clone --local source target &&
+ git config --global --add safe.directory "$(pwd)/source/.git" &&
+ git clone --local source target &&
+ test_path_is_dir target
+'
+
test_done
--
2.33.0

View File

@ -0,0 +1,60 @@
From d1bb66a546b4bb46005d17ba711caaad26f26c1e Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@pks.im>
Date: Mon, 15 Apr 2024 13:30:31 +0200
Subject: [PATCH] builtin/clone: abort when hardlinked source and target file
differ
When performing local clones with hardlinks we refuse to copy source
files which are symlinks as a mitigation for CVE-2022-39253. This check
can be raced by an adversary though by changing the file to a symlink
after we have checked it.
Fix the issue by checking whether the hardlinked destination file
matches the source file and abort in case it doesn't.
This addresses CVE-2024-32021.
Reported-by: Apple Product Security <product-security@apple.com>
Suggested-by: Linus Torvalds <torvalds@linuxfoundation.org>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
builtin/clone.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index 073e6323d..4b80fa087 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -357,8 +357,27 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (unlink(dest->buf) && errno != ENOENT)
die_errno(_("failed to unlink '%s'"), dest->buf);
if (!option_no_hardlinks) {
- if (!link(src->buf, dest->buf))
+ if (!link(src->buf, dest->buf)) {
+ struct stat st;
+
+ /*
+ * Sanity-check whether the created hardlink
+ * actually links to the expected file now. This
+ * catches time-of-check-time-of-use bugs in
+ * case the source file was meanwhile swapped.
+ */
+ if (lstat(dest->buf, &st))
+ die(_("hardlink cannot be checked at '%s'"), dest->buf);
+ if (st.st_mode != iter->st.st_mode ||
+ st.st_ino != iter->st.st_ino ||
+ st.st_dev != iter->st.st_dev ||
+ st.st_size != iter->st.st_size ||
+ st.st_uid != iter->st.st_uid ||
+ st.st_gid != iter->st.st_gid)
+ die(_("hardlink different from source at '%s'"), dest->buf);
+
continue;
+ }
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
option_no_hardlinks = 1;
--
2.33.0

View File

@ -0,0 +1,84 @@
From 150e6b0aedf57d224c3c49038c306477fa159886 Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@pks.im>
Date: Mon, 15 Apr 2024 13:30:26 +0200
Subject: [PATCH] builtin/clone: stop resolving symlinks when copying files
When a user performs a local clone without `--no-local`, then we end up
copying the source repository into the target repository directly. To
optimize this even further, we try to hardlink files into place instead
of copying data over, which helps both disk usage and speed.
There is an important edge case in this context though, namely when we
try to hardlink symlinks from the source repository into the target
repository. Depending on both platform and filesystem the resulting
behaviour here can be different:
- On macOS and NetBSD, calling link(3P) with a symlink target creates
a hardlink to the file pointed to by the symlink.
- On Linux, calling link(3P) instead creates a hardlink to the symlink
itself.
To unify this behaviour, 36596fd2df (clone: better handle symlinked
files at .git/objects/, 2019-07-10) introduced logic to resolve symlinks
before we try to link(3P) files. Consequently, the new behaviour was to
always create a hard link to the target of the symlink on all platforms.
Eventually though, we figured out that following symlinks like this can
cause havoc when performing a local clone of a malicious repository,
which resulted in CVE-2022-39253. This issue was fixed via 6f054f9fb3
(builtin/clone.c: disallow `--local` clones with symlinks, 2022-07-28),
by refusing symlinks in the source repository.
But even though we now shouldn't ever link symlinks anymore, the code
that resolves symlinks still exists. In the best case the code does not
end up doing anything because there are no symlinks anymore. In the
worst case though this can be abused by an adversary that rewrites the
source file after it has been checked not to be a symlink such that it
actually is a symlink when we call link(3P). Thus, it is still possible
to recreate CVE-2022-39253 due to this time-of-check-time-of-use bug.
Remove the call to `realpath()`. This doesn't yet address the actual
vulnerability, which will be handled in a subsequent commit.
Reported-by: Apple Product Security <product-security@apple.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
builtin/clone.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/builtin/clone.c b/builtin/clone.c
index 3c2ae31a5..073e6323d 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -320,7 +320,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
int src_len, dest_len;
struct dir_iterator *iter;
int iter_status;
- struct strbuf realpath = STRBUF_INIT;
mkdir_if_missing(dest->buf, 0777);
@@ -358,8 +357,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
if (unlink(dest->buf) && errno != ENOENT)
die_errno(_("failed to unlink '%s'"), dest->buf);
if (!option_no_hardlinks) {
- strbuf_realpath(&realpath, src->buf, 1);
- if (!link(realpath.buf, dest->buf))
+ if (!link(src->buf, dest->buf))
continue;
if (option_local > 0)
die_errno(_("failed to create link '%s'"), dest->buf);
@@ -373,8 +371,6 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
strbuf_setlen(src, src_len);
die(_("failed to iterate over '%s'"), src->buf);
}
-
- strbuf_release(&realpath);
}
static void clone_local(const char *src_repo, const char *dest_repo)
--
2.33.0

View File

@ -0,0 +1,201 @@
From 7b70e9efb18c2cc3f219af399bd384c5801ba1d7 Mon Sep 17 00:00:00 2001
From: Jeff King <peff@peff.net>
Date: Tue, 16 Apr 2024 04:35:33 -0400
Subject: [PATCH] upload-pack: disable lazy-fetching by default
The upload-pack command tries to avoid trusting the repository in which
it's run (e.g., by not running any hooks and not using any config that
contains arbitrary commands). But if the server side of a fetch or a
clone is a partial clone, then either upload-pack or its child
pack-objects may run a lazy "git fetch" under the hood. And it is very
easy to convince fetch to run arbitrary commands.
The "server" side can be a local repository owned by someone else, who
would be able to configure commands that are run during a clone with the
current user's permissions. This issue has been designated
CVE-2024-32004.
The fix in this commit's parent helps in this scenario, as well as in
related scenarios using SSH to clone, where the untrusted .git directory
is owned by a different user id. But if you received one as a zip file,
on a USB stick, etc, it may be owned by your user but still untrusted.
This has been designated CVE-2024-32465.
To mitigate the issue more completely, let's disable lazy fetching
entirely during `upload-pack`. While fetching from a partial repository
should be relatively rare, it is certainly not an unreasonable workflow.
And thus we need to provide an escape hatch.
This commit works by respecting a GIT_NO_LAZY_FETCH environment variable
(to skip the lazy-fetch), and setting it in upload-pack, but only when
the user has not already done so (which gives us the escape hatch).
The name of the variable is specifically chosen to match what has
already been added in 'master' via e6d5479e7a (git: extend
--no-lazy-fetch to work across subprocesses, 2024-02-27). Since we're
building this fix as a backport for older versions, we could cherry-pick
that patch and its earlier steps. However, we don't really need the
niceties (like a "--no-lazy-fetch" option) that it offers. By using the
same name, everything should just work when the two are eventually
merged, but here are a few notes:
- the blocking of the fetch in e6d5479e7a is incomplete! It sets
fetch_if_missing to 0 when we setup the repository variable, but
that isn't enough. pack-objects in particular will call
prefetch_to_pack() even if that variable is 0. This patch by
contrast checks the environment variable at the lowest level before
we call the lazy fetch, where we can be sure to catch all code
paths.
Possibly the setting of fetch_if_missing from e6d5479e7a can be
reverted, but it may be useful to have. For example, some code may
want to use that flag to change behavior before it gets to the point
of trying to start the fetch. At any rate, that's all outside the
scope of this patch.
- there's documentation for GIT_NO_LAZY_FETCH in e6d5479e7a. We can
live without that here, because for the most part the user shouldn't
need to set it themselves. The exception is if they do want to
override upload-pack's default, and that requires a separate
documentation section (which is added here)
- it would be nice to use the NO_LAZY_FETCH_ENVIRONMENT macro added by
e6d5479e7a, but those definitions have moved from cache.h to
environment.h between 2.39.3 and master. I just used the raw string
literals, and we can replace them with the macro once this topic is
merged to master.
At least with respect to CVE-2024-32004, this does render this commit's
parent commit somewhat redundant. However, it is worth retaining that
commit as defense in depth, and because it may help other issues (e.g.,
symlink/hardlink TOCTOU races, where zip files are not really an
interesting attack vector).
The tests in t0411 still pass, but now we have _two_ mechanisms ensuring
that the evil command is not run. Let's beef up the existing ones to
check that they failed for the expected reason, that we refused to run
upload-pack at all with an alternate user id. And add two new ones for
the same-user case that both the restriction and its escape hatch.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
Documentation/git-upload-pack.txt | 16 ++++++++++++++++
builtin/upload-pack.c | 2 ++
promisor-remote.c | 10 ++++++++++
t/t0411-clone-from-partial.sh | 18 ++++++++++++++++++
4 files changed, 46 insertions(+)
diff --git a/Documentation/git-upload-pack.txt b/Documentation/git-upload-pack.txt
index b656b4756..fc4c62d7b 100644
--- a/Documentation/git-upload-pack.txt
+++ b/Documentation/git-upload-pack.txt
@@ -55,6 +55,22 @@ ENVIRONMENT
admins may need to configure some transports to allow this
variable to be passed. See the discussion in linkgit:git[1].
+`GIT_NO_LAZY_FETCH`::
+ When cloning or fetching from a partial repository (i.e., one
+ itself cloned with `--filter`), the server-side `upload-pack`
+ may need to fetch extra objects from its upstream in order to
+ complete the request. By default, `upload-pack` will refuse to
+ perform such a lazy fetch, because `git fetch` may run arbitrary
+ commands specified in configuration and hooks of the source
+ repository (and `upload-pack` tries to be safe to run even in
+ untrusted `.git` directories).
++
+This is implemented by having `upload-pack` internally set the
+`GIT_NO_LAZY_FETCH` variable to `1`. If you want to override it
+(because you are fetching from a partial clone, and you are sure
+you trust it), you can explicitly set `GIT_NO_LAZY_FETCH` to
+`0`.
+
SEE ALSO
--------
linkgit:gitnamespaces[7]
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
index 25b69da2b..f446ff04f 100644
--- a/builtin/upload-pack.c
+++ b/builtin/upload-pack.c
@@ -35,6 +35,8 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
packet_trace_identity("upload-pack");
disable_replace_refs();
+ /* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */
+ xsetenv("GIT_NO_LAZY_FETCH", "1", 0);
argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
diff --git a/promisor-remote.c b/promisor-remote.c
index faa761294..550a38f75 100644
--- a/promisor-remote.c
+++ b/promisor-remote.c
@@ -20,6 +20,16 @@ static int fetch_objects(struct repository *repo,
int i;
FILE *child_in;
+ /* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */
+ if (git_env_bool("GIT_NO_LAZY_FETCH", 0)) {
+ static int warning_shown;
+ if (!warning_shown) {
+ warning_shown = 1;
+ warning(_("lazy fetching disabled; some objects may not be available"));
+ }
+ return -1;
+ }
+
child.git_cmd = 1;
child.in = -1;
if (repo != the_repository)
diff --git a/t/t0411-clone-from-partial.sh b/t/t0411-clone-from-partial.sh
index eb3360dbc..b3d6ddc4b 100755
--- a/t/t0411-clone-from-partial.sh
+++ b/t/t0411-clone-from-partial.sh
@@ -28,6 +28,7 @@ test_expect_success 'local clone must not fetch from promisor remote and execute
test_must_fail git clone \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
evil clone1 2>err &&
+ grep "detected dubious ownership" err &&
! grep "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
@@ -37,6 +38,7 @@ test_expect_success 'clone from file://... must not fetch from promisor remote a
test_must_fail git clone \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
"file://$(pwd)/evil" clone2 2>err &&
+ grep "detected dubious ownership" err &&
! grep "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
@@ -46,6 +48,7 @@ test_expect_success 'fetch from file://... must not fetch from promisor remote a
test_must_fail git fetch \
--upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \
"file://$(pwd)/evil" 2>err &&
+ grep "detected dubious ownership" err &&
! grep "fake-upload-pack running" err &&
test_path_is_missing script-executed
'
@@ -57,4 +60,19 @@ test_expect_success 'pack-objects should fetch from promisor remote and execute
test_path_is_file script-executed
'
+test_expect_success 'clone from promisor remote does not lazy-fetch by default' '
+ rm -f script-executed &&
+ test_must_fail git clone evil no-lazy 2>err &&
+ grep "lazy fetching disabled" err &&
+ test_path_is_missing script-executed
+'
+
+test_expect_success 'promisor lazy-fetching can be re-enabled' '
+ rm -f script-executed &&
+ test_must_fail env GIT_NO_LAZY_FETCH=0 \
+ git clone evil lazy-ok 2>err &&
+ grep "fake-upload-pack running" err &&
+ test_path_is_file script-executed
+'
+
test_done
--
2.33.0

View File

@ -0,0 +1,316 @@
From 7725b8100ffbbff2750ee4d61a0fcc1f53a086e8 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Wed, 30 Oct 2024 13:26:10 +0100
Subject: [PATCH] credential: sanitize the user prompt
When asking the user interactively for credentials, we want to avoid
misleading them e.g. via control sequences that pretend that the URL
targets a trusted host when it does not.
While Git learned, over the course of the preceding commits, to disallow
URLs containing URL-encoded control characters by default, credential
helpers are still allowed to specify values very freely (apart from Line
Feed and NUL characters, anything is allowed), and this would allow,
say, a username containing control characters to be specified that would
then be displayed in the interactive terminal prompt asking the user for
the password, potentially sending those control characters directly to
the terminal. This is undesirable because control characters can be used
to mislead users to divulge secret information to untrusted sites.
To prevent such an attack vector, let's add a `git_prompt()` that forces
the displayed text to be sanitized, i.e. displaying question marks
instead of control characters.
Note: While this commit's diff changes a lot of `user@host` strings to
`user%40host`, which may look suspicious on the surface, there is a good
reason for that: this string specifies a user name, not a
<username>@<hostname> combination! In the context of t5541, the actual
combination looks like this: `user%40@127.0.0.1:5541`. Therefore, these
string replacements document a net improvement introduced by this
commit, as `user@host@127.0.0.1` could have left readers wondering where
the user name ends and where the host name begins.
Hinted-at-by: Jeff King <peff@peff.net>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
Documentation/config/credential.txt | 6 ++++++
credential.c | 7 ++++++-
credential.h | 4 +++-
t/t0300-credentials.sh | 20 ++++++++++++++++++++
t/t5541-http-push-smart.sh | 6 +++---
t/t5550-http-fetch-dumb.sh | 14 +++++++-------
t/t5551-http-fetch-smart.sh | 16 ++++++++--------
7 files changed, 53 insertions(+), 20 deletions(-)
diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt
index 512f3187..fd8113d6 100644
--- a/Documentation/config/credential.txt
+++ b/Documentation/config/credential.txt
@@ -14,6 +14,12 @@ credential.useHttpPath::
or https URL to be important. Defaults to false. See
linkgit:gitcredentials[7] for more information.
+credential.sanitizePrompt::
+ By default, user names and hosts that are shown as part of the
+ password prompt are not allowed to contain control characters (they
+ will be URL-encoded by default). Configure this setting to `false` to
+ override that behavior.
+
credential.username::
If no username is set for a network authentication, use this username
by default. See credential.<context>.* below, and
diff --git a/credential.c b/credential.c
index 572f1785..1392a54d 100644
--- a/credential.c
+++ b/credential.c
@@ -67,6 +67,8 @@ static int credential_config_callback(const char *var, const char *value,
}
else if (!strcmp(key, "usehttppath"))
c->use_http_path = git_config_bool(var, value);
+ else if (!strcmp(key, "sanitizeprompt"))
+ c->sanitize_prompt = git_config_bool(var, value);
return 0;
}
@@ -179,7 +181,10 @@ static char *credential_ask_one(const char *what, struct credential *c,
struct strbuf prompt = STRBUF_INIT;
char *r;
- credential_describe(c, &desc);
+ if (c->sanitize_prompt)
+ credential_format(c, &desc);
+ else
+ credential_describe(c, &desc);
if (desc.len)
strbuf_addf(&prompt, "%s for '%s': ", what, desc.buf);
else
diff --git a/credential.h b/credential.h
index 935b28a7..0364d436 100644
--- a/credential.h
+++ b/credential.h
@@ -119,7 +119,8 @@ struct credential {
configured:1,
quit:1,
use_http_path:1,
- username_from_proto:1;
+ username_from_proto:1,
+ sanitize_prompt:1;
char *username;
char *password;
@@ -132,6 +133,7 @@ struct credential {
.helpers = STRING_LIST_INIT_DUP, \
.password_expiry_utc = TIME_MAX, \
.wwwauth_headers = STRVEC_INIT, \
+ .sanitize_prompt = 1, \
}
/* Initialize a credential structure, setting all fields to empty. */
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index cb91be14..b62c70c1 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -45,6 +45,10 @@ test_expect_success 'setup helper scripts' '
test -z "$pexpiry" || echo password_expiry_utc=$pexpiry
EOF
+ write_script git-credential-cntrl-in-username <<-\EOF &&
+ printf "username=\\007latrix Lestrange\\n"
+ EOF
+
PATH="$PWD:$PATH"
'
@@ -825,4 +829,20 @@ test_expect_success 'credential config with partial URLs' '
test_grep "skipping credential lookup for key" stderr
'
+BEL="$(printf '\007')"
+
+test_expect_success 'interactive prompt is sanitized' '
+ check fill cntrl-in-username <<-EOF
+ protocol=https
+ host=example.org
+ --
+ protocol=https
+ host=example.org
+ username=${BEL}latrix Lestrange
+ password=askpass-password
+ --
+ askpass: Password for ${SQ}https://%07latrix%20Lestrange@example.org${SQ}:
+ EOF
+'
+
test_done
diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index d0211cd8..2cd2e1a0 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -351,7 +351,7 @@ test_expect_success 'push over smart http with auth' '
git push "$HTTPD_URL"/auth/smart/test_repo.git &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
log -1 --format=%s >actual &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
test_cmp expect actual
'
@@ -363,7 +363,7 @@ test_expect_success 'push to auth-only-for-push repo' '
git push "$HTTPD_URL"/auth-push/smart/test_repo.git &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
log -1 --format=%s >actual &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
test_cmp expect actual
'
@@ -393,7 +393,7 @@ test_expect_success 'push into half-auth-complete requires password' '
git push "$HTTPD_URL/half-auth-complete/smart/half-auth.git" &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/half-auth.git" \
log -1 --format=%s >actual &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
test_cmp expect actual
'
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index 8f182a3c..5d0e3946 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -90,13 +90,13 @@ test_expect_success 'http auth can use user/pass in URL' '
test_expect_success 'http auth can use just user in URL' '
set_askpass wrong pass@host &&
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass &&
- expect_askpass pass user@host
+ expect_askpass pass user%40host
'
test_expect_success 'http auth can request both user and pass' '
set_askpass user@host pass@host &&
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both &&
- expect_askpass both user@host
+ expect_askpass both user%40host
'
test_expect_success 'http auth respects credential helper config' '
@@ -114,14 +114,14 @@ test_expect_success 'http auth can get username from config' '
test_config_global "credential.$HTTPD_URL.username" user@host &&
set_askpass wrong pass@host &&
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user &&
- expect_askpass pass user@host
+ expect_askpass pass user%40host
'
test_expect_success 'configured username does not override URL' '
test_config_global "credential.$HTTPD_URL.username" wrong &&
set_askpass wrong pass@host &&
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 &&
- expect_askpass pass user@host
+ expect_askpass pass user%40host
'
test_expect_success 'set up repo with http submodules' '
@@ -142,7 +142,7 @@ test_expect_success 'cmdline credential config passes to submodule via clone' '
set_askpass wrong pass@host &&
git -c "credential.$HTTPD_URL.username=user@host" \
clone --recursive super super-clone &&
- expect_askpass pass user@host
+ expect_askpass pass user%40host
'
test_expect_success 'cmdline credential config passes submodule via fetch' '
@@ -153,7 +153,7 @@ test_expect_success 'cmdline credential config passes submodule via fetch' '
git -C super-clone \
-c "credential.$HTTPD_URL.username=user@host" \
fetch --recurse-submodules &&
- expect_askpass pass user@host
+ expect_askpass pass user%40host
'
test_expect_success 'cmdline credential config passes submodule update' '
@@ -170,7 +170,7 @@ test_expect_success 'cmdline credential config passes submodule update' '
git -C super-clone \
-c "credential.$HTTPD_URL.username=user@host" \
submodule update &&
- expect_askpass pass user@host
+ expect_askpass pass user%40host
'
test_expect_success 'fetch changes via http' '
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index 0908534f..8a27768d 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -181,7 +181,7 @@ test_expect_success 'clone from password-protected repository' '
echo two >expect &&
set_askpass user@host pass@host &&
git clone --bare "$HTTPD_URL/auth/smart/repo.git" smart-auth &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
git --git-dir=smart-auth log -1 --format=%s >actual &&
test_cmp expect actual
'
@@ -199,7 +199,7 @@ test_expect_success 'clone from auth-only-for-objects repository' '
echo two >expect &&
set_askpass user@host pass@host &&
git clone --bare "$HTTPD_URL/auth-fetch/smart/repo.git" half-auth &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
git --git-dir=half-auth log -1 --format=%s >actual &&
test_cmp expect actual
'
@@ -224,14 +224,14 @@ test_expect_success 'redirects send auth to new location' '
set_askpass user@host pass@host &&
git -c credential.useHttpPath=true \
clone $HTTPD_URL/smart-redir-auth/repo.git repo-redir-auth &&
- expect_askpass both user@host auth/smart/repo.git
+ expect_askpass both user%40host auth/smart/repo.git
'
test_expect_success 'GIT_TRACE_CURL redacts auth details' '
rm -rf redact-auth trace &&
set_askpass user@host pass@host &&
GIT_TRACE_CURL="$(pwd)/trace" git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
# Ensure that there is no "Basic" followed by a base64 string, but that
# the auth details are redacted
@@ -243,7 +243,7 @@ test_expect_success 'GIT_CURL_VERBOSE redacts auth details' '
rm -rf redact-auth trace &&
set_askpass user@host pass@host &&
GIT_CURL_VERBOSE=1 git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth 2>trace &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
# Ensure that there is no "Basic" followed by a base64 string, but that
# the auth details are redacted
@@ -256,7 +256,7 @@ test_expect_success 'GIT_TRACE_CURL does not redact auth details if GIT_TRACE_RE
set_askpass user@host pass@host &&
GIT_TRACE_REDACT=0 GIT_TRACE_CURL="$(pwd)/trace" \
git clone --bare "$HTTPD_URL/auth/smart/repo.git" redact-auth &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
grep -i "Authorization: Basic [0-9a-zA-Z+/]" trace
'
@@ -568,7 +568,7 @@ test_expect_success 'http auth remembers successful credentials' '
# the first request prompts the user...
set_askpass user@host pass@host &&
git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
- expect_askpass both user@host &&
+ expect_askpass both user%40host &&
# ...and the second one uses the stored value rather than
# prompting the user.
@@ -599,7 +599,7 @@ test_expect_success 'http auth forgets bogus credentials' '
# us to prompt the user again.
set_askpass user@host pass@host &&
git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null &&
- expect_askpass both user@host
+ expect_askpass both user%40host
'
test_expect_success 'client falls back from v2 to v0 to match server' '
--
2.23.0

View File

@ -0,0 +1,98 @@
From c903985bf7e772e2d08275c1a95c8a55ab011577 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Thu, 7 Nov 2024 08:57:52 +0100
Subject: [PATCH] credential_format(): also encode <host>[:<port>]
An upcoming change wants to sanitize the credential password prompt
where a URL is displayed that may potentially come from a `.gitmodules`
file. To this end, the `credential_format()` function is employed.
To sanitize the host name (and optional port) part of the URL, we need a
new mode of the `strbuf_add_percentencode()` function because the
current mode is both too strict and too lenient: too strict because it
encodes `:`, `[` and `]` (which should be left unencoded in
`<host>:<port>` and in IPv6 addresses), and too lenient because it does
not encode invalid host name characters `/`, `_` and `~`.
So let's introduce and use a new mode specifically to encode the host
name and optional port part of a URI, leaving alpha-numerical
characters, periods, colons and brackets alone and encoding all others.
This only leads to a change of behavior for URLs that contain invalid
host names.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
credential.c | 3 ++-
strbuf.c | 4 +++-
strbuf.h | 1 +
t/t0300-credentials.sh | 13 +++++++++++++
4 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/credential.c b/credential.c
index f3201134..572f1785 100644
--- a/credential.c
+++ b/credential.c
@@ -164,7 +164,8 @@ static void credential_format(struct credential *c, struct strbuf *out)
strbuf_addch(out, '@');
}
if (c->host)
- strbuf_addstr(out, c->host);
+ strbuf_add_percentencode(out, c->host,
+ STRBUF_ENCODE_HOST_AND_PORT);
if (c->path) {
strbuf_addch(out, '/');
strbuf_add_percentencode(out, c->path, 0);
diff --git a/strbuf.c b/strbuf.c
index c383f41a..756b96c5 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -492,7 +492,9 @@ void strbuf_add_percentencode(struct strbuf *dst, const char *src, int flags)
unsigned char ch = src[i];
if (ch <= 0x1F || ch >= 0x7F ||
(ch == '/' && (flags & STRBUF_ENCODE_SLASH)) ||
- strchr(URL_UNSAFE_CHARS, ch))
+ ((flags & STRBUF_ENCODE_HOST_AND_PORT) ?
+ !isalnum(ch) && !strchr("-.:[]", ch) :
+ !!strchr(URL_UNSAFE_CHARS, ch)))
strbuf_addf(dst, "%%%02X", (unsigned char)ch);
else
strbuf_addch(dst, ch);
diff --git a/strbuf.h b/strbuf.h
index f6dbb968..f9f8bb03 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -380,6 +380,7 @@ size_t strbuf_expand_dict_cb(struct strbuf *sb,
void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);
#define STRBUF_ENCODE_SLASH 1
+#define STRBUF_ENCODE_HOST_AND_PORT 2
/**
* Append the contents of a string to a strbuf, percent-encoding any characters
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index c66d91e8..cb91be14 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -514,6 +514,19 @@ test_expect_success 'match percent-encoded values in username' '
EOF
'
+test_expect_success 'match percent-encoded values in hostname' '
+ test_config "credential.https://a%20b%20c/.helper" "$HELPER" &&
+ check fill <<-\EOF
+ url=https://a b c/
+ --
+ protocol=https
+ host=a b c
+ username=foo
+ password=bar
+ --
+ EOF
+'
+
test_expect_success 'fetch with multiple path components' '
test_unconfig credential.helper &&
test_config credential.https://example.com/foo/repo.git.helper "verbatim foo bar" &&
--
2.23.0

View File

@ -0,0 +1,388 @@
From 5b257412e25ad29410c389300324886aa59e1f83 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Wed, 6 Nov 2024 20:34:50 +0100
Subject: [PATCH 1/3] sideband: mask control characters
The output of `git clone` is a vital component for understanding what
has happened when things go wrong. However, these logs are partially
under the control of the remote server (via the "sideband", which
typically contains what the remote `git pack-objects` process sends to
`stderr`), and is currently not sanitized by Git.
This makes Git susceptible to ANSI escape sequence injection (see
CWE-150, https://cwe.mitre.org/data/definitions/150.html), which allows
attackers to corrupt terminal state, to hide information, and even to
insert characters into the input buffer (i.e. as if the user had typed
those characters).
To plug this vulnerability, disallow any control character in the
sideband, replacing them instead with the common `^<letter/symbol>`
(e.g. `^[` for `\x1b`, `^A` for `\x01`).
There is likely a need for more fine-grained controls instead of using a
"heavy hammer" like this, which will be introduced subsequently.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
sideband.c | 17 +++++++++++++++--
t/t5409-colorize-remote-messages.sh | 12 ++++++++++++
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/sideband.c b/sideband.c
index 85bddfdcd4f57a..9384cb02d56a04 100644
--- a/sideband.c
+++ b/sideband.c
@@ -61,6 +61,19 @@ void list_config_color_sideband_slots(struct string_list *list, const char *pref
list_config_item(list, prefix, keywords[i].keyword);
}
+static void strbuf_add_sanitized(struct strbuf *dest, const char *src, int n)
+{
+ strbuf_grow(dest, n);
+ for (; n && *src; src++, n--) {
+ if (!iscntrl(*src) || *src == '\t' || *src == '\n')
+ strbuf_addch(dest, *src);
+ else {
+ strbuf_addch(dest, '^');
+ strbuf_addch(dest, 0x40 + *src);
+ }
+ }
+}
+
/*
* Optionally highlight one keyword in remote output if it appears at the start
* of the line. This should be called for a single line only, which is
@@ -73,7 +86,7 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
int i;
if (!want_color_stderr(use_sideband_colors())) {
- strbuf_add(dest, src, n);
+ strbuf_add_sanitized(dest, src, n);
return;
}
@@ -106,7 +119,7 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
}
}
- strbuf_add(dest, src, n);
+ strbuf_add_sanitized(dest, src, n);
}
diff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh
index fa5de4500a4f50..6a6e0d15b21050 100755
--- a/t/t5409-colorize-remote-messages.sh
+++ b/t/t5409-colorize-remote-messages.sh
@@ -98,4 +98,16 @@ test_expect_success 'fallback to color.ui' '
grep "<BOLD;RED>error<RESET>: error" decoded
'
+test_expect_success 'disallow (color) control sequences in sideband' '
+ write_script .git/color-me-surprised <<-\EOF &&
+ printf "error: Have you \\033[31mread\\033[m this?\\n" >&2
+ exec "$@"
+ EOF
+ test_config_global uploadPack.packObjectshook ./color-me-surprised &&
+ test_commit need-at-least-one-commit &&
+ git clone --no-local . throw-away 2>stderr &&
+ test_decode_color <stderr >decoded &&
+ test_i18ngrep ! RED decoded
+'
+
test_done
From a8c289b0a531d25336a96eaa5e3584414ed4c6c4 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Wed, 6 Nov 2024 21:07:51 +0100
Subject: [PATCH 2/3] sideband: introduce an "escape hatch" to allow control
characters
The preceding commit fixed the vulnerability whereas sideband messages
(that are under the control of the remote server) could contain ANSI
escape sequences that would be sent to the terminal verbatim.
However, this fix may not be desirable under all circumstances, e.g.
when remote servers deliberately add coloring to their messages to
increase their urgency.
To help with those use cases, give users a way to opt-out of the
protections: `sideband.allowControlCharacters`.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
Documentation/config.txt | 2 ++
Documentation/config/sideband.txt | 5 +++++
sideband.c | 10 ++++++++++
t/t5409-colorize-remote-messages.sh | 8 +++++++-
4 files changed, 24 insertions(+), 1 deletion(-)
create mode 100644 Documentation/config/sideband.txt
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0e93aef86264db..abdbfba9bd756a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -511,6 +511,8 @@ include::config/sequencer.txt[]
include::config/showbranch.txt[]
+include::config/sideband.txt[]
+
include::config/sparse.txt[]
include::config/splitindex.txt[]
diff --git a/Documentation/config/sideband.txt b/Documentation/config/sideband.txt
new file mode 100644
index 00000000000000..3fb5045cd79581
--- /dev/null
+++ b/Documentation/config/sideband.txt
@@ -0,0 +1,5 @@
+sideband.allowControlCharacters::
+ By default, control characters that are delivered via the sideband
+ are masked, to prevent potentially unwanted ANSI escape sequences
+ from being sent to the terminal. Use this config setting to override
+ this behavior.
diff --git a/sideband.c b/sideband.c
index 9384cb02d56a04..8ebf1f0743e6b6 100644
--- a/sideband.c
+++ b/sideband.c
@@ -20,6 +20,8 @@ static struct keyword_entry keywords[] = {
{ "error", GIT_COLOR_BOLD_RED },
};
+static int allow_control_characters;
+
/* Returns a color setting (GIT_COLOR_NEVER, etc). */
static int use_sideband_colors(void)
{
@@ -33,6 +35,9 @@ static int use_sideband_colors(void)
if (use_sideband_colors_cached >= 0)
return use_sideband_colors_cached;
+ git_config_get_bool("sideband.allowcontrolcharacters",
+ &allow_control_characters);
+
if (!git_config_get_string(key, &value)) {
use_sideband_colors_cached = git_config_colorbool(key, value);
} else if (!git_config_get_string("color.ui", &value)) {
@@ -63,6 +68,11 @@ void list_config_color_sideband_slots(struct string_list *list, const char *pref
static void strbuf_add_sanitized(struct strbuf *dest, const char *src, int n)
{
+ if (allow_control_characters) {
+ strbuf_add(dest, src, n);
+ return;
+ }
+
strbuf_grow(dest, n);
for (; n && *src; src++, n--) {
if (!iscntrl(*src) || *src == '\t' || *src == '\n')
diff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh
index 6a6e0d15b21050..1cd0640f200009 100755
--- a/t/t5409-colorize-remote-messages.sh
+++ b/t/t5409-colorize-remote-messages.sh
@@ -105,9 +105,15 @@ test_expect_success 'disallow (color) control sequences in sideband' '
EOF
test_config_global uploadPack.packObjectshook ./color-me-surprised &&
test_commit need-at-least-one-commit &&
+
git clone --no-local . throw-away 2>stderr &&
test_decode_color <stderr >decoded &&
- test_i18ngrep ! RED decoded
+ test_i18ngrep ! RED decoded &&
+
+ rm -rf throw-away &&
+ git -c sideband.allowControlCharacters clone --no-local . throw-away 2>stderr &&
+ test_decode_color <stderr >decoded &&
+ test_i18ngrep RED decoded
'
test_done
From c7049c2a7f47c99a67fd869f1ee89d7aa1a328d2 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Mon, 18 Nov 2024 21:42:57 +0100
Subject: [PATCH 3/3] sideband: do allow ANSI color sequences by default
The preceding two commits introduced special handling of the sideband
channel to neutralize ANSI escape sequences before sending the payload
to the terminal, and `sideband.allowControlCharacters` to override that
behavior.
However, some `pre-receive` hooks that are actively used in practice
want to color their messages and therefore rely on the fact that Git
passes them through to the terminal.
In contrast to other ANSI escape sequences, it is highly unlikely that
coloring sequences can be essential tools in attack vectors that mislead
Git users e.g. by hiding crucial information.
Therefore we can have both: Continue to allow ANSI coloring sequences to
be passed to the terminal, and neutralize all other ANSI escape
sequences.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
Documentation/config/sideband.txt | 17 ++++++--
sideband.c | 61 ++++++++++++++++++++++++++---
t/t5409-colorize-remote-messages.sh | 16 +++++++-
3 files changed, 84 insertions(+), 10 deletions(-)
diff --git a/Documentation/config/sideband.txt b/Documentation/config/sideband.txt
index 3fb5045cd79581..f347fd6b33004a 100644
--- a/Documentation/config/sideband.txt
+++ b/Documentation/config/sideband.txt
@@ -1,5 +1,16 @@
sideband.allowControlCharacters::
By default, control characters that are delivered via the sideband
- are masked, to prevent potentially unwanted ANSI escape sequences
- from being sent to the terminal. Use this config setting to override
- this behavior.
+ are masked, except ANSI color sequences. This prevents potentially
+ unwanted ANSI escape sequences from being sent to the terminal. Use
+ this config setting to override this behavior:
++
+--
+ color::
+ Allow ANSI color sequences, line feeds and horizontal tabs,
+ but mask all other control characters. This is the default.
+ false::
+ Mask all control characters other than line feeds and
+ horizontal tabs.
+ true::
+ Allow all control characters to be sent to the terminal.
+--
diff --git a/sideband.c b/sideband.c
index 8ebf1f0743e6b6..afd62aa008154b 100644
--- a/sideband.c
+++ b/sideband.c
@@ -20,7 +20,11 @@ static struct keyword_entry keywords[] = {
{ "error", GIT_COLOR_BOLD_RED },
};
-static int allow_control_characters;
+static enum {
+ ALLOW_NO_CONTROL_CHARACTERS = 0,
+ ALLOW_ALL_CONTROL_CHARACTERS = 1,
+ ALLOW_ANSI_COLOR_SEQUENCES = 2
+} allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES;
/* Returns a color setting (GIT_COLOR_NEVER, etc). */
static int use_sideband_colors(void)
@@ -35,8 +39,24 @@ static int use_sideband_colors(void)
if (use_sideband_colors_cached >= 0)
return use_sideband_colors_cached;
- git_config_get_bool("sideband.allowcontrolcharacters",
- &allow_control_characters);
+ switch (git_config_get_maybe_bool("sideband.allowcontrolcharacters", &i)) {
+ case 0: /* Boolean value */
+ allow_control_characters = i ? ALLOW_ALL_CONTROL_CHARACTERS :
+ ALLOW_NO_CONTROL_CHARACTERS;
+ break;
+ case -1: /* non-Boolean value */
+ if (git_config_get_string("sideband.allowcontrolcharacters",
+ &value))
+ ; /* huh? `get_maybe_bool()` returned -1 */
+ else if (!strcmp(value, "color"))
+ allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES;
+ else
+ warning(_("unrecognized value for `sideband."
+ "allowControlCharacters`: '%s'"), value);
+ break;
+ default:
+ break; /* not configured */
+ }
if (!git_config_get_string(key, &value)) {
use_sideband_colors_cached = git_config_colorbool(key, value);
@@ -66,9 +86,37 @@ void list_config_color_sideband_slots(struct string_list *list, const char *pref
list_config_item(list, prefix, keywords[i].keyword);
}
+static int handle_ansi_color_sequence(struct strbuf *dest, const char *src, int n)
+{
+ int i;
+
+ /*
+ * Valid ANSI color sequences are of the form
+ *
+ * ESC [ [<n> [; <n>]*] m
+ */
+
+ if (allow_control_characters != ALLOW_ANSI_COLOR_SEQUENCES ||
+ n < 3 || src[0] != '\x1b' || src[1] != '[')
+ return 0;
+
+ for (i = 2; i < n; i++) {
+ if (src[i] == 'm') {
+ strbuf_add(dest, src, i + 1);
+ return i;
+ }
+ if (!isdigit(src[i]) && src[i] != ';')
+ break;
+ }
+
+ return 0;
+}
+
static void strbuf_add_sanitized(struct strbuf *dest, const char *src, int n)
{
- if (allow_control_characters) {
+ int i;
+
+ if (allow_control_characters == ALLOW_ALL_CONTROL_CHARACTERS) {
strbuf_add(dest, src, n);
return;
}
@@ -77,7 +125,10 @@ static void strbuf_add_sanitized(struct strbuf *dest, const char *src, int n)
for (; n && *src; src++, n--) {
if (!iscntrl(*src) || *src == '\t' || *src == '\n')
strbuf_addch(dest, *src);
- else {
+ else if ((i = handle_ansi_color_sequence(dest, src, n))) {
+ src += i;
+ n -= i;
+ } else {
strbuf_addch(dest, '^');
strbuf_addch(dest, 0x40 + *src);
}
diff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh
index 1cd0640f200009..43296ea51c5db1 100755
--- a/t/t5409-colorize-remote-messages.sh
+++ b/t/t5409-colorize-remote-messages.sh
@@ -100,7 +100,7 @@ test_expect_success 'fallback to color.ui' '
test_expect_success 'disallow (color) control sequences in sideband' '
write_script .git/color-me-surprised <<-\EOF &&
- printf "error: Have you \\033[31mread\\033[m this?\\n" >&2
+ printf "error: Have you \\033[31mread\\033[m this?\\a\\n" >&2
exec "$@"
EOF
test_config_global uploadPack.packObjectshook ./color-me-surprised &&
@@ -108,12 +108,24 @@ test_expect_success 'disallow (color) control sequences in sideband' '
git clone --no-local . throw-away 2>stderr &&
test_decode_color <stderr >decoded &&
+ test_i18ngrep RED decoded &&
+ test_i18ngrep "\\^G" stderr &&
+ tr -dc "\\007" <stderr >actual &&
+ test_must_be_empty actual &&
+
+ rm -rf throw-away &&
+ git -c sideband.allowControlCharacters=false \
+ clone --no-local . throw-away 2>stderr &&
+ test_decode_color <stderr >decoded &&
test_i18ngrep ! RED decoded &&
+ test_i18ngrep "\\^G" stderr &&
rm -rf throw-away &&
git -c sideband.allowControlCharacters clone --no-local . throw-away 2>stderr &&
test_decode_color <stderr >decoded &&
- test_i18ngrep RED decoded
+ test_i18ngrep RED decoded &&
+ tr -dc "\\007" <stderr >actual &&
+ test_file_not_empty actual
'
test_done

View File

@ -0,0 +1,171 @@
From b01b9b81d36759cdcd07305e78765199e1bc2060 Mon Sep 17 00:00:00 2001
From: Johannes Schindelin <johannes.schindelin@gmx.de>
Date: Mon, 4 Nov 2024 14:48:22 +0100
Subject: [PATCH] credential: disallow Carriage Returns in the protocol by
default
While Git has documented that the credential protocol is line-based,
with newlines as terminators, the exact shape of a newline has not been
documented.
From Git's perspective, which is firmly rooted in the Linux ecosystem,
it is clear that "a newline" means a Line Feed character.
However, even Git's credential protocol respects Windows line endings
(a Carriage Return character followed by a Line Feed character, "CR/LF")
by virtue of using `strbuf_getline()`.
There is a third category of line endings that has been used originally
by MacOS, and that is respected by the default line readers of .NET and
node.js: bare Carriage Returns.
Git cannot handle those, and what is worse: Git's remedy against
CVE-2020-5260 does not catch when credential helpers are used that
interpret bare Carriage Returns as newlines.
Git Credential Manager addressed this as CVE-2024-50338, but other
credential helpers may still be vulnerable. So let's not only disallow
Line Feed characters as part of the values in the credential protocol,
but also disallow Carriage Return characters.
In the unlikely event that a credential helper relies on Carriage
Returns in the protocol, introduce an escape hatch via the
`credential.protectProtocol` config setting.
This addresses CVE-2024-52006.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
Documentation/config/credential.txt | 5 +++++
credential.c | 21 ++++++++++++++-------
credential.h | 4 +++-
t/t0300-credentials.sh | 16 ++++++++++++++++
4 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt
index fd8113d6..9cadca7f 100644
--- a/Documentation/config/credential.txt
+++ b/Documentation/config/credential.txt
@@ -20,6 +20,11 @@ credential.sanitizePrompt::
will be URL-encoded by default). Configure this setting to `false` to
override that behavior.
+credential.protectProtocol::
+ By default, Carriage Return characters are not allowed in the protocol
+ that is used when Git talks to a credential helper. This setting allows
+ users to override this default.
+
credential.username::
If no username is set for a network authentication, use this username
by default. See credential.<context>.* below, and
diff --git a/credential.c b/credential.c
index 1392a54d..b76a7309 100644
--- a/credential.c
+++ b/credential.c
@@ -69,6 +69,8 @@ static int credential_config_callback(const char *var, const char *value,
c->use_http_path = git_config_bool(var, value);
else if (!strcmp(key, "sanitizeprompt"))
c->sanitize_prompt = git_config_bool(var, value);
+ else if (!strcmp(key, "protectprotocol"))
+ c->protect_protocol = git_config_bool(var, value);
return 0;
}
@@ -262,7 +264,8 @@ int credential_read(struct credential *c, FILE *fp)
return 0;
}
-static void credential_write_item(FILE *fp, const char *key, const char *value,
+static void credential_write_item(const struct credential *c,
+ FILE *fp, const char *key, const char *value,
int required)
{
if (!value && required)
@@ -271,24 +274,28 @@ static void credential_write_item(FILE *fp, const char *key, const char *value,
return;
if (strchr(value, '\n'))
die("credential value for %s contains newline", key);
+ if (c->protect_protocol && strchr(value, '\r'))
+ die("credential value for %s contains carriage return\n"
+ "If this is intended, set `credential.protectProtocol=false`",
+ key);
fprintf(fp, "%s=%s\n", key, value);
}
void credential_write(const struct credential *c, FILE *fp)
{
- credential_write_item(fp, "protocol", c->protocol, 1);
- credential_write_item(fp, "host", c->host, 1);
- credential_write_item(fp, "path", c->path, 0);
- credential_write_item(fp, "username", c->username, 0);
- credential_write_item(fp, "password", c->password, 0);
- credential_write_item(fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
+ credential_write_item(c, fp, "protocol", c->protocol, 1);
+ credential_write_item(c, fp, "host", c->host, 1);
+ credential_write_item(c, fp, "path", c->path, 0);
+ credential_write_item(c, fp, "username", c->username, 0);
+ credential_write_item(c, fp, "password", c->password, 0);
+ credential_write_item(c, fp, "oauth_refresh_token", c->oauth_refresh_token, 0);
if (c->password_expiry_utc != TIME_MAX) {
char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
- credential_write_item(fp, "password_expiry_utc", s, 0);
+ credential_write_item(c, fp, "password_expiry_utc", s, 0);
free(s);
}
for (size_t i = 0; i < c->wwwauth_headers.nr; i++)
- credential_write_item(fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
+ credential_write_item(c, fp, "wwwauth[]", c->wwwauth_headers.v[i], 0);
}
static int run_credential_helper(struct credential *c,
diff --git a/credential.h b/credential.h
index 0364d436..2c0b39a9 100644
--- a/credential.h
+++ b/credential.h
@@ -120,7 +120,8 @@ struct credential {
quit:1,
use_http_path:1,
username_from_proto:1,
- sanitize_prompt:1;
+ sanitize_prompt:1,
+ protect_protocol:1;
char *username;
char *password;
@@ -134,6 +135,7 @@ struct credential {
.password_expiry_utc = TIME_MAX, \
.wwwauth_headers = STRVEC_INIT, \
.sanitize_prompt = 1, \
+ .protect_protocol = 1, \
}
/* Initialize a credential structure, setting all fields to empty. */
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index b62c70c1..168ae765 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -720,6 +720,22 @@ test_expect_success 'url parser rejects embedded newlines' '
test_cmp expect stderr
'
+test_expect_success 'url parser rejects embedded carriage returns' '
+ test_config credential.helper "!true" &&
+ test_must_fail git credential fill 2>stderr <<-\EOF &&
+ url=https://example%0d.com/
+ EOF
+ cat >expect <<-\EOF &&
+ fatal: credential value for host contains carriage return
+ If this is intended, set `credential.protectProtocol=false`
+ EOF
+ test_cmp expect stderr &&
+ GIT_ASKPASS=true \
+ git -c credential.protectProtocol=false credential fill <<-\EOF
+ url=https://example%0d.com/
+ EOF
+'
+
test_expect_success 'host-less URLs are parsed as empty host' '
check fill "verbatim foo bar" <<-\EOF
url=cert:///path/to/cert.pem
--
2.23.0

View File

@ -0,0 +1,116 @@
From 6ff658cc78f36baa74c0f25314b0043a8f4b4fc6 Mon Sep 17 00:00:00 2001
From: Todd Zullinger <tmz@pobox.com>
Date: Thu, 16 Nov 2023 14:30:11 -0500
Subject: [PATCH] send-email: avoid duplicate specification warnings
A warning is issued for options which are specified more than once
beginning with perl-Getopt-Long >= 2.55. In addition to causing users
to see warnings, this results in test failures which compare the output.
An example, from t9001-send-email.37:
| +++ diff -u expect actual
| --- expect 2023-11-14 10:38:23.854346488 +0000
| +++ actual 2023-11-14 10:38:23.848346466 +0000
| @@ -1,2 +1,7 @@
| +Duplicate specification "no-chain-reply-to" for option "no-chain-reply-to"
| +Duplicate specification "to-cover|to-cover!" for option "to-cover"
| +Duplicate specification "cc-cover|cc-cover!" for option "cc-cover"
| +Duplicate specification "no-thread" for option "no-thread"
| +Duplicate specification "no-to-cover" for option "no-to-cover"
| fatal: longline.patch:35 is longer than 998 characters
| warning: no patches were sent
| error: last command exited with $?=1
| not ok 37 - reject long lines
Remove the duplicate option specs. These are primarily the explicit
'--no-' prefix opts which were added in f471494303 (git-send-email.perl:
support no- prefix with older GetOptions, 2015-01-30). This was done
specifically to support perl-5.8.0 which includes Getopt::Long 2.32[1].
Getopt::Long 2.33 added support for the '--no-' prefix natively by
appending '!' to the option specification string, which was included in
perl-5.8.1 and is not present in perl-5.8.0. The previous commit bumped
the minimum supported Perl version to 5.8.1 so we no longer need to
provide the '--no-' variants for negatable options manually.
Teach `--git-completion-helper` to output the '--no-' options. They are
not included in the options hash and would otherwise be lost.
Signed-off-by: Todd Zullinger <tmz@pobox.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
git-send-email.perl | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/git-send-email.perl b/git-send-email.perl
index 041db702d4..60afafb375 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -119,13 +119,16 @@ sub completion_helper {
foreach my $key (keys %$original_opts) {
unless (exists $not_for_completion{$key}) {
- $key =~ s/!$//;
+ my $negatable = ($key =~ s/!$//);
if ($key =~ /[:=][si]$/) {
$key =~ s/[:=][si]$//;
push (@send_email_opts, "--$_=") foreach (split (/\|/, $key));
} else {
push (@send_email_opts, "--$_") foreach (split (/\|/, $key));
+ if ($negatable) {
+ push (@send_email_opts, "--no-$_") foreach (split (/\|/, $key));
+ }
}
}
}
@@ -491,7 +494,6 @@ sub config_regexp {
"bcc=s" => \@getopt_bcc,
"no-bcc" => \$no_bcc,
"chain-reply-to!" => \$chain_reply_to,
- "no-chain-reply-to" => sub {$chain_reply_to = 0},
"sendmail-cmd=s" => \$sendmail_cmd,
"smtp-server=s" => \$smtp_server,
"smtp-server-option=s" => \@smtp_server_options,
@@ -506,36 +508,27 @@ sub config_regexp {
"smtp-auth=s" => \$smtp_auth,
"no-smtp-auth" => sub {$smtp_auth = 'none'},
"annotate!" => \$annotate,
- "no-annotate" => sub {$annotate = 0},
"compose" => \$compose,
"quiet" => \$quiet,
"cc-cmd=s" => \$cc_cmd,
"header-cmd=s" => \$header_cmd,
"no-header-cmd" => \$no_header_cmd,
"suppress-from!" => \$suppress_from,
- "no-suppress-from" => sub {$suppress_from = 0},
"suppress-cc=s" => \@suppress_cc,
"signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
- "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
- "cc-cover|cc-cover!" => \$cover_cc,
- "no-cc-cover" => sub {$cover_cc = 0},
- "to-cover|to-cover!" => \$cover_to,
- "no-to-cover" => sub {$cover_to = 0},
+ "cc-cover!" => \$cover_cc,
+ "to-cover!" => \$cover_to,
"confirm=s" => \$confirm,
"dry-run" => \$dry_run,
"envelope-sender=s" => \$envelope_sender,
"thread!" => \$thread,
- "no-thread" => sub {$thread = 0},
"validate!" => \$validate,
- "no-validate" => sub {$validate = 0},
"transfer-encoding=s" => \$target_xfer_encoding,
"format-patch!" => \$format_patch,
- "no-format-patch" => sub {$format_patch = 0},
"8bit-encoding=s" => \$auto_8bit_encoding,
"compose-encoding=s" => \$compose_encoding,
"force" => \$force,
"xmailer!" => \$use_xmailer,
- "no-xmailer" => sub {$use_xmailer = 0},
"batch-size=i" => \$batch_size,
"relogin-delay=i" => \$relogin_delay,
"git-completion-helper" => \$git_completion_helper,
--
2.33.0

View File

@ -1,7 +1,7 @@
%global gitexecdir %{_libexecdir}/git-core
Name: git
Version: 2.43.0
Release: 1
Release: 6
Summary: A popular and widely used Version Control System
License: GPLv2+ or LGPLv2.1
URL: https://git-scm.com/
@ -12,6 +12,19 @@ Source100: git-gui.desktop
Source101: git@.service.in
Source102: git.socket
Patch0: backport-send-email-avoid-duplicate-specification-warnings.patch
Patch1: backport-CVE-2024-32002-submodules-submodule-paths-m.patch
Patch2: backport-CVE-2024-32021-builtin-clone-stop-resolving-symlinks-when-copying-f.patch
Patch3: backport-CVE-2024-32021-builtin-clone-abort-when-hardlinked-source-and-targe.patch
Patch4: backport-CVE-2024-32004-t0411-add-tests-for-cloning-from-partial-repo.patch
Patch5: backport-CVE-2024-32004-fetch-clone-detect-dubious-ownership-of-local-reposi.patch
Patch6: backport-CVE-2024-32020-builtin-clone-refuse-local-clones-of-unsafe-reposito.patch
Patch7: backport-CVE-2024-32465-upload-pack-disable-lazy-fetching-by-default.patch
Patch8: backport-CVE-2024-50349-credential_format-also-encode-host-port.patch
Patch9: backport-CVE-2024-50349-credential-sanitize-the-user-prompt.patch
Patch10: backport-CVE-2024-52006-credential-disallow-Carriage-Returns-in-the-protocol.patch
Patch11: backport-CVE-2024-52005.patch
BuildRequires: gcc gettext
BuildRequires: openssl-devel libcurl-devel expat-devel systemd asciidoc xmlto glib2-devel libsecret-devel pcre2-devel desktop-file-utils
BuildRequires: python3-devel perl-generators perl-interpreter perl-Error perl(Test::More) perl-MailTools perl(Test)
@ -295,6 +308,36 @@ make %{?_smp_mflags} test
%{_mandir}/man7/git*.7.*
%changelog
* Fri Jan 17 2025 fuanan <fuanan3@h-partners.com> - 2.43.0-6
- Type:CVE
- ID:CVE-2024-52005
- SUG:NA
- DESC:Fix CVE-2024-52005
* Wed Jan 15 2025 fuanan <fuanan3@h-partners.com> - 2.43.0-5
- Type:CVE
- ID:CVE-2024-50349 CVE-2024-52006
- SUG:NA
- DESC:Fix CVE-2024-50349 CVE-2024-52006
* Fri May 17 2024 fuanan <fuanan3@h-partners.com> - 2.43.0-4
- Type:CVE
- ID:CVE-2024-32021 CVE-2024-32004 CVE-2024-32020 CVE-2024-32465
- SUG:NA
- DESC:Fix CVE-2024-32021 CVE-2024-32004 CVE-2024-32020 CVE-2024-32465
* Wed May 15 2024 qiaojijun <qiaojijun@kylinos.cn> - 2.43.0-3
- Type:CVE
- ID:CVE-2024-32002
- SUG:NA
- DESC:Fix CVE-2024-32002
* Mon Apr 08 2024 fuanan <fuanan3@h-partners.com> - 2.43.0-2
- Type:bugfix
- ID:NA
- SUG:NA
- DESC:Fix t9001-send-email.sh test error
* Fri Dec 15 2023 fuanan <fuanan3@h-partners.com> - 2.43.0-1
- Type:enhancement
- ID:NA