From: "Glen Choo via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: "Taylor Blau" <me@ttaylorr.com>,
"Derrick Stolee" <derrickstolee@github.com>,
"Junio C Hamano" <gitster@pobox.com>,
"Emily Shaffer" <emilyshaffer@google.com>,
"Jonathan Tan" <jonathantanmy@google.com>,
"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>,
"Johannes Schindelin" <Johannes.Schindelin@gmx.de>,
"Glen Choo" <chooglen@google.com>,
"Glen Choo" <chooglen@google.com>
Subject: [PATCH v8 5/5] setup.c: create `safe.bareRepository`
Date: Thu, 14 Jul 2022 21:28:01 +0000 [thread overview]
Message-ID: <50069bba9a5933fd968a8aa52acefc2a305204f5.1657834082.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1261.v8.git.git.1657834081.gitgitgadget@gmail.com>
From: Glen Choo <chooglen@google.com>
There is a known social engineering attack that takes advantage of the
fact that a working tree can include an entire bare repository,
including a config file. A user could run a Git command inside the bare
repository thinking that the config file of the 'outer' repository would
be used, but in reality, the bare repository's config file (which is
attacker-controlled) is used, which may result in arbitrary code
execution. See [1] for a fuller description and deeper discussion.
A simple mitigation is to forbid bare repositories unless specified via
`--git-dir` or `GIT_DIR`. In environments that don't use bare
repositories, this would be minimally disruptive.
Create a config variable, `safe.bareRepository`, that tells Git whether
or not to die() when working with a bare repository. This config is an
enum of:
- "all": allow all bare repositories (this is the default)
- "explicit": only allow bare repositories specified via --git-dir
or GIT_DIR.
If we want to protect users from such attacks by default, neither value
will suffice - "all" provides no protection, but "explicit" is
impractical for bare repository users. A more usable default would be to
allow only non-embedded bare repositories ([2] contains one such
proposal), but detecting if a repository is embedded is potentially
non-trivial, so this work is not implemented in this series.
[1]: https://lore.kernel.org/git/kl6lsfqpygsj.fsf@chooglen-macbookpro.roam.corp.google.com
[2]: https://lore.kernel.org/git/5b969c5e-e802-c447-ad25-6acc0b784582@github.com
Signed-off-by: Glen Choo <chooglen@google.com>
---
Documentation/config/safe.txt | 19 +++++++++++
setup.c | 57 ++++++++++++++++++++++++++++++++-
t/t0035-safe-bare-repository.sh | 54 +++++++++++++++++++++++++++++++
3 files changed, 129 insertions(+), 1 deletion(-)
create mode 100755 t/t0035-safe-bare-repository.sh
diff --git a/Documentation/config/safe.txt b/Documentation/config/safe.txt
index f72b4408798..bde7f31459b 100644
--- a/Documentation/config/safe.txt
+++ b/Documentation/config/safe.txt
@@ -1,3 +1,22 @@
+safe.bareRepository::
+ Specifies which bare repositories Git will work with. The currently
+ supported values are:
++
+* `all`: Git works with all bare repositories. This is the default.
+* `explicit`: Git only works with bare repositories specified via
+ the top-level `--git-dir` command-line option, or the `GIT_DIR`
+ environment variable (see linkgit:git[1]).
++
+If you do not use bare repositories in your workflow, then it may be
+beneficial to set `safe.bareRepository` to `explicit` in your global
+config. This will protect you from attacks that involve cloning a
+repository that contains a bare repository and running a Git command
+within that directory.
++
+This config setting is only respected in protected configuration (see
+<<SCOPES>>). This prevents the untrusted repository from tampering with
+this value.
+
safe.directory::
These config entries specify Git-tracked directories that are
considered safe even if they are owned by someone other than the
diff --git a/setup.c b/setup.c
index ec5b9139e32..8c683e92b62 100644
--- a/setup.c
+++ b/setup.c
@@ -10,6 +10,10 @@
static int inside_git_dir = -1;
static int inside_work_tree = -1;
static int work_tree_config_is_bogus;
+enum allowed_bare_repo {
+ ALLOWED_BARE_REPO_EXPLICIT = 0,
+ ALLOWED_BARE_REPO_ALL,
+};
static struct startup_info the_startup_info;
struct startup_info *startup_info = &the_startup_info;
@@ -1160,6 +1164,46 @@ static int ensure_valid_ownership(const char *gitfile,
return data.is_safe;
}
+static int allowed_bare_repo_cb(const char *key, const char *value, void *d)
+{
+ enum allowed_bare_repo *allowed_bare_repo = d;
+
+ if (strcasecmp(key, "safe.bareRepository"))
+ return 0;
+
+ if (!strcmp(value, "explicit")) {
+ *allowed_bare_repo = ALLOWED_BARE_REPO_EXPLICIT;
+ return 0;
+ }
+ if (!strcmp(value, "all")) {
+ *allowed_bare_repo = ALLOWED_BARE_REPO_ALL;
+ return 0;
+ }
+ return -1;
+}
+
+static enum allowed_bare_repo get_allowed_bare_repo(void)
+{
+ enum allowed_bare_repo result = ALLOWED_BARE_REPO_ALL;
+ git_protected_config(allowed_bare_repo_cb, &result);
+ return result;
+}
+
+static const char *allowed_bare_repo_to_string(
+ enum allowed_bare_repo allowed_bare_repo)
+{
+ switch (allowed_bare_repo) {
+ case ALLOWED_BARE_REPO_EXPLICIT:
+ return "explicit";
+ case ALLOWED_BARE_REPO_ALL:
+ return "all";
+ default:
+ BUG("invalid allowed_bare_repo %d",
+ allowed_bare_repo);
+ }
+ return NULL;
+}
+
enum discovery_result {
GIT_DIR_NONE = 0,
GIT_DIR_EXPLICIT,
@@ -1169,7 +1213,8 @@ enum discovery_result {
GIT_DIR_HIT_CEILING = -1,
GIT_DIR_HIT_MOUNT_POINT = -2,
GIT_DIR_INVALID_GITFILE = -3,
- GIT_DIR_INVALID_OWNERSHIP = -4
+ GIT_DIR_INVALID_OWNERSHIP = -4,
+ GIT_DIR_DISALLOWED_BARE = -5,
};
/*
@@ -1297,6 +1342,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
}
if (is_git_directory(dir->buf)) {
+ if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT)
+ return GIT_DIR_DISALLOWED_BARE;
if (!ensure_valid_ownership(NULL, NULL, dir->buf))
return GIT_DIR_INVALID_OWNERSHIP;
strbuf_addstr(gitdir, ".");
@@ -1443,6 +1490,14 @@ const char *setup_git_directory_gently(int *nongit_ok)
}
*nongit_ok = 1;
break;
+ case GIT_DIR_DISALLOWED_BARE:
+ if (!nongit_ok) {
+ die(_("cannot use bare repository '%s' (safe.bareRepository is '%s')"),
+ dir.buf,
+ allowed_bare_repo_to_string(get_allowed_bare_repo()));
+ }
+ *nongit_ok = 1;
+ break;
case GIT_DIR_NONE:
/*
* As a safeguard against setup_git_directory_gently_1 returning
diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh
new file mode 100755
index 00000000000..ecbdc8238db
--- /dev/null
+++ b/t/t0035-safe-bare-repository.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+test_description='verify safe.bareRepository checks'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+pwd="$(pwd)"
+
+expect_accepted () {
+ git "$@" rev-parse --git-dir
+}
+
+expect_rejected () {
+ test_must_fail git "$@" rev-parse --git-dir 2>err &&
+ grep -F "cannot use bare repository" err
+}
+
+test_expect_success 'setup bare repo in worktree' '
+ git init outer-repo &&
+ git init --bare outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository unset' '
+ expect_accepted -C outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository=all' '
+ test_config_global safe.bareRepository all &&
+ expect_accepted -C outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository=explicit' '
+ test_config_global safe.bareRepository explicit &&
+ expect_rejected -C outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository in the repository' '
+ # safe.bareRepository must not be "explicit", otherwise
+ # git config fails with "fatal: not in a git directory" (like
+ # safe.directory)
+ test_config -C outer-repo/bare-repo safe.bareRepository \
+ all &&
+ test_config_global safe.bareRepository explicit &&
+ expect_rejected -C outer-repo/bare-repo
+'
+
+test_expect_success 'safe.bareRepository on the command line' '
+ test_config_global safe.bareRepository explicit &&
+ expect_accepted -C outer-repo/bare-repo \
+ -c safe.bareRepository=all
+'
+
+test_done
--
gitgitgadget
prev parent reply other threads:[~2022-07-14 21:28 UTC|newest]
Thread overview: 113+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-06 18:30 [PATCH] [RFC] setup.c: make bare repo discovery optional Glen Choo via GitGitGadget
2022-05-06 20:33 ` Junio C Hamano
2022-05-09 21:42 ` Taylor Blau
2022-05-09 22:54 ` Junio C Hamano
2022-05-09 23:57 ` Taylor Blau
2022-05-10 0:23 ` Junio C Hamano
2022-05-10 22:00 ` Glen Choo
2022-05-13 23:37 ` [PATCH v2 0/2] " Glen Choo via GitGitGadget
2022-05-13 23:37 ` [PATCH v2 1/2] " Glen Choo via GitGitGadget
2022-05-16 18:12 ` Glen Choo
2022-05-16 18:46 ` Derrick Stolee
2022-05-16 22:25 ` Taylor Blau
2022-05-17 20:24 ` Glen Choo
2022-05-17 21:51 ` Glen Choo
2022-05-13 23:37 ` [PATCH v2 2/2] setup.c: learn discovery.bareRepository=cwd Glen Choo via GitGitGadget
2022-05-16 18:49 ` Derrick Stolee
2022-05-16 16:40 ` [PATCH v2 0/2] setup.c: make bare repo discovery optional Junio C Hamano
2022-05-16 18:36 ` Glen Choo
2022-05-16 19:16 ` Junio C Hamano
2022-05-16 20:27 ` Glen Choo
2022-05-16 22:16 ` Junio C Hamano
2022-05-16 16:43 ` Junio C Hamano
2022-05-16 19:07 ` Derrick Stolee
2022-05-16 22:43 ` Taylor Blau
2022-05-16 23:19 ` Junio C Hamano
2022-05-17 18:56 ` Glen Choo
2022-05-27 21:09 ` [PATCH v3 0/5] config: introduce discovery.bare and protected config Glen Choo via GitGitGadget
2022-05-27 21:09 ` [PATCH v3 1/5] Documentation: define protected configuration Glen Choo via GitGitGadget
2022-05-27 23:29 ` Junio C Hamano
2022-06-02 12:42 ` Derrick Stolee
2022-06-02 16:53 ` Junio C Hamano
2022-06-02 17:39 ` Glen Choo
2022-06-03 15:57 ` Glen Choo
2022-05-27 21:09 ` [PATCH v3 2/5] config: read protected config with `git_protected_config()` Glen Choo via GitGitGadget
2022-05-28 0:28 ` Junio C Hamano
2022-05-31 17:43 ` Glen Choo
2022-06-01 15:58 ` Junio C Hamano
2022-06-02 12:56 ` Derrick Stolee
2022-05-27 21:09 ` [PATCH v3 3/5] setup.c: create `discovery.bare` Glen Choo via GitGitGadget
2022-05-28 0:59 ` Junio C Hamano
2022-06-02 13:11 ` Derrick Stolee
2022-05-27 21:09 ` [PATCH v3 4/5] config: include "-c" in protected config Glen Choo via GitGitGadget
2022-06-02 13:15 ` Derrick Stolee
2022-05-27 21:09 ` [PATCH v3 5/5] upload-pack: make uploadpack.packObjectsHook protected Glen Choo via GitGitGadget
2022-06-02 13:18 ` Derrick Stolee
2022-06-07 20:57 ` [PATCH v4 0/5] config: introduce discovery.bare and protected config Glen Choo via GitGitGadget
2022-06-07 20:57 ` [PATCH v4 1/5] Documentation/git-config.txt: add SCOPES section Glen Choo via GitGitGadget
2022-06-07 20:57 ` [PATCH v4 2/5] Documentation: define protected configuration Glen Choo via GitGitGadget
2022-06-22 21:58 ` Jonathan Tan
2022-06-23 18:21 ` Glen Choo
2022-06-07 20:57 ` [PATCH v4 3/5] config: read protected config with `git_protected_config()` Glen Choo via GitGitGadget
2022-06-07 22:49 ` Junio C Hamano
2022-06-08 0:22 ` Glen Choo
2022-06-07 20:57 ` [PATCH v4 4/5] safe.directory: use git_protected_config() Glen Choo via GitGitGadget
2022-06-07 20:57 ` [PATCH v4 5/5] setup.c: create `discovery.bare` Glen Choo via GitGitGadget
2022-06-07 21:37 ` Glen Choo
2022-06-22 22:03 ` [PATCH v4 0/5] config: introduce discovery.bare and protected config Jonathan Tan
2022-06-23 17:13 ` Glen Choo
2022-06-23 18:32 ` Junio C Hamano
2022-06-27 17:34 ` Glen Choo
2022-06-27 18:19 ` Glen Choo
2022-06-27 18:36 ` [PATCH v5 " Glen Choo via GitGitGadget
2022-06-27 18:36 ` [PATCH v5 1/5] Documentation/git-config.txt: add SCOPES section Glen Choo via GitGitGadget
2022-06-27 18:36 ` [PATCH v5 2/5] Documentation: define protected configuration Glen Choo via GitGitGadget
2022-06-27 18:36 ` [PATCH v5 3/5] config: learn `git_protected_config()` Glen Choo via GitGitGadget
2022-06-27 18:36 ` [PATCH v5 4/5] safe.directory: use git_protected_config() Glen Choo via GitGitGadget
2022-06-27 18:36 ` [PATCH v5 5/5] setup.c: create `discovery.bare` Glen Choo via GitGitGadget
2022-06-30 13:20 ` Ævar Arnfjörð Bjarmason
2022-06-30 17:28 ` Glen Choo
2022-06-30 18:13 ` [PATCH v6 0/5] config: introduce discovery.bare and protected config Glen Choo via GitGitGadget
2022-06-30 18:13 ` [PATCH v6 1/5] Documentation/git-config.txt: add SCOPES section Glen Choo via GitGitGadget
2022-06-30 22:32 ` Taylor Blau
2022-07-06 17:44 ` Glen Choo
2022-06-30 18:13 ` [PATCH v6 2/5] Documentation: define protected configuration Glen Choo via GitGitGadget
2022-06-30 23:49 ` Taylor Blau
2022-07-06 18:21 ` Glen Choo
2022-06-30 18:13 ` [PATCH v6 3/5] config: learn `git_protected_config()` Glen Choo via GitGitGadget
2022-07-01 1:22 ` Taylor Blau
2022-07-06 22:42 ` Glen Choo
2022-06-30 18:13 ` [PATCH v6 4/5] safe.directory: use git_protected_config() Glen Choo via GitGitGadget
2022-06-30 18:13 ` [PATCH v6 5/5] setup.c: create `discovery.bare` Glen Choo via GitGitGadget
2022-07-01 1:30 ` Taylor Blau
2022-07-07 19:55 ` Glen Choo
2022-06-30 22:13 ` [PATCH v6 0/5] config: introduce discovery.bare and protected config Taylor Blau
2022-06-30 23:07 ` Ævar Arnfjörð Bjarmason
2022-07-01 17:37 ` Glen Choo
2022-07-08 21:58 ` Ævar Arnfjörð Bjarmason
2022-07-12 20:47 ` Glen Choo
2022-07-12 23:53 ` Ævar Arnfjörð Bjarmason
2022-07-07 23:01 ` [PATCH v7 " Glen Choo via GitGitGadget
2022-07-07 23:01 ` [PATCH v7 1/5] Documentation/git-config.txt: add SCOPES section Glen Choo via GitGitGadget
2022-07-07 23:43 ` Junio C Hamano
2022-07-08 17:01 ` Glen Choo
2022-07-08 19:01 ` Junio C Hamano
2022-07-08 21:38 ` Glen Choo
2022-07-07 23:01 ` [PATCH v7 2/5] Documentation: define protected configuration Glen Choo via GitGitGadget
2022-07-08 0:39 ` Junio C Hamano
2022-07-07 23:01 ` [PATCH v7 3/5] config: learn `git_protected_config()` Glen Choo via GitGitGadget
2022-07-07 23:01 ` [PATCH v7 4/5] safe.directory: use git_protected_config() Glen Choo via GitGitGadget
2022-07-07 23:01 ` [PATCH v7 5/5] setup.c: create `discovery.bare` Glen Choo via GitGitGadget
2022-07-08 1:07 ` [PATCH v7 0/5] config: introduce discovery.bare and protected config Junio C Hamano
2022-07-08 20:35 ` Glen Choo
2022-07-12 22:11 ` Glen Choo
2022-07-14 21:27 ` [PATCH v8 0/5] config: introduce safe.bareRepository " Glen Choo via GitGitGadget
2022-07-14 21:27 ` [PATCH v8 1/5] Documentation/git-config.txt: add SCOPES section Glen Choo via GitGitGadget
2022-07-14 21:27 ` [PATCH v8 2/5] Documentation: define protected configuration Glen Choo via GitGitGadget
2022-07-14 21:27 ` [PATCH v8 3/5] config: learn `git_protected_config()` Glen Choo via GitGitGadget
2022-07-25 18:26 ` SANITIZE=address failure on master (was: [PATCH v8 3/5] config: learn `git_protected_config()`) Ævar Arnfjörð Bjarmason
2022-07-25 20:15 ` Glen Choo
2022-07-25 20:41 ` Ævar Arnfjörð Bjarmason
2022-07-25 20:56 ` Glen Choo
2022-07-14 21:28 ` [PATCH v8 4/5] safe.directory: use git_protected_config() Glen Choo via GitGitGadget
2022-07-14 21:28 ` Glen Choo via GitGitGadget [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=50069bba9a5933fd968a8aa52acefc2a305204f5.1657834082.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=Johannes.Schindelin@gmx.de \
--cc=avarab@gmail.com \
--cc=chooglen@google.com \
--cc=derrickstolee@github.com \
--cc=emilyshaffer@google.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jonathantanmy@google.com \
--cc=me@ttaylorr.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).