From 9d645763843d0c83d5ac93b42f87d97c6ec6e8a4 Mon Sep 17 00:00:00 2001 From: zhangruifang2020 Date: Sat, 22 Oct 2022 16:48:18 +0800 Subject: [PATCH] Fix CVE-2022-39260 --- ...-disallow-local-clones-with-symlinks.patch | 194 ++++++++++++++++++ git.spec | 10 +- 2 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 builtin-clone.c-disallow-local-clones-with-symlinks.patch diff --git a/builtin-clone.c-disallow-local-clones-with-symlinks.patch b/builtin-clone.c-disallow-local-clones-with-symlinks.patch new file mode 100644 index 0000000..0fc724b --- /dev/null +++ b/builtin-clone.c-disallow-local-clones-with-symlinks.patch @@ -0,0 +1,194 @@ +From 6f054f9fb3a501c35b55c65e547a244f14c38d56 Mon Sep 17 00:00:00 2001 +From: Taylor Blau +Date: Thu, 28 Jul 2022 17:35:17 -0400 +Subject: [PATCH] builtin/clone.c: disallow `--local` clones with symlinks + +When cloning a repository with `--local`, Git relies on either making a +hardlink or copy to every file in the "objects" directory of the source +repository. This is done through the callpath `cmd_clone()` -> +`clone_local()` -> `copy_or_link_directory()`. + +The way this optimization works is by enumerating every file and +directory recursively in the source repository's `$GIT_DIR/objects` +directory, and then either making a copy or hardlink of each file. The +only exception to this rule is when copying the "alternates" file, in +which case paths are rewritten to be absolute before writing a new +"alternates" file in the destination repo. + +One quirk of this implementation is that it dereferences symlinks when +cloning. This behavior was most recently modified in 36596fd2df (clone: +better handle symlinked files at .git/objects/, 2019-07-10), which +attempted to support `--local` clones of repositories with symlinks in +their objects directory in a platform-independent way. + +Unfortunately, this behavior of dereferencing symlinks (that is, +creating a hardlink or copy of the source's link target in the +destination repository) can be used as a component in attacking a +victim by inadvertently exposing the contents of file stored outside of +the repository. + +Take, for example, a repository that stores a Dockerfile and is used to +build Docker images. When building an image, Docker copies the directory +contents into the VM, and then instructs the VM to execute the +Dockerfile at the root of the copied directory. This protects against +directory traversal attacks by copying symbolic links as-is without +dereferencing them. + +That is, if a user has a symlink pointing at their private key material +(where the symlink is present in the same directory as the Dockerfile, +but the key itself is present outside of that directory), the key is +unreadable to a Docker image, since the link will appear broken from the +container's point of view. + +This behavior enables an attack whereby a victim is convinced to clone a +repository containing an embedded submodule (with a URL like +"file:///proc/self/cwd/path/to/submodule") which has a symlink pointing +at a path containing sensitive information on the victim's machine. If a +user is tricked into doing this, the contents at the destination of +those symbolic links are exposed to the Docker image at runtime. + +One approach to preventing this behavior is to recreate symlinks in the +destination repository. But this is problematic, since symlinking the +objects directory are not well-supported. (One potential problem is that +when sharing, e.g. a "pack" directory via symlinks, different writers +performing garbage collection may consider different sets of objects to +be reachable, enabling a situation whereby garbage collecting one +repository may remove reachable objects in another repository). + +Instead, prohibit the local clone optimization when any symlinks are +present in the `$GIT_DIR/objects` directory of the source repository. +Users may clone the repository again by prepending the "file://" scheme +to their clone URL, or by adding the `--no-local` option to their `git +clone` invocation. + +The directory iterator used by `copy_or_link_directory()` must no longer +dereference symlinks (i.e., it *must* call `lstat()` instead of `stat()` +in order to discover whether or not there are symlinks present). This has +no bearing on the overall behavior, since we will immediately `die()` on +encounter a symlink. + +Note that t5604.33 suggests that we do support local clones with +symbolic links in the source repository's objects directory, but this +was likely unintentional, or at least did not take into consideration +the problem with sharing parts of the objects directory with symbolic +links at the time. Update this test to reflect which options are and +aren't supported. + +Helped-by: Johannes Schindelin +Signed-off-by: Taylor Blau +--- + builtin/clone.c | 8 +++--- + t/t5604-clone-reference.sh | 50 ++++++++++++++------------------------ + 2 files changed, 23 insertions(+), 35 deletions(-) + +diff --git a/builtin/clone.c b/builtin/clone.c +index e335734b4c..e626073b1f 100644 +--- a/builtin/clone.c ++++ b/builtin/clone.c +@@ -420,13 +420,11 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, + int src_len, dest_len; + struct dir_iterator *iter; + int iter_status; +- unsigned int flags; + struct strbuf realpath = STRBUF_INIT; + + mkdir_if_missing(dest->buf, 0777); + +- flags = DIR_ITERATOR_PEDANTIC | DIR_ITERATOR_FOLLOW_SYMLINKS; +- iter = dir_iterator_begin(src->buf, flags); ++ iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC); + + if (!iter) + die_errno(_("failed to start iterator over '%s'"), src->buf); +@@ -442,6 +440,10 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, + strbuf_setlen(dest, dest_len); + strbuf_addstr(dest, iter->relative_path); + ++ if (S_ISLNK(iter->st.st_mode)) ++ die(_("symlink '%s' exists, refusing to clone with --local"), ++ iter->relative_path); ++ + if (S_ISDIR(iter->st.st_mode)) { + mkdir_if_missing(dest->buf, 0777); + continue; +diff --git a/t/t5604-clone-reference.sh b/t/t5604-clone-reference.sh +index 2f7be23044..9d32f1c4a4 100755 +--- a/t/t5604-clone-reference.sh ++++ b/t/t5604-clone-reference.sh +@@ -300,8 +300,6 @@ test_expect_success SYMLINKS 'setup repo with manually symlinked or unknown file + ln -s ../an-object $obj && + + cd ../ && +- find . -type f | sort >../../../T.objects-files.raw && +- find . -type l | sort >../../../T.objects-symlinks.raw && + echo unknown_content >unknown_file + ) && + git -C T fsck && +@@ -310,19 +308,27 @@ test_expect_success SYMLINKS 'setup repo with manually symlinked or unknown file + + + test_expect_success SYMLINKS 'clone repo with symlinked or unknown files at objects/' ' +- for option in --local --no-hardlinks --shared --dissociate ++ # None of these options work when cloning locally, since T has ++ # symlinks in its `$GIT_DIR/objects` directory ++ for option in --local --no-hardlinks --dissociate + do +- git clone $option T T$option || return 1 && +- git -C T$option fsck || return 1 && +- git -C T$option rev-list --all --objects >T$option.objects && +- test_cmp T.objects T$option.objects && +- ( +- cd T$option/.git/objects && +- find . -type f | sort >../../../T$option.objects-files.raw && +- find . -type l | sort >../../../T$option.objects-symlinks.raw +- ) ++ test_must_fail git clone $option T T$option 2>err || return 1 && ++ test_i18ngrep "symlink.*exists" err || return 1 + done && + ++ # But `--shared` clones should still work, even when specifying ++ # a local path *and* that repository has symlinks present in its ++ # `$GIT_DIR/objects` directory. ++ git clone --shared T T--shared && ++ git -C T--shared fsck && ++ git -C T--shared rev-list --all --objects >T--shared.objects && ++ test_cmp T.objects T--shared.objects && ++ ( ++ cd T--shared/.git/objects && ++ find . -type f | sort >../../../T--shared.objects-files.raw && ++ find . -type l | sort >../../../T--shared.objects-symlinks.raw ++ ) && ++ + for raw in $(ls T*.raw) + do + sed -e "s!/../!/Y/!; s![0-9a-f]\{38,\}!Z!" -e "/commit-graph/d" \ +@@ -330,26 +336,6 @@ test_expect_success SYMLINKS 'clone repo with symlinked or unknown files at obje + sort $raw.de-sha-1 >$raw.de-sha || return 1 + done && + +- cat >expected-files <<-EOF && +- ./Y/Z +- ./Y/Z +- ./Y/Z +- ./a-loose-dir/Z +- ./an-object +- ./info/packs +- ./pack/pack-Z.idx +- ./pack/pack-Z.pack +- ./packs/pack-Z.idx +- ./packs/pack-Z.pack +- ./unknown_file +- EOF +- +- for option in --local --no-hardlinks --dissociate +- do +- test_cmp expected-files T$option.objects-files.raw.de-sha || return 1 && +- test_must_be_empty T$option.objects-symlinks.raw.de-sha || return 1 +- done && +- + echo ./info/alternates >expected-files && + test_cmp expected-files T--shared.objects-files.raw && + test_must_be_empty T--shared.objects-symlinks.raw +-- +2.27.0 + diff --git a/git.spec b/git.spec index 2089206..60fca37 100644 --- a/git.spec +++ b/git.spec @@ -1,7 +1,7 @@ %global gitexecdir %{_libexecdir}/git-core Name: git Version: 2.33.0 -Release: 3 +Release: 4 Summary: A popular and widely used Version Control System License: GPLv2+ or LGPLv2.1 URL: https://git-scm.com/ @@ -21,6 +21,8 @@ Patch5: backport-0005-CVE-2022-24765.patch Patch6: backport-0006-CVE-2022-24765.patch Patch7: backport-CVE-2022-29187.patch +Patch8: builtin-clone.c-disallow-local-clones-with-symlinks.patch + BuildRequires: gcc gettext BuildRequires: openssl-devel libcurl-devel expat-devel systemd asciidoc xmlto glib2-devel libsecret-devel pcre-devel desktop-file-utils BuildRequires: python3-devel perl-generators perl-interpreter perl-Error perl(Test::More) perl-MailTools perl(Test) @@ -263,6 +265,12 @@ make %{?_smp_mflags} test %{_mandir}/man7/git*.7.* %changelog +* Sat Oct 22 2022 zhangruifang - 2.33.0-4 +- Type:CVE +- ID:CVE-2022-39260 +- SUG:NA +- DESC:Fix CVE-2022-39260 + * Mon Jul 18 2022 fuanan - 2.33.0-3 - Type:CVE - ID:CVE-2022-29187 -- Gitee