summary refs log tree commit diff
diff options
context:
space:
mode:
authorJiang Xin <worldhello.net@gmail.com>2022-04-13 14:51:53 +0800
committerJiang Xin <worldhello.net@gmail.com>2022-04-13 14:51:53 +0800
commit61de00a32115b6090891f20797fdfd1501709ab9 (patch)
treee6a0290cef9e52589a8b78e55dbae3daf559e202
parentdfbdf52df590cf8af37b193d9bf9f9a41162f3ae (diff)
parent11cfe552610386954886543f5de87dcc49ad5735 (diff)
Merge branch 'master' of github.com:git/git
* 'master' of github.com:git/git: (25 commits)
  Git 2.36-rc2
  i18n: fix some badly formatted i18n strings
  Git 2.36-rc1
  t9902: split test to run on appropriate systems
  ls-tree doc: document interaction with submodules
  Documentation: add --batch-command to cat-file synopsis
  git-ls-tree.txt: fix the name of "%(objectsize:padded)"
  submodule-helper: fix usage string
  doc: replace "--" with {litdd} in credential-cache/fsmonitor
  contrib/scalar: fix 'all' target in Makefile
  Documentation/Makefile: fix "make info" regression in dad9cd7d518
  configure.ac: fix HAVE_SYNC_FILE_RANGE definition
  git-compat-util: really support openssl as a source of entropy
  ls-tree: `-l` should not imply recursive listing
  Git 2.35.2
  Git 2.34.2
  Git 2.33.2
  Git 2.32.1
  Git 2.31.2
  Git 2.30.3
  ...
-rw-r--r--Documentation/Makefile2
-rw-r--r--Documentation/RelNotes/2.30.3.txt24
-rw-r--r--Documentation/RelNotes/2.31.2.txt6
-rw-r--r--Documentation/RelNotes/2.32.1.txt6
-rw-r--r--Documentation/RelNotes/2.33.2.txt15
-rw-r--r--Documentation/RelNotes/2.34.2.txt6
-rw-r--r--Documentation/RelNotes/2.35.2.txt7
-rw-r--r--Documentation/RelNotes/2.36.0.txt2
-rw-r--r--Documentation/config.txt2
-rw-r--r--Documentation/config/core.txt2
-rw-r--r--Documentation/config/safe.txt21
-rw-r--r--Documentation/git-cat-file.txt2
-rw-r--r--Documentation/git-credential-cache--daemon.txt6
-rw-r--r--Documentation/git-fsmonitor--daemon.txt12
-rw-r--r--Documentation/git-ls-tree.txt6
-rw-r--r--Documentation/git-update-index.txt2
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile1
-rw-r--r--builtin/ls-tree.c2
-rw-r--r--builtin/submodule--helper.c4
-rw-r--r--compat/mingw.c87
-rw-r--r--compat/mingw.h7
-rw-r--r--configure.ac2
-rw-r--r--contrib/scalar/Makefile2
-rw-r--r--git-compat-util.h16
-rwxr-xr-xgit-send-email.perl7
-rw-r--r--imap-send.c2
-rw-r--r--path.c14
-rw-r--r--setup.c57
-rwxr-xr-xt/t0060-path-utils.sh20
-rwxr-xr-xt/t9902-completion.sh35
31 files changed, 331 insertions, 48 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 1eb9192dae..44c080e3e5 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -390,7 +390,7 @@ gitman.texi: $(MAN_XML) cat-texi.perl texi.xsl
 	$(RM) $@+
 
 gitman.info: gitman.texi
-	$(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
+	$(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $<
 
 $(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
 	$(QUIET_DB2TEXI)$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@
diff --git a/Documentation/RelNotes/2.30.3.txt b/Documentation/RelNotes/2.30.3.txt
new file mode 100644
index 0000000000..31b2a4daa6
--- /dev/null
+++ b/Documentation/RelNotes/2.30.3.txt
@@ -0,0 +1,24 @@
+Git v2.30.2 Release Notes
+=========================
+
+This release addresses the security issue CVE-2022-24765.
+
+Fixes since v2.30.2
+-------------------
+
+ * Build fix on Windows.
+
+ * Fix `GIT_CEILING_DIRECTORIES` with Windows-style root directories.
+
+ * CVE-2022-24765:
+   On multi-user machines, Git users might find themselves
+   unexpectedly in a Git worktree, e.g. when another user created a
+   repository in `C:\.git`, in a mounted network drive or in a
+   scratch space. Merely having a Git-aware prompt that runs `git
+   status` (or `git diff`) and navigating to a directory which is
+   supposedly not a Git worktree, or opening such a directory in an
+   editor or IDE such as VS Code or Atom, will potentially run
+   commands defined by that other user.
+
+Credit for finding this vulnerability goes to 俞晨东; The fix was
+authored by Johannes Schindelin.
diff --git a/Documentation/RelNotes/2.31.2.txt b/Documentation/RelNotes/2.31.2.txt
new file mode 100644
index 0000000000..aa13a5b022
--- /dev/null
+++ b/Documentation/RelNotes/2.31.2.txt
@@ -0,0 +1,6 @@
+Git v2.31.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3 to address
+the security issue CVE-2022-24765; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.32.1.txt b/Documentation/RelNotes/2.32.1.txt
new file mode 100644
index 0000000000..7dcca13b92
--- /dev/null
+++ b/Documentation/RelNotes/2.32.1.txt
@@ -0,0 +1,6 @@
+Git v2.32.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3 and
+v2.31.2 to address the security issue CVE-2022-24765; see the
+release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.33.2.txt b/Documentation/RelNotes/2.33.2.txt
new file mode 100644
index 0000000000..e504489d61
--- /dev/null
+++ b/Documentation/RelNotes/2.33.2.txt
@@ -0,0 +1,15 @@
+Git v2.33.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3, v2.31.2
+and v2.32.1 to address the security issue CVE-2022-24765; see
+the release notes for these versions for details.
+
+In addition, it contains the following fixes:
+
+ * Squelch over-eager warning message added during this cycle.
+
+ * A bug in "git rebase -r" has been fixed.
+
+ * One CI task based on Fedora image noticed a not-quite-kosher
+   construct recently, which has been corrected.
diff --git a/Documentation/RelNotes/2.34.2.txt b/Documentation/RelNotes/2.34.2.txt
new file mode 100644
index 0000000000..0c32cd844b
--- /dev/null
+++ b/Documentation/RelNotes/2.34.2.txt
@@ -0,0 +1,6 @@
+Git v2.34.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3, v2.31.2,
+v2.32.1 and v2.33.2 to address the security issue CVE-2022-24765;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.35.2.txt b/Documentation/RelNotes/2.35.2.txt
new file mode 100644
index 0000000000..290bfa9ea4
--- /dev/null
+++ b/Documentation/RelNotes/2.35.2.txt
@@ -0,0 +1,7 @@
+Git v2.35.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3,
+v2.31.2, v2.32.1, v2.33.2 and v2.34.2 to address the security
+issue CVE-2022-24765; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.36.0.txt b/Documentation/RelNotes/2.36.0.txt
index 8da5b2e1e7..d61ade21e2 100644
--- a/Documentation/RelNotes/2.36.0.txt
+++ b/Documentation/RelNotes/2.36.0.txt
@@ -397,6 +397,8 @@ Fixes since v2.35
    entry it moved.
    (merge b7f9130a06 vd/mv-refresh-stat later to maint).
 
+ * Fix for CVE-2022-24765 has been merged up from 2.35.2 and others.
+
  * Other code cleanup, docfix, build fix, etc.
    (merge cfc5cf428b jc/find-header later to maint).
    (merge 40e7cfdd46 jh/p4-fix-use-of-process-error-exception later to maint).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 43f5e6fd6d..e284b042f2 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -495,6 +495,8 @@ include::config/repack.txt[]
 
 include::config/rerere.txt[]
 
+include::config/safe.txt[]
+
 include::config/sendemail.txt[]
 
 include::config/sequencer.txt[]
diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index 889522956e..e67392cc83 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -63,7 +63,7 @@ core.protectNTFS::
 
 core.fsmonitor::
 	If set to true, enable the built-in file system monitor
-	daemon for this working directory (linkgit:git-fsmonitor--daemon[1]).
+	daemon for this working directory (linkgit:git-fsmonitor{litdd}daemon[1]).
 +
 Like hook-based file system monitors, the built-in file system monitor
 can speed up Git commands that need to refresh the Git index
diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt
new file mode 100644
index 0000000000..63597b2df8
--- /dev/null
+++ b/Documentation/config/safe.txt
@@ -0,0 +1,21 @@
+safe.directory::
+	These config entries specify Git-tracked directories that are
+	considered safe even if they are owned by someone other than the
+	current user. By default, Git will refuse to even parse a Git
+	config of a repository owned by someone else, let alone run its
+	hooks, and this config setting allows users to specify exceptions,
+	e.g. for intentionally shared repositories (see the `--shared`
+	option in linkgit:git-init[1]).
++
+This is a multi-valued setting, i.e. you can add more than one directory
+via `git config --add`. To reset the list of safe directories (e.g. to
+override any such directories specified in the system config), add a
+`safe.directory` entry with an empty value.
++
+This config setting is only respected when specified in a system or global
+config, not when it is specified in a repository config or via the command
+line option `-c safe.directory=<path>`.
++
+The value of this setting is interpolated, i.e. `~/<path>` expands to a
+path relative to the home directory and `%(prefix)/<path>` expands to a
+path relative to Git's (runtime) prefix.
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 70c5b4f12d..24a811f0ef 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -12,7 +12,7 @@ SYNOPSIS
 'git cat-file' <type> <object>
 'git cat-file' (-e | -p) <object>
 'git cat-file' (-t | -s) [--allow-unknown-type] <object>
-'git cat-file' (--batch | --batch-check) [--batch-all-objects]
+'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
 	     [--buffer] [--follow-symlinks] [--unordered]
 	     [--textconv | --filters]
 'git cat-file' (--textconv | --filters)
diff --git a/Documentation/git-credential-cache--daemon.txt b/Documentation/git-credential-cache--daemon.txt
index 7051c6bdf8..01e1c214dd 100644
--- a/Documentation/git-credential-cache--daemon.txt
+++ b/Documentation/git-credential-cache--daemon.txt
@@ -1,5 +1,5 @@
-git-credential-cache--daemon(1)
-===============================
+git-credential-cache{litdd}daemon(1)
+====================================
 
 NAME
 ----
@@ -8,7 +8,7 @@ git-credential-cache--daemon - Temporarily store user credentials in memory
 SYNOPSIS
 --------
 [verse]
-git credential-cache--daemon [--debug] <socket>
+'git credential-cache{litdd}daemon' [--debug] <socket>
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt
index 0fedf5a456..cc142fb861 100644
--- a/Documentation/git-fsmonitor--daemon.txt
+++ b/Documentation/git-fsmonitor--daemon.txt
@@ -1,5 +1,5 @@
-git-fsmonitor--daemon(1)
-========================
+git-fsmonitor{litdd}daemon(1)
+=============================
 
 NAME
 ----
@@ -8,10 +8,10 @@ git-fsmonitor--daemon - A Built-in File System Monitor
 SYNOPSIS
 --------
 [verse]
-'git fsmonitor--daemon' start
-'git fsmonitor--daemon' run
-'git fsmonitor--daemon' stop
-'git fsmonitor--daemon' status
+'git fsmonitor{litdd}daemon' start
+'git fsmonitor{litdd}daemon' run
+'git fsmonitor{litdd}daemon' stop
+'git fsmonitor{litdd}daemon' status
 
 DESCRIPTION
 -----------
diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt
index 43aebb9938..0240adb8ee 100644
--- a/Documentation/git-ls-tree.txt
+++ b/Documentation/git-ls-tree.txt
@@ -151,12 +151,12 @@ names can be used:
 objectmode::
 	The mode of the object.
 objecttype::
-	The type of the object (`blob` or `tree`).
+	The type of the object (`commit`, `blob` or `tree`).
 objectname::
 	The name of the object.
 objectsize[:padded]::
-	The size of the object ("-" if it's a tree).
-	It also supports a padded format of size with "%(size:padded)".
+	The size of a `blob` object ("-" if it's a `commit` or `tree`).
+	It also supports a padded format of size with "%(objectsize:padded)".
 path::
 	The pathname of the object.
 
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 64315e2e8c..5ea2f2c60e 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -528,7 +528,7 @@ This feature is intended to speed up git operations for repos that have
 large working directories.
 
 It enables git to work together with a file system monitor (see
-linkgit:git-fsmonitor--daemon[1]
+linkgit:git-fsmonitor{litdd}daemon[1]
 and the
 "fsmonitor-watchman" section of linkgit:githooks[5]) that can
 inform it as to what files have been modified. This enables git to avoid
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index d92e7d4398..9252e0430d 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.36.0-rc0
+DEF_VER=v2.36.0-rc2
 
 LF='
 '
diff --git a/Makefile b/Makefile
index 9173848562..f8bccfab5e 100644
--- a/Makefile
+++ b/Makefile
@@ -1972,6 +1972,7 @@ endif
 
 ifneq ($(findstring openssl,$(CSPRNG_METHOD)),)
 	BASIC_CFLAGS += -DHAVE_OPENSSL_CSPRNG
+	EXTLIBS += -lcrypto -lssl
 endif
 
 ifneq ($(PROCFS_EXECUTABLE_PATH),)
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index 5dac9ee5b9..e279be8bb6 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -255,7 +255,7 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
 	printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
 	       find_unique_abbrev(data.oid, abbrev), size_text);
 	show_tree_common_default_long(base, pathname, data.base->len);
-	return 1;
+	return recurse;
 }
 
 static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c3e0d4570f..2c87ef9364 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1902,7 +1902,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
 	const char *const git_submodule_helper_usage[] = {
 		N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
 		   "[--reference <repository>] [--name <name>] [--depth <depth>] "
-		   "[--single-branch] [--filter <filter-spec>]"
+		   "[--single-branch] [--filter <filter-spec>] "
 		   "--url <url> --path <path>"),
 		NULL
 	};
@@ -3082,7 +3082,7 @@ static int module_create_branch(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 	const char *const usage[] = {
-		N_("git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--quiet] [-t|--track] [-n|--dry-run] <name> <start_oid> <start_name>"),
+		N_("git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"),
 		NULL
 	};
 
diff --git a/compat/mingw.c b/compat/mingw.c
index 58f347d6ae..6fe80fdf01 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,5 +1,6 @@
 #include "../git-compat-util.h"
 #include "win32.h"
+#include <aclapi.h>
 #include <conio.h>
 #include <wchar.h>
 #include "../strbuf.h"
@@ -2645,6 +2646,92 @@ static void setup_windows_environment(void)
 	}
 }
 
+static PSID get_current_user_sid(void)
+{
+	HANDLE token;
+	DWORD len = 0;
+	PSID result = NULL;
+
+	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
+		return NULL;
+
+	if (!GetTokenInformation(token, TokenUser, NULL, 0, &len)) {
+		TOKEN_USER *info = xmalloc((size_t)len);
+		if (GetTokenInformation(token, TokenUser, info, len, &len)) {
+			len = GetLengthSid(info->User.Sid);
+			result = xmalloc(len);
+			if (!CopySid(len, result, info->User.Sid)) {
+				error(_("failed to copy SID (%ld)"),
+				      GetLastError());
+				FREE_AND_NULL(result);
+			}
+		}
+		FREE_AND_NULL(info);
+	}
+	CloseHandle(token);
+
+	return result;
+}
+
+int is_path_owned_by_current_sid(const char *path)
+{
+	WCHAR wpath[MAX_PATH];
+	PSID sid = NULL;
+	PSECURITY_DESCRIPTOR descriptor = NULL;
+	DWORD err;
+
+	static wchar_t home[MAX_PATH];
+
+	int result = 0;
+
+	if (xutftowcs_path(wpath, path) < 0)
+		return 0;
+
+	/*
+	 * On Windows, the home directory is owned by the administrator, but for
+	 * all practical purposes, it belongs to the user. Do pretend that it is
+	 * owned by the user.
+	 */
+	if (!*home) {
+		DWORD size = ARRAY_SIZE(home);
+		DWORD len = GetEnvironmentVariableW(L"HOME", home, size);
+		if (!len || len > size)
+			wcscpy(home, L"::N/A::");
+	}
+	if (!wcsicmp(wpath, home))
+		return 1;
+
+	/* Get the owner SID */
+	err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT,
+				    OWNER_SECURITY_INFORMATION |
+				    DACL_SECURITY_INFORMATION,
+				    &sid, NULL, NULL, NULL, &descriptor);
+
+	if (err != ERROR_SUCCESS)
+		error(_("failed to get owner for '%s' (%ld)"), path, err);
+	else if (sid && IsValidSid(sid)) {
+		/* Now, verify that the SID matches the current user's */
+		static PSID current_user_sid;
+
+		if (!current_user_sid)
+			current_user_sid = get_current_user_sid();
+
+		if (current_user_sid &&
+		    IsValidSid(current_user_sid) &&
+		    EqualSid(sid, current_user_sid))
+			result = 1;
+	}
+
+	/*
+	 * We can release the security descriptor struct only now because `sid`
+	 * actually points into this struct.
+	 */
+	if (descriptor)
+		LocalFree(descriptor);
+
+	return result;
+}
+
 int is_valid_win32_path(const char *path, int allow_literal_nul)
 {
 	const char *p = path;
diff --git a/compat/mingw.h b/compat/mingw.h
index 6074a3d3ce..494cc8de92 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -457,6 +457,13 @@ char *mingw_query_user_email(void);
 #endif
 
 /**
+ * Verifies that the specified path is owned by the user running the
+ * current process.
+ */
+int is_path_owned_by_current_sid(const char *path);
+#define is_path_owned_by_current_user is_path_owned_by_current_sid
+
+/**
  * Verifies that the given path is a valid one on Windows.
  *
  * In particular, path segments are disallowed which
diff --git a/configure.ac b/configure.ac
index 6bd6bef1c4..316a31d231 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1087,7 +1087,7 @@ GIT_CONF_SUBST([HAVE_CLOCK_MONOTONIC])
 # Define HAVE_SYNC_FILE_RANGE=YesPlease if sync_file_range is available.
 GIT_CHECK_FUNC(sync_file_range,
 	[HAVE_SYNC_FILE_RANGE=YesPlease],
-	[HAVE_SYNC_FILE_RANGE])
+	[HAVE_SYNC_FILE_RANGE=])
 GIT_CONF_SUBST([HAVE_SYNC_FILE_RANGE])
 
 #
diff --git a/contrib/scalar/Makefile b/contrib/scalar/Makefile
index 5e86d78e19..37f283f35d 100644
--- a/contrib/scalar/Makefile
+++ b/contrib/scalar/Makefile
@@ -11,7 +11,7 @@ include ../../config.mak.uname
 TARGETS = scalar$(X) scalar.o
 GITLIBS = ../../common-main.o ../../libgit.a ../../xdiff/lib.a
 
-all: scalar$(X) ../../bin-wrappers/scalar
+all:: scalar$(X) ../../bin-wrappers/scalar
 
 $(GITLIBS):
 	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) $(subst ../../,,$@)
diff --git a/git-compat-util.h b/git-compat-util.h
index 4d444dca27..58fd813bd0 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -436,6 +436,18 @@ static inline int git_offset_1st_component(const char *path)
 #define is_valid_path(path) 1
 #endif
 
+#ifndef is_path_owned_by_current_user
+static inline int is_path_owned_by_current_uid(const char *path)
+{
+	struct stat st;
+	if (lstat(path, &st))
+		return 0;
+	return st.st_uid == geteuid();
+}
+
+#define is_path_owned_by_current_user is_path_owned_by_current_uid
+#endif
+
 #ifndef find_last_dir_sep
 static inline char *git_find_last_dir_sep(const char *path)
 {
@@ -525,6 +537,10 @@ void warning_errno(const char *err, ...) __attribute__((format (printf, 1, 2)));
 #include <openssl/x509v3.h>
 #endif /* NO_OPENSSL */
 
+#ifdef HAVE_OPENSSL_CSPRNG
+#include <openssl/rand.h>
+#endif
+
 /*
  * Let callers be aware of the constant return value; this can help
  * gcc with -Wuninitialized analysis. We restrict this trick to gcc, though,
diff --git a/git-send-email.perl b/git-send-email.perl
index a98460bdb9..5861e99a6e 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -2096,10 +2096,9 @@ sub validate_patch {
 			chdir($cwd_save) or die("chdir: $!");
 		}
 		if ($hook_error) {
-			$hook_error = sprintf(__("fatal: %s: rejected by %s hook\n" .
-						 $hook_error . "\n" .
-						 "warning: no patches were sent\n"),
-					      $fn, $hook_name);
+			$hook_error = sprintf(
+			    __("fatal: %s: rejected by %s hook\n%s\nwarning: no patches were sent\n"),
+			    $fn, $hook_name, $hook_error);
 			die $hook_error;
 		}
 	}
diff --git a/imap-send.c b/imap-send.c
index 5ac6fa9c66..a50af56b82 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -27,7 +27,7 @@
 #include "exec-cmd.h"
 #include "run-command.h"
 #include "parse-options.h"
-#ifdef NO_OPENSSL
+#if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG)
 typedef void *SSL;
 #endif
 #ifdef USE_CURL_FOR_IMAP_SEND
diff --git a/path.c b/path.c
index 2c895471d9..d73146b6cd 100644
--- a/path.c
+++ b/path.c
@@ -1225,11 +1225,15 @@ int longest_ancestor_length(const char *path, struct string_list *prefixes)
 		const char *ceil = prefixes->items[i].string;
 		int len = strlen(ceil);
 
-		if (len == 1 && ceil[0] == '/')
-			len = 0; /* root matches anything, with length 0 */
-		else if (!strncmp(path, ceil, len) && path[len] == '/')
-			; /* match of length len */
-		else
+		/*
+		 * For root directories (`/`, `C:/`, `//server/share/`)
+		 * adjust the length to exclude the trailing slash.
+		 */
+		if (len > 0 && ceil[len - 1] == '/')
+			len--;
+
+		if (strncmp(path, ceil, len) ||
+		    path[len] != '/' || !path[len + 1])
 			continue; /* no match */
 
 		if (len > max_len)
diff --git a/setup.c b/setup.c
index 04ce33cdcd..c8f67bfed5 100644
--- a/setup.c
+++ b/setup.c
@@ -5,6 +5,7 @@
 #include "string-list.h"
 #include "chdir-notify.h"
 #include "promisor-remote.h"
+#include "quote.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -1090,6 +1091,42 @@ static int canonicalize_ceiling_entry(struct string_list_item *item,
 	}
 }
 
+struct safe_directory_data {
+	const char *path;
+	int is_safe;
+};
+
+static int safe_directory_cb(const char *key, const char *value, void *d)
+{
+	struct safe_directory_data *data = d;
+
+	if (!value || !*value)
+		data->is_safe = 0;
+	else {
+		const char *interpolated = NULL;
+
+		if (!git_config_pathname(&interpolated, key, value) &&
+		    !fspathcmp(data->path, interpolated ? interpolated : value))
+			data->is_safe = 1;
+
+		free((char *)interpolated);
+	}
+
+	return 0;
+}
+
+static int ensure_valid_ownership(const char *path)
+{
+	struct safe_directory_data data = { .path = path };
+
+	if (is_path_owned_by_current_user(path))
+		return 1;
+
+	read_very_early_config(safe_directory_cb, &data);
+
+	return data.is_safe;
+}
+
 enum discovery_result {
 	GIT_DIR_NONE = 0,
 	GIT_DIR_EXPLICIT,
@@ -1098,7 +1135,8 @@ enum discovery_result {
 	/* these are errors */
 	GIT_DIR_HIT_CEILING = -1,
 	GIT_DIR_HIT_MOUNT_POINT = -2,
-	GIT_DIR_INVALID_GITFILE = -3
+	GIT_DIR_INVALID_GITFILE = -3,
+	GIT_DIR_INVALID_OWNERSHIP = -4
 };
 
 /*
@@ -1188,11 +1226,15 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
 		}
 		strbuf_setlen(dir, offset);
 		if (gitdirenv) {
+			if (!ensure_valid_ownership(dir->buf))
+				return GIT_DIR_INVALID_OWNERSHIP;
 			strbuf_addstr(gitdir, gitdirenv);
 			return GIT_DIR_DISCOVERED;
 		}
 
 		if (is_git_directory(dir->buf)) {
+			if (!ensure_valid_ownership(dir->buf))
+				return GIT_DIR_INVALID_OWNERSHIP;
 			strbuf_addstr(gitdir, ".");
 			return GIT_DIR_BARE;
 		}
@@ -1324,6 +1366,19 @@ const char *setup_git_directory_gently(int *nongit_ok)
 			    dir.buf);
 		*nongit_ok = 1;
 		break;
+	case GIT_DIR_INVALID_OWNERSHIP:
+		if (!nongit_ok) {
+			struct strbuf quoted = STRBUF_INIT;
+
+			sq_quote_buf_pretty(&quoted, dir.buf);
+			die(_("unsafe repository ('%s' is owned by someone else)\n"
+			      "To add an exception for this directory, call:\n"
+			      "\n"
+			      "\tgit config --global --add safe.directory %s"),
+			    dir.buf, quoted.buf);
+		}
+		*nongit_ok = 1;
+		break;
 	case GIT_DIR_NONE:
 		/*
 		 * As a safeguard against setup_git_directory_gently_1 returning
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 71a5d370cc..2fe6ae6a4e 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -55,12 +55,15 @@ fi
 ancestor() {
 	# We do some math with the expected ancestor length.
 	expected=$3
-	if test -n "$rootoff" && test "x$expected" != x-1; then
-		expected=$(($expected-$rootslash))
-		test $expected -lt 0 ||
-		expected=$(($expected+$rootoff))
-	fi
-	test_expect_success "longest ancestor: $1 $2 => $expected" \
+	case "$rootoff,$expected,$2" in
+	*,*,//*) ;; # leave UNC paths alone
+	[0-9]*,[0-9]*,/*)
+		# On Windows, expect MSYS2 pseudo root translation for
+		# Unix-style absolute paths
+		expected=$(($expected-$rootslash+$rootoff))
+		;;
+	esac
+	test_expect_success $4 "longest ancestor: $1 $2 => $expected" \
 	"actual=\$(test-tool path-utils longest_ancestor_length '$1' '$2') &&
 	 test \"\$actual\" = '$expected'"
 }
@@ -156,6 +159,11 @@ ancestor /foo/bar /foo 4
 ancestor /foo/bar /foo:/bar 4
 ancestor /foo/bar /bar -1
 
+# Windows-specific: DOS drives, network shares
+ancestor C:/Users/me C:/ 2 MINGW
+ancestor D:/Users/me C:/ -1 MINGW
+ancestor //server/share/my-directory //server/share/ 14 MINGW
+
 test_expect_success 'strip_path_suffix' '
 	test c:/msysgit = $(test-tool path-utils strip_path_suffix \
 		c:/msysgit/libexec//git-core libexec/git-core)
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 24117cb901..31526e6b64 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -1529,28 +1529,45 @@ test_expect_success 'cone mode sparse-checkout completes directory names with sp
 	)
 '
 
-# use FUNNYNAMES to avoid running on Windows, which doesn't permit backslashes or tabs in paths
-test_expect_success FUNNYNAMES 'cone mode sparse-checkout completes directory names with backslashes and tabs' '
+# use FUNNYNAMES to avoid running on Windows, which doesn't permit tabs in paths
+test_expect_success FUNNYNAMES 'cone mode sparse-checkout completes directory names with tabs' '
 	# reset sparse-checkout
 	git -C sparse-checkout sparse-checkout disable &&
 	(
 		cd sparse-checkout &&
-		mkdir "directory\with\backslashes" &&
 		mkdir "$(printf "directory\twith\ttabs")" &&
-		>"directory\with\backslashes/randomfile" &&
 		>"$(printf "directory\twith\ttabs")/randomfile" &&
 		git add . &&
-		git commit -m "Add directory with backslashes and directory with tabs" &&
-		git sparse-checkout set --cone "directory\with\backslashes" \
+		git commit -m "Add directory with tabs" &&
+		git sparse-checkout set --cone \
 			"$(printf "directory\twith\ttabs")" &&
 		test_completion "git sparse-checkout add dir" <<-\EOF &&
-		directory\with\backslashes/
 		directory	with	tabs/
 		EOF
-		rm -rf "directory\with\backslashes" &&
 		rm -rf "$(printf "directory\twith\ttabs")" &&
 		git add . &&
-		git commit -m "Remove directory with backslashes and directory with tabs"
+		git commit -m "Remove directory with tabs"
+	)
+'
+
+# use FUNNYNAMES to avoid running on Windows, and !CYGWIN for Cygwin, as neither permit backslashes in paths
+test_expect_success FUNNYNAMES,!CYGWIN 'cone mode sparse-checkout completes directory names with backslashes' '
+	# reset sparse-checkout
+	git -C sparse-checkout sparse-checkout disable &&
+	(
+		cd sparse-checkout &&
+		mkdir "directory\with\backslashes" &&
+		>"directory\with\backslashes/randomfile" &&
+		git add . &&
+		git commit -m "Add directory with backslashes" &&
+		git sparse-checkout set --cone \
+			"directory\with\backslashes" &&
+		test_completion "git sparse-checkout add dir" <<-\EOF &&
+		directory\with\backslashes/
+		EOF
+		rm -rf "directory\with\backslashes" &&
+		git add . &&
+		git commit -m "Remove directory with backslashes"
 	)
 '