Fix CVE-2022-39253
This commit is contained in:
parent
cbb5bfd1dd
commit
cdcbd92961
@ -0,0 +1,194 @@
|
||||
From 6f054f9fb3a501c35b55c65e547a244f14c38d56 Mon Sep 17 00:00:00 2001
|
||||
From: Taylor Blau <me@ttaylorr.com>
|
||||
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 <Johannes.Schindelin@gmx.de>
|
||||
Signed-off-by: Taylor Blau <me@ttaylorr.com>
|
||||
---
|
||||
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
|
||||
|
||||
15
git.spec
15
git.spec
@ -1,7 +1,7 @@
|
||||
%global gitexecdir %{_libexecdir}/git-core
|
||||
Name: git
|
||||
Version: 2.27.0
|
||||
Release: 11
|
||||
Release: 12
|
||||
Summary: A popular and widely used Version Control System
|
||||
License: GPLv2+ or LGPLv2.1
|
||||
URL: https://git-scm.com/
|
||||
@ -24,9 +24,10 @@ Patch9: backport-t0033-add-tests-for-safe.directory.patch
|
||||
Patch10: backport-0005-CVE-2022-24765.patch
|
||||
Patch11: backport-0006-CVE-2022-24765.patch
|
||||
Patch12: backport-CVE-2022-29187.patch
|
||||
Patch13: backport-CVE-2022-39260-shell-add-basic-tests.patch
|
||||
Patch14: backport-CVE-2022-39260-shell-limit-size-of-interactive-commands.patch
|
||||
Patch15: backport-CVE-2022-39260-alias.c-reject-too-long-cmdline-strings-in-split_cmd.patch
|
||||
Patch13: backport-CVE-2022-39253-builtin-clone.c-disallow-local-clones-with-symlinks.patch
|
||||
Patch14: backport-CVE-2022-39260-shell-add-basic-tests.patch
|
||||
Patch15: backport-CVE-2022-39260-shell-limit-size-of-interactive-commands.patch
|
||||
Patch16: backport-CVE-2022-39260-alias.c-reject-too-long-cmdline-strings-in-split_cmd.patch
|
||||
|
||||
BuildRequires: gcc gettext
|
||||
BuildRequires: openssl-devel libcurl-devel expat-devel systemd asciidoc xmlto glib2-devel libsecret-devel pcre-devel desktop-file-utils
|
||||
@ -276,6 +277,12 @@ make %{?_smp_mflags} test
|
||||
%{_mandir}/man7/git*.7.*
|
||||
|
||||
%changelog
|
||||
* Mon Oct 24 2022 fuanan <fuanan3@h-partners.com> - 2.27.0-12
|
||||
- Type:CVE
|
||||
- ID:CVE-2022-39253
|
||||
- SUG:NA
|
||||
- DESC:Fix CVE-2022-39253
|
||||
|
||||
* Fri Oct 21 2022 fuanan <fuanan3@h-partners.com> - 2.27.0-11
|
||||
- Type:CVE
|
||||
- ID:CVE-2022-39260
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user