From 411c1b0a0c9a359bb4f8a331094ef9eb1dd2ff9c Mon Sep 17 00:00:00 2001 From: yinyongkang Date: Fri, 15 Jul 2022 15:04:21 +0800 Subject: [PATCH] Fix CVE-2022-29187 --- backport-CVE-2022-29187.patch | 166 ++++++++++++++++++++++++++++++++++ git.spec | 10 +- 2 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2022-29187.patch diff --git a/backport-CVE-2022-29187.patch b/backport-CVE-2022-29187.patch new file mode 100644 index 0000000..ce61786 --- /dev/null +++ b/backport-CVE-2022-29187.patch @@ -0,0 +1,166 @@ +From 8dda857a86aa8e4f6ae39951164ed6493ed6678f Mon Sep 17 00:00:00 2001 +From: yinyongkang +Date: Fri, 15 Jul 2022 14:46:25 +0800 +Subject: [PATCH] setup: tighten ownership checks post CVE-2022-24765 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +8959555 (setup_git_directory(): add an owner check for the top-level +directory, 2022-03-02), adds a function to check for ownership of +repositories using a directory that is representative of it, and ways to +add exempt a specific repository from said check if needed, but that +check didn't account for owership of the gitdir, or (when used) the +gitfile that points to that gitdir. + +An attacker could create a git repository in a directory that they can +write into but that is owned by the victim to work around the fix that +was introduced with CVE-2022-24765 to potentially run code as the +victim. + +An example that could result in privilege escalation to root in *NIX would +be to set a repository in a shared tmp directory by doing (for example): + + $ git -C /tmp init + +To avoid that, extend the ensure_valid_ownership function to be able to +check for all three paths. + +This will have the side effect of tripling the number of stat() calls +when a repository is detected, but the effect is expected to be likely +minimal, as it is done only once during the directory walk in which Git +looks for a repository. + +Additionally make sure to resolve the gitfile (if one was used) to find +the relevant gitdir for checking. + +While at it change the message printed on failure so it is clear we are +referring to the repository by its worktree (or gitdir if it is bare) and +not to a specific directory. + +Helped-by: Junio C Hamano +Helped-by: Johannes Schindelin +Signed-off-by: Carlo Marcelo Arenas Belón +--- + setup.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 60 insertions(+), 11 deletions(-) + +diff --git a/setup.c b/setup.c +index a7b36f3..ca6a5dd 100644 +--- a/setup.c ++++ b/setup.c +@@ -1120,14 +1120,32 @@ static int safe_directory_cb(const char *key, const char *value, void *d) + return 0; + } + +-static int ensure_valid_ownership(const char *path) ++/* ++ * Check if a repository is safe, by verifying the ownership of the ++ * worktree (if any), the git directory, and the gitfile (if any). ++ * ++ * Exemptions for known-safe repositories can be added via `safe.directory` ++ * config settings; for non-bare repositories, their worktree needs to be ++ * added, for bare ones their git directory. ++ */ ++static int ensure_valid_ownership(const char *gitfile, ++ const char *worktree, const char *gitdir) + { +- struct safe_directory_data data = { .path = path }; ++ struct safe_directory_data data = { ++ .path = worktree ? worktree : gitdir ++ }; + + if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) && +- is_path_owned_by_current_user(path)) ++ (!gitfile || is_path_owned_by_current_user(gitfile)) && ++ (!worktree || is_path_owned_by_current_user(worktree)) && ++ (!gitdir || is_path_owned_by_current_user(gitdir))) + return 1; + ++ /* ++ * data.path is the "path" that identifies the repository and it is ++ * constant regardless of what failed above. data.is_safe should be ++ * initialized to false, and might be changed by the callback. ++ */ + read_very_early_config(safe_directory_cb, &data); + + return data.is_safe; +@@ -1215,6 +1233,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir, + current_device = get_device_or_die(dir->buf, NULL, 0); + for (;;) { + int offset = dir->len, error_code = 0; ++ char *gitdir_path = NULL; ++ char *gitfile = NULL; + + if (offset > min_offset) + strbuf_addch(dir, '/'); +@@ -1225,21 +1245,50 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir, + if (die_on_error || + error_code == READ_GITFILE_ERR_NOT_A_FILE) { + /* NEEDSWORK: fail if .git is not file nor dir */ +- if (is_git_directory(dir->buf)) ++ if (is_git_directory(dir->buf)) { + gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT; ++ gitdir_path = xstrdup(dir->buf); ++ } + } else if (error_code != READ_GITFILE_ERR_STAT_FAILED) + return GIT_DIR_INVALID_GITFILE; +- } ++ } else ++ gitfile = xstrdup(dir->buf); ++ /* ++ * Earlier, we tentatively added DEFAULT_GIT_DIR_ENVIRONMENT ++ * to check that directory for a repository. ++ * Now trim that tentative addition away, because we want to ++ * focus on the real directory we are in. ++ */ + 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; ++ enum discovery_result ret; ++ ++ if (ensure_valid_ownership(gitfile, ++ dir->buf, ++ (gitdir_path ? gitdir_path : gitdirenv))) { ++ strbuf_addstr(gitdir, gitdirenv); ++ ret = GIT_DIR_DISCOVERED; ++ } else ++ ret = GIT_DIR_INVALID_OWNERSHIP; ++ ++ /* ++ * Earlier, during discovery, we might have allocated ++ * string copies for gitdir_path or gitfile so make ++ * sure we don't leak by freeing them now, before ++ * leaving the loop and function. ++ * ++ * Note: gitdirenv will be non-NULL whenever these are ++ * allocated, therefore we need not take care of releasing ++ * them outside of this conditional block. ++ */ ++ free(gitdir_path); ++ free(gitfile); ++ ++ return ret; + } + + if (is_git_directory(dir->buf)) { +- if (!ensure_valid_ownership(dir->buf)) ++ if (!ensure_valid_ownership(NULL, NULL, dir->buf)) + return GIT_DIR_INVALID_OWNERSHIP; + strbuf_addstr(gitdir, "."); + return GIT_DIR_BARE; +@@ -1377,7 +1426,7 @@ const char *setup_git_directory_gently(int *nongit_ok) + struct strbuf quoted = STRBUF_INIT; + + sq_quote_buf_pretty("ed, dir.buf); +- die(_("unsafe repository ('%s' is owned by someone else)\n" ++ die(_("detected dubious ownership in repository at '%s'\n" + "To add an exception for this directory, call:\n" + "\n" + "\tgit config --global --add safe.directory %s"), +-- +2.33.0 + diff --git a/git.spec b/git.spec index c021131..704ddcf 100644 --- a/git.spec +++ b/git.spec @@ -1,7 +1,7 @@ %global gitexecdir %{_libexecdir}/git-core Name: git Version: 2.36.1 -Release: 1 +Release: 2 Summary: A popular and widely used Version Control System License: GPLv2+ or LGPLv2.1 URL: https://git-scm.com/ @@ -12,6 +12,8 @@ Source100: git-gui.desktop Source101: git@.service.in Source102: git.socket +Patch6000: backport-CVE-2022-29187.patch + BuildRequires: gcc gettext BuildRequires: openssl-devel libcurl-devel expat-devel systemd asciidoc xmlto glib2-devel libsecret-devel pcre-devel desktop-file-utils BuildRequires: python3-devel perl-generators perl-interpreter perl-Error perl(Test::More) perl-MailTools perl(Test) @@ -291,6 +293,12 @@ make %{?_smp_mflags} test %{_mandir}/man7/git*.7.* %changelog +* Fri Jul 15 2022 yinyongkang -2.36.1-2 +- Type:CVE +- ID:CVE-2022-29187 +- SUG:NA +- DESC:Fix CVE-2022-29187 + * Fri Jul 01 2022 fuanan - 2.36.1-1 - Type:enhancement - ID:NA -- Gitee