Fix CVE-2022-24765
This commit is contained in:
parent
1900e1969c
commit
1101f7ebc7
118
backport-0001-CVE-2022-24765.patch
Normal file
118
backport-0001-CVE-2022-24765.patch
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
From fdcad5a53e14bd397e4fa323e7fd0c3bf16dd373 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Johannes Schindelin <johannes.schindelin@gmx.de>
|
||||||
|
Date: Wed, 23 Mar 2022 23:00:41 +0100
|
||||||
|
Subject: [PATCH] Fix `GIT_CEILING_DIRECTORIES` with `C:\` and the likes
|
||||||
|
|
||||||
|
When determining the length of the longest ancestor of a given path with
|
||||||
|
respect to to e.g. `GIT_CEILING_DIRECTORIES`, we special-case the root
|
||||||
|
directory by returning 0 (i.e. we pretend that the path `/` does not end
|
||||||
|
in a slash by virtually stripping it).
|
||||||
|
|
||||||
|
That is the correct behavior because when normalizing paths, the root
|
||||||
|
directory is special: all other directory paths have their trailing
|
||||||
|
slash stripped, but not the root directory's path (because it would
|
||||||
|
become the empty string, which is not a legal path).
|
||||||
|
|
||||||
|
However, this special-casing of the root directory in
|
||||||
|
`longest_ancestor_length()` completely forgets about Windows-style root
|
||||||
|
directories, e.g. `C:\`. These _also_ get normalized with a trailing
|
||||||
|
slash (because `C:` would actually refer to the current directory on
|
||||||
|
that drive, not necessarily to its root directory).
|
||||||
|
|
||||||
|
In fc56c7b34b (mingw: accomodate t0060-path-utils for MSYS2,
|
||||||
|
2016-01-27), we almost got it right. We noticed that
|
||||||
|
`longest_ancestor_length()` expects a slash _after_ the matched prefix,
|
||||||
|
and if the prefix already ends in a slash, the normalized path won't
|
||||||
|
ever match and -1 is returned.
|
||||||
|
|
||||||
|
But then that commit went astray: The correct fix is not to adjust the
|
||||||
|
_tests_ to expect an incorrect -1 when that function is fed a prefix
|
||||||
|
that ends in a slash, but instead to treat such a prefix as if the
|
||||||
|
trailing slash had been removed.
|
||||||
|
|
||||||
|
Likewise, that function needs to handle the case where it is fed a path
|
||||||
|
that ends in a slash (not only a prefix that ends in a slash): if it
|
||||||
|
matches the prefix (plus trailing slash), we still need to verify that
|
||||||
|
the path does not end there, otherwise the prefix is not actually an
|
||||||
|
ancestor of the path but identical to it (and we need to return -1 in
|
||||||
|
that case).
|
||||||
|
|
||||||
|
With these two adjustments, we no longer need to play games in t0060
|
||||||
|
where we only add `$rootoff` if the passed prefix is different from the
|
||||||
|
MSYS2 pseudo root, instead we also add it for the MSYS2 pseudo root
|
||||||
|
itself. We do have to be careful to skip that logic entirely for Windows
|
||||||
|
paths, though, because they do are not subject to that MSYS2 pseudo root
|
||||||
|
treatment.
|
||||||
|
|
||||||
|
This patch fixes the scenario where a user has set
|
||||||
|
`GIT_CEILING_DIRECTORIES=C:\`, which would be ignored otherwise.
|
||||||
|
|
||||||
|
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
|
||||||
|
---
|
||||||
|
path.c | 14 +++++++++-----
|
||||||
|
t/t0060-path-utils.sh | 20 ++++++++++++++------
|
||||||
|
2 files changed, 23 insertions(+), 11 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/path.c b/path.c
|
||||||
|
index 7b385e5eb28227..853e7165c89fd0 100644
|
||||||
|
--- a/path.c
|
||||||
|
+++ b/path.c
|
||||||
|
@@ -1218,11 +1218,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/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
|
||||||
|
index 56db5c8abab62e..f538264cdd3382 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)
|
||||||
187
backport-0002-CVE-2022-24765.patch
Normal file
187
backport-0002-CVE-2022-24765.patch
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
From 8959555cee7ec045958f9b6dd62e541affb7e7d9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Johannes Schindelin <johannes.schindelin@gmx.de>
|
||||||
|
Date: Wed, 2 Mar 2022 12:23:04 +0100
|
||||||
|
Subject: [PATCH] setup_git_directory(): add an owner check for the top-level
|
||||||
|
directory
|
||||||
|
|
||||||
|
It poses a security risk to search for a git directory outside of the
|
||||||
|
directories owned by the current user.
|
||||||
|
|
||||||
|
For example, it is common e.g. in computer pools of educational
|
||||||
|
institutes to have a "scratch" space: a mounted disk with plenty of
|
||||||
|
space that is regularly swiped where any authenticated user can create
|
||||||
|
a directory to do their work. Merely navigating to such a space with a
|
||||||
|
Git-enabled `PS1` when there is a maliciously-crafted `/scratch/.git/`
|
||||||
|
can lead to a compromised account.
|
||||||
|
|
||||||
|
The same holds true in multi-user setups running Windows, as `C:\` is
|
||||||
|
writable to every authenticated user by default.
|
||||||
|
|
||||||
|
To plug this vulnerability, we stop Git from accepting top-level
|
||||||
|
directories owned by someone other than the current user. We avoid
|
||||||
|
looking at the ownership of each and every directories between the
|
||||||
|
current and the top-level one (if there are any between) to avoid
|
||||||
|
introducing a performance bottleneck.
|
||||||
|
|
||||||
|
This new default behavior is obviously incompatible with the concept of
|
||||||
|
shared repositories, where we expect the top-level directory to be owned
|
||||||
|
by only one of its legitimate users. To re-enable that use case, we add
|
||||||
|
support for adding exceptions from the new default behavior via the
|
||||||
|
config setting `safe.directory`.
|
||||||
|
|
||||||
|
The `safe.directory` config setting is only respected in the system and
|
||||||
|
global configs, not from repository configs or via the command-line, and
|
||||||
|
can have multiple values to allow for multiple shared repositories.
|
||||||
|
|
||||||
|
We are particularly careful to provide a helpful message to any user
|
||||||
|
trying to use a shared repository.
|
||||||
|
|
||||||
|
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
|
||||||
|
---
|
||||||
|
Documentation/config.txt | 2 ++
|
||||||
|
Documentation/config/safe.txt | 21 +++++++++++++
|
||||||
|
setup.c | 57 ++++++++++++++++++++++++++++++++++-
|
||||||
|
3 files changed, 79 insertions(+), 1 deletion(-)
|
||||||
|
create mode 100644 Documentation/config/safe.txt
|
||||||
|
|
||||||
|
diff --git a/Documentation/config.txt b/Documentation/config.txt
|
||||||
|
index 6ba50b1104aa79..34e6d477d669f1 100644
|
||||||
|
--- a/Documentation/config.txt
|
||||||
|
+++ b/Documentation/config.txt
|
||||||
|
@@ -438,6 +438,8 @@ include::config/rerere.txt[]
|
||||||
|
|
||||||
|
include::config/reset.txt[]
|
||||||
|
|
||||||
|
+include::config/safe.txt[]
|
||||||
|
+
|
||||||
|
include::config/sendemail.txt[]
|
||||||
|
|
||||||
|
include::config/sequencer.txt[]
|
||||||
|
diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000000000..63597b2df8f80f
|
||||||
|
--- /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/setup.c b/setup.c
|
||||||
|
index c04cd25a30dfe0..95d5b00940a87e 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;
|
||||||
|
@@ -1024,6 +1025,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,
|
||||||
|
@@ -1032,7 +1069,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
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -1122,11 +1160,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;
|
||||||
|
}
|
||||||
|
@@ -1253,6 +1295,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("ed, 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
|
||||||
174
backport-0003-CVE-2022-24765.patch
Normal file
174
backport-0003-CVE-2022-24765.patch
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
From bdc77d1d685be9c10b88abb281a42bc620548595 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Johannes Schindelin <johannes.schindelin@gmx.de>
|
||||||
|
Date: Wed, 2 Mar 2022 11:06:24 +0100
|
||||||
|
Subject: [PATCH] Add a function to determine whether a path is owned by the
|
||||||
|
current user
|
||||||
|
|
||||||
|
This function will be used in the next commit to prevent
|
||||||
|
`setup_git_directory()` from discovering a repository in a directory
|
||||||
|
that is owned by someone other than the current user.
|
||||||
|
|
||||||
|
Note: We cannot simply use `st.st_uid` on Windows just like we do on
|
||||||
|
Linux and other Unix-like platforms: according to
|
||||||
|
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions
|
||||||
|
this field is always zero on Windows (because Windows' idea of a user ID
|
||||||
|
does not fit into a single numerical value). Therefore, we have to do
|
||||||
|
something a little involved to replicate the same functionality there.
|
||||||
|
|
||||||
|
Also note: On Windows, a user's home directory is not actually owned by
|
||||||
|
said user, but by the administrator. For all practical purposes, it is
|
||||||
|
under the user's control, though, therefore we pretend that it is owned
|
||||||
|
by the user.
|
||||||
|
|
||||||
|
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
|
||||||
|
---
|
||||||
|
compat/mingw.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
compat/mingw.h | 7 ++++
|
||||||
|
git-compat-util.h | 12 +++++++
|
||||||
|
3 files changed, 106 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/compat/mingw.c b/compat/mingw.c
|
||||||
|
index abb4d26ce940f3..38ac35913df78e 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"
|
||||||
|
@@ -2601,6 +2602,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 af8eddd73edb2b..f6bab548f4cf44 100644
|
||||||
|
--- a/compat/mingw.h
|
||||||
|
+++ b/compat/mingw.h
|
||||||
|
@@ -452,6 +452,13 @@ char *mingw_query_user_email(void);
|
||||||
|
#include <inttypes.h>
|
||||||
|
#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.
|
||||||
|
*
|
||||||
|
diff --git a/git-compat-util.h b/git-compat-util.h
|
||||||
|
index 3da9f975e27712..63ba89dd31d947 100644
|
||||||
|
--- a/git-compat-util.h
|
||||||
|
+++ b/git-compat-util.h
|
||||||
|
@@ -392,6 +392,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)
|
||||||
|
{
|
||||||
66
backport-0004-CVE-2022-24765.patch
Normal file
66
backport-0004-CVE-2022-24765.patch
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
From 6e7ad1e4c22e7038975ba37c7413374fe566b064 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= <carenas@gmail.com>
|
||||||
|
Date: Sat, 27 Nov 2021 10:15:32 +0000
|
||||||
|
Subject: [PATCH] mingw: avoid fallback for {local,gm}time_r()
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
mingw-w64's pthread_unistd.h had a bug that mistakenly (because there is
|
||||||
|
no support for the *lockfile() functions required[1]) defined
|
||||||
|
_POSIX_THREAD_SAFE_FUNCTIONS and that was being worked around since
|
||||||
|
3ecd153a3b (compat/mingw: support MSys2-based MinGW build, 2016-01-14).
|
||||||
|
|
||||||
|
The bug was fixed in winphtreads, but as a side effect, leaves the
|
||||||
|
reentrant functions from time.h no longer visible and therefore breaks
|
||||||
|
the build.
|
||||||
|
|
||||||
|
Since the intention all along was to avoid using the fallback functions,
|
||||||
|
formalize the use of POSIX by setting the corresponding feature flag and
|
||||||
|
compile out the implementation for the fallback functions.
|
||||||
|
|
||||||
|
[1] https://unix.org/whitepapers/reentrant.html
|
||||||
|
|
||||||
|
Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
|
||||||
|
Acked-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
|
||||||
|
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
||||||
|
---
|
||||||
|
compat/mingw.c | 2 ++
|
||||||
|
git-compat-util.h | 4 +++-
|
||||||
|
2 files changed, 5 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/compat/mingw.c b/compat/mingw.c
|
||||||
|
index a43599841c6c6b..abb4d26ce940f3 100644
|
||||||
|
--- a/compat/mingw.c
|
||||||
|
+++ b/compat/mingw.c
|
||||||
|
@@ -1060,6 +1060,7 @@ int pipe(int filedes[2])
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifndef __MINGW64__
|
||||||
|
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
||||||
|
{
|
||||||
|
if (gmtime_s(result, timep) == 0)
|
||||||
|
@@ -1073,6 +1074,7 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
|
||||||
|
return result;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
char *mingw_getcwd(char *pointer, int len)
|
||||||
|
{
|
||||||
|
diff --git a/git-compat-util.h b/git-compat-util.h
|
||||||
|
index 7d3db43f11d049..3da9f975e27712 100644
|
||||||
|
--- a/git-compat-util.h
|
||||||
|
+++ b/git-compat-util.h
|
||||||
|
@@ -127,7 +127,9 @@
|
||||||
|
/* Approximation of the length of the decimal representation of this type. */
|
||||||
|
#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
|
||||||
|
|
||||||
|
-#if defined(__sun__)
|
||||||
|
+#ifdef __MINGW64__
|
||||||
|
+#define _POSIX_C_SOURCE 1
|
||||||
|
+#elif defined(__sun__)
|
||||||
|
/*
|
||||||
|
* On Solaris, when _XOPEN_EXTENDED is set, its header file
|
||||||
|
* forces the programs to be XPG4v2, defeating any _XOPEN_SOURCE
|
||||||
48
backport-0005-CVE-2022-24765.patch
Normal file
48
backport-0005-CVE-2022-24765.patch
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
From bb50ec3cc300eeff3aba7a2bea145aabdb477d31 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Matheus Valadares <me@m28.io>
|
||||||
|
Date: Wed, 13 Apr 2022 15:32:30 +0000
|
||||||
|
Subject: [PATCH] setup: fix safe.directory key not being checked
|
||||||
|
|
||||||
|
It seems that nothing is ever checking to make sure the safe directories
|
||||||
|
in the configs actually have the key safe.directory, so some unrelated
|
||||||
|
config that has a value with a certain directory would also make it a
|
||||||
|
safe directory.
|
||||||
|
|
||||||
|
Signed-off-by: Matheus Valadares <me@m28.io>
|
||||||
|
Signed-off-by: Derrick Stolee <derrickstolee@github.com>
|
||||||
|
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
||||||
|
---
|
||||||
|
setup.c | 3 +++
|
||||||
|
t/t0033-safe-directory.sh | 5 +++++
|
||||||
|
2 files changed, 8 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/setup.c b/setup.c
|
||||||
|
index 3c6ed17af9566a..4b9f073617c2c6 100644
|
||||||
|
--- a/setup.c
|
||||||
|
+++ b/setup.c
|
||||||
|
@@ -1034,6 +1034,9 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
|
||||||
|
{
|
||||||
|
struct safe_directory_data *data = d;
|
||||||
|
|
||||||
|
+ if (strcmp(key, "safe.directory"))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
if (!value || !*value)
|
||||||
|
data->is_safe = 0;
|
||||||
|
else {
|
||||||
|
diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
|
||||||
|
index 9380ff3d017096..6f33c0dfefaaf3 100755
|
||||||
|
--- a/t/t0033-safe-directory.sh
|
||||||
|
+++ b/t/t0033-safe-directory.sh
|
||||||
|
@@ -21,6 +21,11 @@ test_expect_success 'safe.directory does not match' '
|
||||||
|
expect_rejected_dir
|
||||||
|
'
|
||||||
|
|
||||||
|
+test_expect_success 'path exist as different key' '
|
||||||
|
+ git config --global foo.bar "$(pwd)" &&
|
||||||
|
+ expect_rejected_dir
|
||||||
|
+'
|
||||||
|
+
|
||||||
|
test_expect_success 'safe.directory matches' '
|
||||||
|
git config --global --add safe.directory "$(pwd)" &&
|
||||||
|
git status
|
||||||
88
backport-0006-CVE-2022-24765.patch
Normal file
88
backport-0006-CVE-2022-24765.patch
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
From 0f85c4a30b072a26d74af8bbf63cc8f6a5dfc1b8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Derrick Stolee <derrickstolee@github.com>
|
||||||
|
Date: Wed, 13 Apr 2022 15:32:31 +0000
|
||||||
|
Subject: [PATCH] setup: opt-out of check with safe.directory=*
|
||||||
|
|
||||||
|
With the addition of the safe.directory in 8959555ce
|
||||||
|
(setup_git_directory(): add an owner check for the top-level directory,
|
||||||
|
2022-03-02) released in v2.35.2, we are receiving feedback from a
|
||||||
|
variety of users about the feature.
|
||||||
|
|
||||||
|
Some users have a very large list of shared repositories and find it
|
||||||
|
cumbersome to add this config for every one of them.
|
||||||
|
|
||||||
|
In a more difficult case, certain workflows involve running Git commands
|
||||||
|
within containers. The container boundary prevents any global or system
|
||||||
|
config from communicating `safe.directory` values from the host into the
|
||||||
|
container. Further, the container almost always runs as a different user
|
||||||
|
than the owner of the directory in the host.
|
||||||
|
|
||||||
|
To simplify the reactions necessary for these users, extend the
|
||||||
|
definition of the safe.directory config value to include a possible '*'
|
||||||
|
value. This value implies that all directories are safe, providing a
|
||||||
|
single setting to opt-out of this protection.
|
||||||
|
|
||||||
|
Note that an empty assignment of safe.directory clears all previous
|
||||||
|
values, and this is already the case with the "if (!value || !*value)"
|
||||||
|
condition.
|
||||||
|
|
||||||
|
Signed-off-by: Derrick Stolee <derrickstolee@github.com>
|
||||||
|
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
||||||
|
---
|
||||||
|
Documentation/config/safe.txt | 7 +++++++
|
||||||
|
setup.c | 6 ++++--
|
||||||
|
t/t0033-safe-directory.sh | 10 ++++++++++
|
||||||
|
3 files changed, 21 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt
|
||||||
|
index 63597b2df8f80f..6d764fe0ccf3a8 100644
|
||||||
|
--- a/Documentation/config/safe.txt
|
||||||
|
+++ b/Documentation/config/safe.txt
|
||||||
|
@@ -19,3 +19,10 @@ 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.
|
||||||
|
++
|
||||||
|
+To completely opt-out of this security check, set `safe.directory` to the
|
||||||
|
+string `*`. This will allow all repositories to be treated as if their
|
||||||
|
+directory was listed in the `safe.directory` list. If `safe.directory=*`
|
||||||
|
+is set in system config and you want to re-enable this protection, then
|
||||||
|
+initialize your list with an empty value before listing the repositories
|
||||||
|
+that you deem safe.
|
||||||
|
diff --git a/setup.c b/setup.c
|
||||||
|
index 4b9f073617c2c6..aad9ace0af97ef 100644
|
||||||
|
--- a/setup.c
|
||||||
|
+++ b/setup.c
|
||||||
|
@@ -1037,9 +1037,11 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
|
||||||
|
if (strcmp(key, "safe.directory"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- if (!value || !*value)
|
||||||
|
+ if (!value || !*value) {
|
||||||
|
data->is_safe = 0;
|
||||||
|
- else {
|
||||||
|
+ } else if (!strcmp(value, "*")) {
|
||||||
|
+ data->is_safe = 1;
|
||||||
|
+ } else {
|
||||||
|
const char *interpolated = NULL;
|
||||||
|
|
||||||
|
if (!git_config_pathname(&interpolated, key, value) &&
|
||||||
|
diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
|
||||||
|
index 6f33c0dfefaaf3..239d93f4d21141 100755
|
||||||
|
--- a/t/t0033-safe-directory.sh
|
||||||
|
+++ b/t/t0033-safe-directory.sh
|
||||||
|
@@ -36,4 +36,14 @@ test_expect_success 'safe.directory matches, but is reset' '
|
||||||
|
expect_rejected_dir
|
||||||
|
'
|
||||||
|
|
||||||
|
+test_expect_success 'safe.directory=*' '
|
||||||
|
+ git config --global --add safe.directory "*" &&
|
||||||
|
+ git status
|
||||||
|
+'
|
||||||
|
+
|
||||||
|
+test_expect_success 'safe.directory=*, but is reset' '
|
||||||
|
+ git config --global --add safe.directory "" &&
|
||||||
|
+ expect_rejected_dir
|
||||||
|
+'
|
||||||
|
+
|
||||||
|
test_done
|
||||||
72
backport-t0033-add-tests-for-safe.directory.patch
Normal file
72
backport-t0033-add-tests-for-safe.directory.patch
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
From e47363e5a8bdf5144059d664c45c0975243ef05b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Derrick Stolee <derrickstolee@github.com>
|
||||||
|
Date: Wed, 13 Apr 2022 15:32:29 +0000
|
||||||
|
Subject: [PATCH] t0033: add tests for safe.directory
|
||||||
|
|
||||||
|
It is difficult to change the ownership on a directory in our test
|
||||||
|
suite, so insert a new GIT_TEST_ASSUME_DIFFERENT_OWNER environment
|
||||||
|
variable to trick Git into thinking we are in a differently-owned
|
||||||
|
directory. This allows us to test that the config is parsed correctly.
|
||||||
|
|
||||||
|
Signed-off-by: Derrick Stolee <derrickstolee@github.com>
|
||||||
|
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
||||||
|
---
|
||||||
|
setup.c | 3 ++-
|
||||||
|
t/t0033-safe-directory.sh | 34 ++++++++++++++++++++++++++++++++++
|
||||||
|
2 files changed, 36 insertions(+), 1 deletion(-)
|
||||||
|
create mode 100755 t/t0033-safe-directory.sh
|
||||||
|
|
||||||
|
diff --git a/setup.c b/setup.c
|
||||||
|
index 95d5b00940a87e..3c6ed17af9566a 100644
|
||||||
|
--- a/setup.c
|
||||||
|
+++ b/setup.c
|
||||||
|
@@ -1053,7 +1053,8 @@ static int ensure_valid_ownership(const char *path)
|
||||||
|
{
|
||||||
|
struct safe_directory_data data = { .path = path };
|
||||||
|
|
||||||
|
- if (is_path_owned_by_current_user(path))
|
||||||
|
+ if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
|
||||||
|
+ is_path_owned_by_current_user(path))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
read_very_early_config(safe_directory_cb, &data);
|
||||||
|
diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
|
||||||
|
new file mode 100755
|
||||||
|
index 00000000000000..9380ff3d017096
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/t/t0033-safe-directory.sh
|
||||||
|
@@ -0,0 +1,34 @@
|
||||||
|
+#!/bin/sh
|
||||||
|
+
|
||||||
|
+test_description='verify safe.directory checks'
|
||||||
|
+
|
||||||
|
+. ./test-lib.sh
|
||||||
|
+
|
||||||
|
+GIT_TEST_ASSUME_DIFFERENT_OWNER=1
|
||||||
|
+export GIT_TEST_ASSUME_DIFFERENT_OWNER
|
||||||
|
+
|
||||||
|
+expect_rejected_dir () {
|
||||||
|
+ test_must_fail git status 2>err &&
|
||||||
|
+ grep "safe.directory" err
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+test_expect_success 'safe.directory is not set' '
|
||||||
|
+ expect_rejected_dir
|
||||||
|
+'
|
||||||
|
+
|
||||||
|
+test_expect_success 'safe.directory does not match' '
|
||||||
|
+ git config --global safe.directory bogus &&
|
||||||
|
+ expect_rejected_dir
|
||||||
|
+'
|
||||||
|
+
|
||||||
|
+test_expect_success 'safe.directory matches' '
|
||||||
|
+ git config --global --add safe.directory "$(pwd)" &&
|
||||||
|
+ git status
|
||||||
|
+'
|
||||||
|
+
|
||||||
|
+test_expect_success 'safe.directory matches, but is reset' '
|
||||||
|
+ git config --global --add safe.directory "" &&
|
||||||
|
+ expect_rejected_dir
|
||||||
|
+'
|
||||||
|
+
|
||||||
|
+test_done
|
||||||
16
git.spec
16
git.spec
@ -1,7 +1,7 @@
|
|||||||
%global gitexecdir %{_libexecdir}/git-core
|
%global gitexecdir %{_libexecdir}/git-core
|
||||||
Name: git
|
Name: git
|
||||||
Version: 2.33.0
|
Version: 2.33.0
|
||||||
Release: 2
|
Release: 3
|
||||||
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,6 +12,14 @@ Source100: git-gui.desktop
|
|||||||
Source101: git@.service.in
|
Source101: git@.service.in
|
||||||
Source102: git.socket
|
Source102: git.socket
|
||||||
|
|
||||||
|
Patch0: backport-0001-CVE-2022-24765.patch
|
||||||
|
Patch1: backport-0002-CVE-2022-24765.patch
|
||||||
|
Patch2: backport-0003-CVE-2022-24765.patch
|
||||||
|
Patch3: backport-0004-CVE-2022-24765.patch
|
||||||
|
Patch4: backport-t0033-add-tests-for-safe.directory.patch
|
||||||
|
Patch5: backport-0005-CVE-2022-24765.patch
|
||||||
|
Patch6: backport-0006-CVE-2022-24765.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)
|
||||||
@ -291,6 +299,12 @@ make %{?_smp_mflags} test
|
|||||||
%{_mandir}/man7/git*.7.*
|
%{_mandir}/man7/git*.7.*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri May 20 2022 fuanan <fuanan3@h-partners.com> - 2.33.0-3
|
||||||
|
- Type:CVE
|
||||||
|
- ID:CVE-2022-24765
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:Fix CVE-2022-24765
|
||||||
|
|
||||||
* Thu Feb 17 2022 duyiwei <duyiwei@kylinos.cn> - 2.33.0-2
|
* Thu Feb 17 2022 duyiwei <duyiwei@kylinos.cn> - 2.33.0-2
|
||||||
- add subpackage git-core
|
- add subpackage git-core
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user