update version to 2.33.0
This commit is contained in:
parent
51f0120d0e
commit
3cbe224deb
@ -1,382 +0,0 @@
|
|||||||
From 684dd4c2b414bcf648505e74498a608f28de4592 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Matheus Tavares <matheus.bernardino@usp.br>
|
|
||||||
Date: Thu, 10 Dec 2020 10:27:55 -0300
|
|
||||||
Subject: [PATCH] checkout: fix bug that makes checkout follow symlinks in
|
|
||||||
leading path
|
|
||||||
|
|
||||||
Before checking out a file, we have to confirm that all of its leading
|
|
||||||
components are real existing directories. And to reduce the number of
|
|
||||||
lstat() calls in this process, we cache the last leading path known to
|
|
||||||
contain only directories. However, when a path collision occurs (e.g.
|
|
||||||
when checking out case-sensitive files in case-insensitive file
|
|
||||||
systems), a cached path might have its file type changed on disk,
|
|
||||||
leaving the cache on an invalid state. Normally, this doesn't bring
|
|
||||||
any bad consequences as we usually check out files in index order, and
|
|
||||||
therefore, by the time the cached path becomes outdated, we no longer
|
|
||||||
need it anyway (because all files in that directory would have already
|
|
||||||
been written).
|
|
||||||
|
|
||||||
But, there are some users of the checkout machinery that do not always
|
|
||||||
follow the index order. In particular: checkout-index writes the paths
|
|
||||||
in the same order that they appear on the CLI (or stdin); and the
|
|
||||||
delayed checkout feature -- used when a long-running filter process
|
|
||||||
replies with "status=delayed" -- postpones the checkout of some entries,
|
|
||||||
thus modifying the checkout order.
|
|
||||||
|
|
||||||
When we have to check out an out-of-order entry and the lstat() cache is
|
|
||||||
invalid (due to a previous path collision), checkout_entry() may end up
|
|
||||||
using the invalid data and thrusting that the leading components are
|
|
||||||
real directories when, in reality, they are not. In the best case
|
|
||||||
scenario, where the directory was replaced by a regular file, the user
|
|
||||||
will get an error: "fatal: unable to create file 'foo/bar': Not a
|
|
||||||
directory". But if the directory was replaced by a symlink, checkout
|
|
||||||
could actually end up following the symlink and writing the file at a
|
|
||||||
wrong place, even outside the repository. Since delayed checkout is
|
|
||||||
affected by this bug, it could be used by an attacker to write
|
|
||||||
arbitrary files during the clone of a maliciously crafted repository.
|
|
||||||
|
|
||||||
Some candidate solutions considered were to disable the lstat() cache
|
|
||||||
during unordered checkouts or sort the entries before passing them to
|
|
||||||
the checkout machinery. But both ideas include some performance penalty
|
|
||||||
and they don't future-proof the code against new unordered use cases.
|
|
||||||
|
|
||||||
Instead, we now manually reset the lstat cache whenever we successfully
|
|
||||||
remove a directory. Note: We are not even checking whether the directory
|
|
||||||
was the same as the lstat cache points to because we might face a
|
|
||||||
scenario where the paths refer to the same location but differ due to
|
|
||||||
case folding, precomposed UTF-8 issues, or the presence of `..`
|
|
||||||
components in the path. Two regression tests, with case-collisions and
|
|
||||||
utf8-collisions, are also added for both checkout-index and delayed
|
|
||||||
checkout.
|
|
||||||
|
|
||||||
Note: to make the previously mentioned clone attack unfeasible, it would
|
|
||||||
be sufficient to reset the lstat cache only after the remove_subtree()
|
|
||||||
call inside checkout_entry(). This is the place where we would remove a
|
|
||||||
directory whose path collides with the path of another entry that we are
|
|
||||||
currently trying to check out (possibly a symlink). However, in the
|
|
||||||
interest of a thorough fix that does not leave Git open to
|
|
||||||
similar-but-not-identical attack vectors, we decided to intercept
|
|
||||||
all `rmdir()` calls in one fell swoop.
|
|
||||||
|
|
||||||
This addresses CVE-2021-21300.
|
|
||||||
|
|
||||||
Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de>
|
|
||||||
Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
|
|
||||||
---
|
|
||||||
cache.h | 1 +
|
|
||||||
compat/mingw.c | 2 +
|
|
||||||
git-compat-util.h | 5 +++
|
|
||||||
run-command.c | 9 ++++-
|
|
||||||
symlinks.c | 24 +++++++++++
|
|
||||||
t/t0021-conversion.sh | 71 +++++++++++++++++++++++++++++++++
|
|
||||||
t/t0021/rot13-filter.pl | 21 ++++++++--
|
|
||||||
t/t2006-checkout-index-basic.sh | 40 +++++++++++++++++++
|
|
||||||
unpack-trees.c | 3 ++
|
|
||||||
9 files changed, 172 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/cache.h b/cache.h
|
|
||||||
index 7109765..0a0b32f 100644
|
|
||||||
--- a/cache.h
|
|
||||||
+++ b/cache.h
|
|
||||||
@@ -1657,6 +1657,7 @@ int has_symlink_leading_path(const char *name, int len);
|
|
||||||
int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
|
|
||||||
int check_leading_path(const char *name, int len);
|
|
||||||
int has_dirs_only_path(const char *name, int len, int prefix_len);
|
|
||||||
+void invalidate_lstat_cache(void);
|
|
||||||
void schedule_dir_for_removal(const char *name, int len);
|
|
||||||
void remove_scheduled_dirs(void);
|
|
||||||
|
|
||||||
diff --git a/compat/mingw.c b/compat/mingw.c
|
|
||||||
index a00f331..a435998 100644
|
|
||||||
--- a/compat/mingw.c
|
|
||||||
+++ b/compat/mingw.c
|
|
||||||
@@ -367,6 +367,8 @@ int mingw_rmdir(const char *pathname)
|
|
||||||
ask_yes_no_if_possible("Deletion of directory '%s' failed. "
|
|
||||||
"Should I try again?", pathname))
|
|
||||||
ret = _wrmdir(wpathname);
|
|
||||||
+ if (!ret)
|
|
||||||
+ invalidate_lstat_cache();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/git-compat-util.h b/git-compat-util.h
|
|
||||||
index 104993b..7d3db43 100644
|
|
||||||
--- a/git-compat-util.h
|
|
||||||
+++ b/git-compat-util.h
|
|
||||||
@@ -349,6 +349,11 @@ static inline int noop_core_config(const char *var, const char *value, void *cb)
|
|
||||||
#define platform_core_config noop_core_config
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+int lstat_cache_aware_rmdir(const char *path);
|
|
||||||
+#if !defined(__MINGW32__) && !defined(_MSC_VER)
|
|
||||||
+#define rmdir lstat_cache_aware_rmdir
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
#ifndef has_dos_drive_prefix
|
|
||||||
static inline int git_has_dos_drive_prefix(const char *path)
|
|
||||||
{
|
|
||||||
diff --git a/run-command.c b/run-command.c
|
|
||||||
index ea4d0fb..25fbab2 100644
|
|
||||||
--- a/run-command.c
|
|
||||||
+++ b/run-command.c
|
|
||||||
@@ -990,6 +990,7 @@ int finish_command(struct child_process *cmd)
|
|
||||||
int ret = wait_or_whine(cmd->pid, cmd->argv[0], 0);
|
|
||||||
trace2_child_exit(cmd, ret);
|
|
||||||
child_process_clear(cmd);
|
|
||||||
+ invalidate_lstat_cache();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1291,13 +1292,19 @@ int start_async(struct async *async)
|
|
||||||
int finish_async(struct async *async)
|
|
||||||
{
|
|
||||||
#ifdef NO_PTHREADS
|
|
||||||
- return wait_or_whine(async->pid, "child process", 0);
|
|
||||||
+ int ret = wait_or_whine(async->pid, "child process", 0);
|
|
||||||
+
|
|
||||||
+ invalidate_lstat_cache();
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
#else
|
|
||||||
void *ret = (void *)(intptr_t)(-1);
|
|
||||||
|
|
||||||
if (pthread_join(async->tid, &ret))
|
|
||||||
error("pthread_join failed");
|
|
||||||
+ invalidate_lstat_cache();
|
|
||||||
return (int)(intptr_t)ret;
|
|
||||||
+
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/symlinks.c b/symlinks.c
|
|
||||||
index 69d458a..7dbb6b2 100644
|
|
||||||
--- a/symlinks.c
|
|
||||||
+++ b/symlinks.c
|
|
||||||
@@ -267,6 +267,13 @@ int has_dirs_only_path(const char *name, int len, int prefix_len)
|
|
||||||
*/
|
|
||||||
static int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len)
|
|
||||||
{
|
|
||||||
+ /*
|
|
||||||
+ * Note: this function is used by the checkout machinery, which also
|
|
||||||
+ * takes care to properly reset the cache when it performs an operation
|
|
||||||
+ * that would leave the cache outdated. If this function starts caching
|
|
||||||
+ * anything else besides FL_DIR, remember to also invalidate the cache
|
|
||||||
+ * when creating or deleting paths that might be in the cache.
|
|
||||||
+ */
|
|
||||||
return lstat_cache(cache, name, len,
|
|
||||||
FL_DIR|FL_FULLPATH, prefix_len) &
|
|
||||||
FL_DIR;
|
|
||||||
@@ -321,3 +328,20 @@ void remove_scheduled_dirs(void)
|
|
||||||
{
|
|
||||||
do_remove_scheduled_dirs(0);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+void invalidate_lstat_cache(void)
|
|
||||||
+{
|
|
||||||
+ reset_lstat_cache(&default_cache);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+#undef rmdir
|
|
||||||
+int lstat_cache_aware_rmdir(const char *path)
|
|
||||||
+{
|
|
||||||
+ /* Any change in this function must be made also in `mingw_rmdir()` */
|
|
||||||
+ int ret = rmdir(path);
|
|
||||||
+
|
|
||||||
+ if (!ret)
|
|
||||||
+ invalidate_lstat_cache();
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
|
|
||||||
index f6deaf4..cd15ddf 100755
|
|
||||||
--- a/t/t0021-conversion.sh
|
|
||||||
+++ b/t/t0021-conversion.sh
|
|
||||||
@@ -953,4 +953,75 @@ test_expect_success PERL 'invalid file in delayed checkout' '
|
|
||||||
grep "error: external filter .* signaled that .unfiltered. is now available although it has not been delayed earlier" git-stderr.log
|
|
||||||
'
|
|
||||||
|
|
||||||
+for mode in 'case' 'utf-8'
|
|
||||||
+do
|
|
||||||
+ case "$mode" in
|
|
||||||
+ case) dir='A' symlink='a' mode_prereq='CASE_INSENSITIVE_FS' ;;
|
|
||||||
+ utf-8)
|
|
||||||
+ dir=$(printf "\141\314\210") symlink=$(printf "\303\244")
|
|
||||||
+ mode_prereq='UTF8_NFD_TO_NFC' ;;
|
|
||||||
+ esac
|
|
||||||
+
|
|
||||||
+ test_expect_success PERL,SYMLINKS,$mode_prereq \
|
|
||||||
+ "delayed checkout with $mode-collision don't write to the wrong place" '
|
|
||||||
+ test_config_global filter.delay.process \
|
|
||||||
+ "\"$TEST_ROOT/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" &&
|
|
||||||
+ test_config_global filter.delay.required true &&
|
|
||||||
+ git init $mode-collision &&
|
|
||||||
+ (
|
|
||||||
+ cd $mode-collision &&
|
|
||||||
+ mkdir target-dir &&
|
|
||||||
+ empty_oid=$(printf "" | git hash-object -w --stdin) &&
|
|
||||||
+ symlink_oid=$(printf "%s" "$PWD/target-dir" | git hash-object -w --stdin) &&
|
|
||||||
+ attr_oid=$(echo "$dir/z filter=delay" | git hash-object -w --stdin) &&
|
|
||||||
+ cat >objs <<-EOF &&
|
|
||||||
+ 100644 blob $empty_oid $dir/x
|
|
||||||
+ 100644 blob $empty_oid $dir/y
|
|
||||||
+ 100644 blob $empty_oid $dir/z
|
|
||||||
+ 120000 blob $symlink_oid $symlink
|
|
||||||
+ 100644 blob $attr_oid .gitattributes
|
|
||||||
+ EOF
|
|
||||||
+ git update-index --index-info <objs &&
|
|
||||||
+ git commit -m "test commit"
|
|
||||||
+ ) &&
|
|
||||||
+ git clone $mode-collision $mode-collision-cloned &&
|
|
||||||
+ # Make sure z was really delayed
|
|
||||||
+ grep "IN: smudge $dir/z .* \\[DELAYED\\]" $mode-collision-cloned/delayed.log &&
|
|
||||||
+ # Should not create $dir/z at $symlink/z
|
|
||||||
+ test_path_is_missing $mode-collision/target-dir/z
|
|
||||||
+ '
|
|
||||||
+done
|
|
||||||
+
|
|
||||||
+test_expect_success PERL,SYMLINKS,CASE_INSENSITIVE_FS \
|
|
||||||
+"delayed checkout with submodule collision don't write to the wrong place" '
|
|
||||||
+ git init collision-with-submodule &&
|
|
||||||
+ (
|
|
||||||
+ cd collision-with-submodule &&
|
|
||||||
+ git config filter.delay.process "\"$TEST_ROOT/rot13-filter.pl\" --always-delay delayed.log clean smudge delay" &&
|
|
||||||
+ git config filter.delay.required true &&
|
|
||||||
+ # We need Git to treat the submodule "a" and the
|
|
||||||
+ # leading dir "A" as different paths in the index.
|
|
||||||
+ git config --local core.ignoreCase false &&
|
|
||||||
+ empty_oid=$(printf "" | git hash-object -w --stdin) &&
|
|
||||||
+ attr_oid=$(echo "A/B/y filter=delay" | git hash-object -w --stdin) &&
|
|
||||||
+ cat >objs <<-EOF &&
|
|
||||||
+ 100644 blob $empty_oid A/B/x
|
|
||||||
+ 100644 blob $empty_oid A/B/y
|
|
||||||
+ 100644 blob $attr_oid .gitattributes
|
|
||||||
+ EOF
|
|
||||||
+ git update-index --index-info <objs &&
|
|
||||||
+ git init a &&
|
|
||||||
+ mkdir target-dir &&
|
|
||||||
+ symlink_oid=$(printf "%s" "$PWD/target-dir" | git -C a hash-object -w --stdin) &&
|
|
||||||
+ echo "120000 blob $symlink_oid b" >objs &&
|
|
||||||
+ git -C a update-index --index-info <objs &&
|
|
||||||
+ git -C a commit -m sub &&
|
|
||||||
+ git submodule add ./a &&
|
|
||||||
+ git commit -m super &&
|
|
||||||
+ git checkout --recurse-submodules . &&
|
|
||||||
+ grep "IN: smudge A/B/y .* \\[DELAYED\\]" delayed.log &&
|
|
||||||
+ test_path_is_missing target-dir/y
|
|
||||||
+ )
|
|
||||||
+'
|
|
||||||
+
|
|
||||||
test_done
|
|
||||||
diff --git a/t/t0021/rot13-filter.pl b/t/t0021/rot13-filter.pl
|
|
||||||
index cd32a82..b8782f7 100644
|
|
||||||
--- a/t/t0021/rot13-filter.pl
|
|
||||||
+++ b/t/t0021/rot13-filter.pl
|
|
||||||
@@ -2,10 +2,16 @@
|
|
||||||
# Example implementation for the Git filter protocol version 2
|
|
||||||
# See Documentation/gitattributes.txt, section "Filter Protocol"
|
|
||||||
#
|
|
||||||
-# The first argument defines a debug log file that the script write to.
|
|
||||||
-# All remaining arguments define a list of supported protocol
|
|
||||||
-# capabilities ("clean", "smudge", etc).
|
|
||||||
+# Usage: rot13-filter.pl [--always-delay] <log path> <capabilities>
|
|
||||||
#
|
|
||||||
+# Log path defines a debug log file that the script writes to. The
|
|
||||||
+# subsequent arguments define a list of supported protocol capabilities
|
|
||||||
+# ("clean", "smudge", etc).
|
|
||||||
+#
|
|
||||||
+# When --always-delay is given all pathnames with the "can-delay" flag
|
|
||||||
+# that don't appear on the list bellow are delayed with a count of 1
|
|
||||||
+# (see more below).
|
|
||||||
+#
|
|
||||||
# This implementation supports special test cases:
|
|
||||||
# (1) If data with the pathname "clean-write-fail.r" is processed with
|
|
||||||
# a "clean" operation then the write operation will die.
|
|
||||||
@@ -53,6 +59,13 @@ sub gitperllib {
|
|
||||||
use Git::Packet;
|
|
||||||
|
|
||||||
my $MAX_PACKET_CONTENT_SIZE = 65516;
|
|
||||||
+
|
|
||||||
+my $always_delay = 0;
|
|
||||||
+if ( $ARGV[0] eq '--always-delay' ) {
|
|
||||||
+ $always_delay = 1;
|
|
||||||
+ shift @ARGV;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
my $log_file = shift @ARGV;
|
|
||||||
my @capabilities = @ARGV;
|
|
||||||
|
|
||||||
@@ -134,6 +147,8 @@ sub rot13 {
|
|
||||||
if ( $buffer eq "can-delay=1" ) {
|
|
||||||
if ( exists $DELAY{$pathname} and $DELAY{$pathname}{"requested"} == 0 ) {
|
|
||||||
$DELAY{$pathname}{"requested"} = 1;
|
|
||||||
+ } elsif ( !exists $DELAY{$pathname} and $always_delay ) {
|
|
||||||
+ $DELAY{$pathname} = { "requested" => 1, "count" => 1 };
|
|
||||||
}
|
|
||||||
} elsif ($buffer =~ /^(ref|treeish|blob)=/) {
|
|
||||||
print $debug " $buffer";
|
|
||||||
diff --git a/t/t2006-checkout-index-basic.sh b/t/t2006-checkout-index-basic.sh
|
|
||||||
index 8e181db..602d8fe 100755
|
|
||||||
--- a/t/t2006-checkout-index-basic.sh
|
|
||||||
+++ b/t/t2006-checkout-index-basic.sh
|
|
||||||
@@ -32,4 +32,44 @@ test_expect_success 'checkout-index reports errors (stdin)' '
|
|
||||||
test_i18ngrep not.in.the.cache stderr
|
|
||||||
'
|
|
||||||
|
|
||||||
+for mode in 'case' 'utf-8'
|
|
||||||
+do
|
|
||||||
+ case "$mode" in
|
|
||||||
+ case) dir='A' symlink='a' mode_prereq='CASE_INSENSITIVE_FS' ;;
|
|
||||||
+ utf-8)
|
|
||||||
+ dir=$(printf "\141\314\210") symlink=$(printf "\303\244")
|
|
||||||
+ mode_prereq='UTF8_NFD_TO_NFC' ;;
|
|
||||||
+ esac
|
|
||||||
+
|
|
||||||
+ test_expect_success SYMLINKS,$mode_prereq \
|
|
||||||
+ "checkout-index with $mode-collision don't write to the wrong place" '
|
|
||||||
+ git init $mode-collision &&
|
|
||||||
+ (
|
|
||||||
+ cd $mode-collision &&
|
|
||||||
+ mkdir target-dir &&
|
|
||||||
+ empty_obj_hex=$(git hash-object -w --stdin </dev/null) &&
|
|
||||||
+ symlink_hex=$(printf "%s" "$PWD/target-dir" | git hash-object -w --stdin) &&
|
|
||||||
+ cat >objs <<-EOF &&
|
|
||||||
+ 100644 blob ${empty_obj_hex} ${dir}/x
|
|
||||||
+ 100644 blob ${empty_obj_hex} ${dir}/y
|
|
||||||
+ 100644 blob ${empty_obj_hex} ${dir}/z
|
|
||||||
+ 120000 blob ${symlink_hex} ${symlink}
|
|
||||||
+ EOF
|
|
||||||
+ git update-index --index-info <objs &&
|
|
||||||
+ # Note: the order is important here to exercise the
|
|
||||||
+ # case where the file at ${dir} has its type changed by
|
|
||||||
+ # the time Git tries to check out ${dir}/z.
|
|
||||||
+ #
|
|
||||||
+ # Also, we use core.precomposeUnicode=false because we
|
|
||||||
+ # want Git to treat the UTF-8 paths transparently on
|
|
||||||
+ # Mac OS, matching what is in the index.
|
|
||||||
+ #
|
|
||||||
+ git -c core.precomposeUnicode=false checkout-index -f \
|
|
||||||
+ ${dir}/x ${dir}/y ${symlink} ${dir}/z &&
|
|
||||||
+ # Should not create ${dir}/z at ${symlink}/z
|
|
||||||
+ test_path_is_missing target-dir/z
|
|
||||||
+ )
|
|
||||||
+ '
|
|
||||||
+done
|
|
||||||
+
|
|
||||||
test_done
|
|
||||||
diff --git a/unpack-trees.c b/unpack-trees.c
|
|
||||||
index 323280d..2344b5e 100644
|
|
||||||
--- a/unpack-trees.c
|
|
||||||
+++ b/unpack-trees.c
|
|
||||||
@@ -417,6 +417,9 @@ static int check_updates(struct unpack_trees_options *o,
|
|
||||||
|
|
||||||
progress = get_progress(o, index);
|
|
||||||
|
|
||||||
+ /* Start with clean cache to avoid using any possibly outdated info. */
|
|
||||||
+ invalidate_lstat_cache();
|
|
||||||
+
|
|
||||||
git_attr_set_direction(GIT_ATTR_CHECKOUT);
|
|
||||||
|
|
||||||
if (should_update_submodules())
|
|
||||||
--
|
|
||||||
2.23.0
|
|
||||||
|
|
||||||
@ -1,111 +0,0 @@
|
|||||||
From bccc37fdc7ec66377af454417013f7612aef75e6 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Adam Dinwoodie <adam@dinwoodie.org>
|
|
||||||
Date: Thu, 29 Apr 2021 21:11:44 +0100
|
|
||||||
Subject: [PATCH] cygwin: disallow backslashes in file names
|
|
||||||
|
|
||||||
The backslash character is not a valid part of a file name on Windows.
|
|
||||||
If, in Windows, Git attempts to write a file that has a backslash
|
|
||||||
character in the filename, it will be incorrectly interpreted as a
|
|
||||||
directory separator.
|
|
||||||
|
|
||||||
This caused CVE-2019-1354 in MinGW, as this behaviour can be manipulated
|
|
||||||
to cause the checkout to write to files it ought not write to, such as
|
|
||||||
adding code to the .git/hooks directory. This was fixed by e1d911dd4c
|
|
||||||
(mingw: disallow backslash characters in tree objects' file names,
|
|
||||||
2019-09-12). However, the vulnerability also exists in Cygwin: while
|
|
||||||
Cygwin mostly provides a POSIX-like path system, it will still interpret
|
|
||||||
a backslash as a directory separator.
|
|
||||||
|
|
||||||
To avoid this vulnerability, CVE-2021-29468, extend the previous fix to
|
|
||||||
also apply to Cygwin.
|
|
||||||
|
|
||||||
Similarly, extend the test case added by the previous version of the
|
|
||||||
commit. The test suite doesn't have an easy way to say "run this test
|
|
||||||
if in MinGW or Cygwin", so add a new test prerequisite that covers both.
|
|
||||||
|
|
||||||
As well as checking behaviour in the presence of paths containing
|
|
||||||
backslashes, the existing test also checks behaviour in the presence of
|
|
||||||
paths that differ only by the presence of a trailing ".". MinGW follows
|
|
||||||
normal Windows application behaviour and treats them as the same path,
|
|
||||||
but Cygwin more closely emulates *nix systems (at the expense of
|
|
||||||
compatibility with native Windows applications) and will create and
|
|
||||||
distinguish between such paths. Gate the relevant bit of that test
|
|
||||||
accordingly.
|
|
||||||
|
|
||||||
Reported-by: RyotaK <security@ryotak.me>
|
|
||||||
Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
|
|
||||||
Signed-off-by: Adam Dinwoodie <adam@dinwoodie.org>
|
|
||||||
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
|
||||||
---
|
|
||||||
read-cache.c | 2 +-
|
|
||||||
t/t7415-submodule-names.sh | 13 ++++++++-----
|
|
||||||
t/test-lib.sh | 2 ++
|
|
||||||
3 files changed, 11 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/read-cache.c b/read-cache.c
|
|
||||||
index 5a907af..b6c13bc 100644
|
|
||||||
--- a/read-cache.c
|
|
||||||
+++ b/read-cache.c
|
|
||||||
@@ -985,7 +985,7 @@ int verify_path(const char *path, unsigned mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (protect_ntfs) {
|
|
||||||
-#ifdef GIT_WINDOWS_NATIVE
|
|
||||||
+#if defined GIT_WINDOWS_NATIVE || defined __CYGWIN__
|
|
||||||
if (c == '\\')
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
diff --git a/t/t7415-submodule-names.sh b/t/t7415-submodule-names.sh
|
|
||||||
index f70368b..6bf098a 100755
|
|
||||||
--- a/t/t7415-submodule-names.sh
|
|
||||||
+++ b/t/t7415-submodule-names.sh
|
|
||||||
@@ -191,7 +191,7 @@ test_expect_success 'fsck detects corrupt .gitmodules' '
|
|
||||||
)
|
|
||||||
'
|
|
||||||
|
|
||||||
-test_expect_success MINGW 'prevent git~1 squatting on Windows' '
|
|
||||||
+test_expect_success WINDOWS 'prevent git~1 squatting on Windows' '
|
|
||||||
git init squatting &&
|
|
||||||
(
|
|
||||||
cd squatting &&
|
|
||||||
@@ -219,10 +219,13 @@ test_expect_success MINGW 'prevent git~1 squatting on Windows' '
|
|
||||||
test_tick &&
|
|
||||||
git -c core.protectNTFS=false commit -m "module"
|
|
||||||
) &&
|
|
||||||
- test_must_fail git -c core.protectNTFS=false \
|
|
||||||
- clone --recurse-submodules squatting squatting-clone 2>err &&
|
|
||||||
- test_i18ngrep -e "directory not empty" -e "not an empty directory" err &&
|
|
||||||
- ! grep gitdir squatting-clone/d/a/git~2
|
|
||||||
+ if test_have_prereq MINGW
|
|
||||||
+ then
|
|
||||||
+ test_must_fail git -c core.protectNTFS=false \
|
|
||||||
+ clone --recurse-submodules squatting squatting-clone 2>err &&
|
|
||||||
+ test_i18ngrep -e "directory not empty" -e "not an empty directory" err &&
|
|
||||||
+ ! grep gitdir squatting-clone/d/a/git~2
|
|
||||||
+ fi
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'git dirs of sibling submodules must not be nested' '
|
|
||||||
diff --git a/t/test-lib.sh b/t/test-lib.sh
|
|
||||||
index d3f6af6..e84b8c8 100644
|
|
||||||
--- a/t/test-lib.sh
|
|
||||||
+++ b/t/test-lib.sh
|
|
||||||
@@ -1457,6 +1457,7 @@ case $uname_s in
|
|
||||||
test_set_prereq NATIVE_CRLF
|
|
||||||
test_set_prereq SED_STRIPS_CR
|
|
||||||
test_set_prereq GREP_STRIPS_CR
|
|
||||||
+ test_set_prereq WINDOWS
|
|
||||||
GIT_TEST_CMP=mingw_test_cmp
|
|
||||||
;;
|
|
||||||
*CYGWIN*)
|
|
||||||
@@ -1465,6 +1466,7 @@ case $uname_s in
|
|
||||||
test_set_prereq CYGWIN
|
|
||||||
test_set_prereq SED_STRIPS_CR
|
|
||||||
test_set_prereq GREP_STRIPS_CR
|
|
||||||
+ test_set_prereq WINDOWS
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
test_set_prereq POSIXPERM
|
|
||||||
--
|
|
||||||
1.8.3.1
|
|
||||||
|
|
||||||
@ -1,104 +0,0 @@
|
|||||||
From a02ea577174ab8ed18f847cf1693f213e0b9c473 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Jeff King <peff@peff.net>
|
|
||||||
Date: Thu, 7 Jan 2021 04:43:58 -0500
|
|
||||||
Subject: [PATCH] git_connect_git(): forbid newlines in host and path
|
|
||||||
|
|
||||||
When we connect to a git:// server, we send an initial request that
|
|
||||||
looks something like:
|
|
||||||
|
|
||||||
002dgit-upload-pack repo.git\0host=example.com
|
|
||||||
|
|
||||||
If the repo path contains a newline, then it's included literally, and
|
|
||||||
we get:
|
|
||||||
|
|
||||||
002egit-upload-pack repo
|
|
||||||
.git\0host=example.com
|
|
||||||
|
|
||||||
This works fine if you really do have a newline in your repository name;
|
|
||||||
the server side uses the pktline framing to parse the string, not
|
|
||||||
newlines. However, there are many _other_ protocols in the wild that do
|
|
||||||
parse on newlines, such as HTTP. So a carefully constructed git:// URL
|
|
||||||
can actually turn into a valid HTTP request. For example:
|
|
||||||
|
|
||||||
git://localhost:1234/%0d%0a%0d%0aGET%20/%20HTTP/1.1 %0d%0aHost:localhost%0d%0a%0d%0a
|
|
||||||
|
|
||||||
becomes:
|
|
||||||
|
|
||||||
0050git-upload-pack /
|
|
||||||
GET / HTTP/1.1
|
|
||||||
Host:localhost
|
|
||||||
|
|
||||||
host=localhost:1234
|
|
||||||
|
|
||||||
on the wire. Again, this isn't a problem for a real Git server, but it
|
|
||||||
does mean that feeding a malicious URL to Git (e.g., through a
|
|
||||||
submodule) can cause it to make unexpected cross-protocol requests.
|
|
||||||
Since repository names with newlines are presumably quite rare (and
|
|
||||||
indeed, we already disallow them in git-over-http), let's just disallow
|
|
||||||
them over this protocol.
|
|
||||||
|
|
||||||
Hostnames could likewise inject a newline, but this is unlikely a
|
|
||||||
problem in practice; we'd try resolving the hostname with a newline in
|
|
||||||
it, which wouldn't work. Still, it doesn't hurt to err on the side of
|
|
||||||
caution there, since we would not expect them to work in the first
|
|
||||||
place.
|
|
||||||
|
|
||||||
The ssh and local code paths are unaffected by this patch. In both cases
|
|
||||||
we're trying to run upload-pack via a shell, and will quote the newline
|
|
||||||
so that it makes it intact. An attacker can point an ssh url at an
|
|
||||||
arbitrary port, of course, but unless there's an actual ssh server
|
|
||||||
there, we'd never get as far as sending our shell command anyway. We
|
|
||||||
_could_ similarly restrict newlines in those protocols out of caution,
|
|
||||||
but there seems little benefit to doing so.
|
|
||||||
|
|
||||||
The new test here is run alongside the git-daemon tests, which cover the
|
|
||||||
same protocol, but it shouldn't actually contact the daemon at all. In
|
|
||||||
theory we could make the test more robust by setting up an actual
|
|
||||||
repository with a newline in it (so that our clone would succeed if our
|
|
||||||
new check didn't kick in). But a repo directory with newline in it is
|
|
||||||
likely not portable across all filesystems. Likewise, we could check
|
|
||||||
git-daemon's log that it was not contacted at all, but we do not
|
|
||||||
currently record the log (and anyway, it would make the test racy with
|
|
||||||
the daemon's log write). We'll just check the client-side stderr to make
|
|
||||||
sure we hit the expected code path.
|
|
||||||
|
|
||||||
Reported-by: Harold Kim <h.kim@flatt.tech>
|
|
||||||
Signed-off-by: Jeff King <peff@peff.net>
|
|
||||||
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
|
||||||
---
|
|
||||||
connect.c | 2 ++
|
|
||||||
t/t5570-git-daemon.sh | 5 +++++
|
|
||||||
2 files changed, 7 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/connect.c b/connect.c
|
|
||||||
index 79f1b3b24257a1..7b4b65751d43d4 100644
|
|
||||||
--- a/connect.c
|
|
||||||
+++ b/connect.c
|
|
||||||
@@ -1063,6 +1063,8 @@ static struct child_process *git_connect_git(int fd[2], char *hostandport,
|
|
||||||
target_host = xstrdup(hostandport);
|
|
||||||
|
|
||||||
transport_check_allowed("git");
|
|
||||||
+ if (strchr(target_host, '\n') || strchr(path, '\n'))
|
|
||||||
+ die(_("newline is forbidden in git:// hosts and repo paths"));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These underlying connection commands die() if they
|
|
||||||
diff --git a/t/t5570-git-daemon.sh b/t/t5570-git-daemon.sh
|
|
||||||
index 7466aad111fe4e..336d417a90f871 100755
|
|
||||||
--- a/t/t5570-git-daemon.sh
|
|
||||||
+++ b/t/t5570-git-daemon.sh
|
|
||||||
@@ -102,6 +102,11 @@ test_expect_success 'fetch notices corrupt idx' '
|
|
||||||
)
|
|
||||||
'
|
|
||||||
|
|
||||||
+test_expect_success 'client refuses to ask for repo with newline' '
|
|
||||||
+ test_must_fail git clone "$GIT_DAEMON_URL/repo$LF.git" dst 2>stderr &&
|
|
||||||
+ test_i18ngrep newline.is.forbidden stderr
|
|
||||||
+'
|
|
||||||
+
|
|
||||||
test_remote_error()
|
|
||||||
{
|
|
||||||
do_export=YesPlease
|
|
||||||
--
|
|
||||||
2.27.0
|
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
BIN
git-2.33.0.tar.sign
Normal file
BIN
git-2.33.0.tar.sign
Normal file
Binary file not shown.
BIN
git-2.33.0.tar.xz
Normal file
BIN
git-2.33.0.tar.xz
Normal file
Binary file not shown.
21
git.spec
21
git.spec
@ -1,7 +1,7 @@
|
|||||||
%global gitexecdir %{_libexecdir}/git-core
|
%global gitexecdir %{_libexecdir}/git-core
|
||||||
Name: git
|
Name: git
|
||||||
Version: 2.30.0
|
Version: 2.33.0
|
||||||
Release: 6
|
Release: 1
|
||||||
Summary: A popular and widely used Version Control System
|
Summary: A popular and widely used Version Control System
|
||||||
License: GPLv2+ or LGPLv2.1
|
License: GPLv2+ or LGPLv2.1
|
||||||
URL: https://git-scm.com/
|
URL: https://git-scm.com/
|
||||||
@ -12,10 +12,6 @@ Source100: git-gui.desktop
|
|||||||
Source101: git@.service.in
|
Source101: git@.service.in
|
||||||
Source102: git.socket
|
Source102: git.socket
|
||||||
|
|
||||||
Patch1: backport-CVE-2021-21300.patch
|
|
||||||
Patch2: backport-CVE-2021-29468-cygwin-disallow-backslashes-in-file-names.patch
|
|
||||||
Patch3: backport-CVE-2021-40330.patch
|
|
||||||
|
|
||||||
BuildRequires: gcc gettext
|
BuildRequires: gcc gettext
|
||||||
BuildRequires: openssl-devel libcurl-devel expat-devel systemd asciidoc xmlto glib2-devel libsecret-devel pcre-devel desktop-file-utils
|
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)
|
BuildRequires: python3-devel perl-generators perl-interpreter perl-Error perl(Test::More) perl-MailTools perl(Test)
|
||||||
@ -138,10 +134,8 @@ NO_PERL_CPAN_FALLBACKS = 1
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Default using python3
|
# Default using python3
|
||||||
sed -i '1s@#![ ]*/usr/bin/env python@#!%{__python3}@' \
|
sed -i -e '1s@#!\( */usr/bin/env python\|%{__python2}\)$@#!%{__python3}@' \
|
||||||
contrib/hooks/multimail/git_multimail.py \
|
contrib/hg-to-git/hg-to-git.py
|
||||||
contrib/hooks/multimail/migrate-mailhook-config \
|
|
||||||
contrib/hooks/multimail/post-receive.example
|
|
||||||
|
|
||||||
%make_build
|
%make_build
|
||||||
%make_build -C contrib/subtree/
|
%make_build -C contrib/subtree/
|
||||||
@ -165,11 +159,7 @@ ln -s git %{buildroot}%{_datadir}/bash-completion/completions/gitk
|
|||||||
|
|
||||||
# install contrib to git-core
|
# install contrib to git-core
|
||||||
mkdir -p %{buildroot}%{_datadir}/git-core/contrib/completion
|
mkdir -p %{buildroot}%{_datadir}/git-core/contrib/completion
|
||||||
mv contrib/hooks/multimail/git_multimail{.py,}
|
|
||||||
mv contrib/hooks %{buildroot}%{_datadir}/git-core/contrib
|
|
||||||
install -p -m 644 contrib/completion/git-completion.tcsh %{buildroot}%{_datadir}/git-core/contrib/completion/
|
install -p -m 644 contrib/completion/git-completion.tcsh %{buildroot}%{_datadir}/git-core/contrib/completion/
|
||||||
install -p -m 644 contrib/completion/git-prompt.sh %{buildroot}%{_datadir}/git-core/contrib/completion/
|
|
||||||
install -D -p -m 0755 contrib/diff-highlight/diff-highlight %{buildroot}%{_datadir}/git-core/contrib/diff-highlight
|
|
||||||
|
|
||||||
# install root path for gitweb
|
# install root path for gitweb
|
||||||
mkdir -p %{buildroot}%{_localstatedir}/lib/git
|
mkdir -p %{buildroot}%{_localstatedir}/lib/git
|
||||||
@ -264,6 +254,9 @@ make %{?_smp_mflags} test
|
|||||||
%{_mandir}/man7/git*.7.*
|
%{_mandir}/man7/git*.7.*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Dec 30 2021 zoulin<zoulin13@huawei.com> - 2.33.0-1
|
||||||
|
- update version to 2.33.0
|
||||||
|
|
||||||
* Fri Sep 10 2021 fuanan <fuanan3@huawei.com> - 2.30.0-6
|
* Fri Sep 10 2021 fuanan <fuanan3@huawei.com> - 2.30.0-6
|
||||||
- Type:CVE
|
- Type:CVE
|
||||||
- ID:CVE-2021-40330
|
- ID:CVE-2021-40330
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user