|
|
776a70 |
From cfa4e13f09d07f679ffacdddfbe0ef44d1de32d9 Mon Sep 17 00:00:00 2001
|
|
|
776a70 |
From: Petr Stodulka <pstodulk@redhat.com>
|
|
|
776a70 |
Date: Wed, 28 Oct 2015 15:21:08 +0100
|
|
|
776a70 |
Subject: [PATCH 2/5] transport: add a protocol-whitelist environment variable
|
|
|
776a70 |
|
|
|
776a70 |
If we are cloning an untrusted remote repository into a
|
|
|
776a70 |
sandbox, we may also want to fetch remote submodules in
|
|
|
776a70 |
order to get the complete view as intended by the other
|
|
|
776a70 |
side. However, that opens us up to attacks where a malicious
|
|
|
776a70 |
user gets us to clone something they would not otherwise
|
|
|
776a70 |
have access to (this is not necessarily a problem by itself,
|
|
|
776a70 |
but we may then act on the cloned contents in a way that
|
|
|
776a70 |
exposes them to the attacker).
|
|
|
776a70 |
|
|
|
776a70 |
Ideally such a setup would sandbox git entirely away from
|
|
|
776a70 |
high-value items, but this is not always practical or easy
|
|
|
776a70 |
to set up (e.g., OS network controls may block multiple
|
|
|
776a70 |
protocols, and we would want to enable some but not others).
|
|
|
776a70 |
|
|
|
776a70 |
We can help this case by providing a way to restrict
|
|
|
776a70 |
particular protocols. We use a whitelist in the environment.
|
|
|
776a70 |
This is more annoying to set up than a blacklist, but
|
|
|
776a70 |
defaults to safety if the set of protocols git supports
|
|
|
776a70 |
grows). If no whitelist is specified, we continue to default
|
|
|
776a70 |
to allowing all protocols (this is an "unsafe" default, but
|
|
|
776a70 |
since the minority of users will want this sandboxing
|
|
|
776a70 |
effect, it is the only sensible one).
|
|
|
776a70 |
|
|
|
776a70 |
A note on the tests: ideally these would all be in a single
|
|
|
776a70 |
test file, but the git-daemon and httpd test infrastructure
|
|
|
776a70 |
is an all-or-nothing proposition rather than a test-by-test
|
|
|
776a70 |
prerequisite. By putting them all together, we would be
|
|
|
776a70 |
unable to test the file-local code on machines without
|
|
|
776a70 |
apache.
|
|
|
776a70 |
---
|
|
|
776a70 |
Documentation/git.txt | 32 ++++++++++++++++++++++++++++++++
|
|
|
776a70 |
connect.c | 4 ++++
|
|
|
776a70 |
transport-helper.c | 2 ++
|
|
|
776a70 |
transport.c | 21 ++++++++++++++++++++-
|
|
|
776a70 |
transport.h | 7 +++++++
|
|
|
776a70 |
5 files changed, 65 insertions(+), 1 deletion(-)
|
|
|
776a70 |
|
|
|
776a70 |
diff --git a/Documentation/git.txt b/Documentation/git.txt
|
|
|
776a70 |
index 443d88f..179a0e8 100644
|
|
|
776a70 |
--- a/Documentation/git.txt
|
|
|
776a70 |
+++ b/Documentation/git.txt
|
|
|
776a70 |
@@ -847,6 +847,38 @@ GIT_LITERAL_PATHSPECS::
|
|
|
776a70 |
literal paths to Git (e.g., paths previously given to you by
|
|
|
776a70 |
`git ls-tree`, `--raw` diff output, etc).
|
|
|
776a70 |
|
|
|
776a70 |
+`GIT_ALLOW_PROTOCOL`::
|
|
|
776a70 |
+ If set, provide a colon-separated list of protocols which are
|
|
|
776a70 |
+ allowed to be used with fetch/push/clone. This is useful to
|
|
|
776a70 |
+ restrict recursive submodule initialization from an untrusted
|
|
|
776a70 |
+ repository. Any protocol not mentioned will be disallowed (i.e.,
|
|
|
776a70 |
+ this is a whitelist, not a blacklist). If the variable is not
|
|
|
776a70 |
+ set at all, all protocols are enabled. The protocol names
|
|
|
776a70 |
+ currently used by git are:
|
|
|
776a70 |
+
|
|
|
776a70 |
+ - `file`: any local file-based path (including `file://` URLs,
|
|
|
776a70 |
+ or local paths)
|
|
|
776a70 |
+
|
|
|
776a70 |
+ - `git`: the anonymous git protocol over a direct TCP
|
|
|
776a70 |
+ connection (or proxy, if configured)
|
|
|
776a70 |
+
|
|
|
776a70 |
+ - `ssh`: git over ssh (including `host:path` syntax,
|
|
|
776a70 |
+ `git+ssh://`, etc).
|
|
|
776a70 |
+
|
|
|
776a70 |
+ - `rsync`: git over rsync
|
|
|
776a70 |
+
|
|
|
776a70 |
+ - `http`: git over http, both "smart http" and "dumb http".
|
|
|
776a70 |
+ Note that this does _not_ include `https`; if you want both,
|
|
|
776a70 |
+ you should specify both as `http:https`.
|
|
|
776a70 |
+
|
|
|
776a70 |
+ - any external helpers are named by their protocol (e.g., use
|
|
|
776a70 |
+ `hg` to allow the `git-remote-hg` helper)
|
|
|
776a70 |
++
|
|
|
776a70 |
+Note that this controls only git's internal protocol selection.
|
|
|
776a70 |
+If libcurl is used (e.g., by the `http` transport), it may
|
|
|
776a70 |
+redirect to other protocols. There is not currently any way to
|
|
|
776a70 |
+restrict this.
|
|
|
776a70 |
+
|
|
|
776a70 |
|
|
|
776a70 |
Discussion[[Discussion]]
|
|
|
776a70 |
------------------------
|
|
|
776a70 |
diff --git a/connect.c b/connect.c
|
|
|
776a70 |
index f57efd0..6d4ea13 100644
|
|
|
776a70 |
--- a/connect.c
|
|
|
776a70 |
+++ b/connect.c
|
|
|
776a70 |
@@ -6,6 +6,7 @@
|
|
|
776a70 |
#include "run-command.h"
|
|
|
776a70 |
#include "remote.h"
|
|
|
776a70 |
#include "url.h"
|
|
|
776a70 |
+#include "transport.h"
|
|
|
776a70 |
|
|
|
776a70 |
static char *server_capabilities;
|
|
|
776a70 |
|
|
|
776a70 |
@@ -587,6 +588,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
|
|
|
776a70 |
* cannot connect.
|
|
|
776a70 |
*/
|
|
|
776a70 |
char *target_host = xstrdup(host);
|
|
|
776a70 |
+ transport_check_allowed("git");
|
|
|
776a70 |
if (git_use_proxy(host))
|
|
|
776a70 |
conn = git_proxy_connect(fd, host);
|
|
|
776a70 |
else
|
|
|
776a70 |
@@ -623,6 +625,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
|
|
|
776a70 |
if (protocol == PROTO_SSH) {
|
|
|
776a70 |
const char *ssh = getenv("GIT_SSH");
|
|
|
776a70 |
int putty = ssh && strcasestr(ssh, "plink");
|
|
|
776a70 |
+ transport_check_allowed("ssh");
|
|
|
776a70 |
if (!ssh) ssh = "ssh";
|
|
|
776a70 |
|
|
|
776a70 |
*arg++ = ssh;
|
|
|
776a70 |
@@ -639,6 +642,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
|
|
|
776a70 |
/* remove repo-local variables from the environment */
|
|
|
776a70 |
conn->env = local_repo_env;
|
|
|
776a70 |
conn->use_shell = 1;
|
|
|
776a70 |
+ transport_check_allowed("file");
|
|
|
776a70 |
}
|
|
|
776a70 |
*arg++ = cmd.buf;
|
|
|
776a70 |
*arg = NULL;
|
|
|
776a70 |
diff --git a/transport-helper.c b/transport-helper.c
|
|
|
776a70 |
index 522d791..be8402a 100644
|
|
|
776a70 |
--- a/transport-helper.c
|
|
|
776a70 |
+++ b/transport-helper.c
|
|
|
776a70 |
@@ -932,6 +932,8 @@ int transport_helper_init(struct transport *transport, const char *name)
|
|
|
776a70 |
struct helper_data *data = xcalloc(sizeof(*data), 1);
|
|
|
776a70 |
data->name = name;
|
|
|
776a70 |
|
|
|
776a70 |
+ transport_check_allowed(name);
|
|
|
776a70 |
+
|
|
|
776a70 |
if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
|
|
|
776a70 |
debug = 1;
|
|
|
776a70 |
|
|
|
776a70 |
diff --git a/transport.c b/transport.c
|
|
|
776a70 |
index ba5d8af..733717d 100644
|
|
|
776a70 |
--- a/transport.c
|
|
|
776a70 |
+++ b/transport.c
|
|
|
776a70 |
@@ -894,6 +894,20 @@ static int external_specification_len(const char *url)
|
|
|
776a70 |
return strchr(url, ':') - url;
|
|
|
776a70 |
}
|
|
|
776a70 |
|
|
|
776a70 |
+void transport_check_allowed(const char *type)
|
|
|
776a70 |
+{
|
|
|
776a70 |
+ struct string_list allowed = STRING_LIST_INIT_DUP;
|
|
|
776a70 |
+ const char *v = getenv("GIT_ALLOW_PROTOCOL");
|
|
|
776a70 |
+
|
|
|
776a70 |
+ if (!v)
|
|
|
776a70 |
+ return;
|
|
|
776a70 |
+
|
|
|
776a70 |
+ string_list_split(&allowed, v, ':', -1);
|
|
|
776a70 |
+ if (!unsorted_string_list_has_string(&allowed, type))
|
|
|
776a70 |
+ die("transport '%s' not allowed", type);
|
|
|
776a70 |
+ string_list_clear(&allowed, 0);
|
|
|
776a70 |
+}
|
|
|
776a70 |
+
|
|
|
776a70 |
struct transport *transport_get(struct remote *remote, const char *url)
|
|
|
776a70 |
{
|
|
|
776a70 |
const char *helper;
|
|
|
776a70 |
@@ -925,12 +939,14 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
|
|
776a70 |
if (helper) {
|
|
|
776a70 |
transport_helper_init(ret, helper);
|
|
|
776a70 |
} else if (!prefixcmp(url, "rsync:")) {
|
|
|
776a70 |
+ transport_check_allowed("rsync");
|
|
|
776a70 |
ret->get_refs_list = get_refs_via_rsync;
|
|
|
776a70 |
ret->fetch = fetch_objs_via_rsync;
|
|
|
776a70 |
ret->push = rsync_transport_push;
|
|
|
776a70 |
ret->smart_options = NULL;
|
|
|
776a70 |
} else if (is_local(url) && is_file(url) && is_bundle(url, 1)) {
|
|
|
776a70 |
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
|
|
|
776a70 |
+ transport_check_allowed("file");
|
|
|
776a70 |
ret->data = data;
|
|
|
776a70 |
ret->get_refs_list = get_refs_from_bundle;
|
|
|
776a70 |
ret->fetch = fetch_refs_from_bundle;
|
|
|
776a70 |
@@ -942,7 +958,10 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
|
|
776a70 |
|| !prefixcmp(url, "ssh://")
|
|
|
776a70 |
|| !prefixcmp(url, "git+ssh://")
|
|
|
776a70 |
|| !prefixcmp(url, "ssh+git://")) {
|
|
|
776a70 |
- /* These are builtin smart transports. */
|
|
|
776a70 |
+ /*
|
|
|
776a70 |
+ * These are builtin smart transports; "allowed" transports
|
|
|
776a70 |
+ * will be checked individually in git_connect.
|
|
|
776a70 |
+ */
|
|
|
776a70 |
struct git_transport_data *data = xcalloc(1, sizeof(*data));
|
|
|
776a70 |
ret->data = data;
|
|
|
776a70 |
ret->set_option = NULL;
|
|
|
776a70 |
diff --git a/transport.h b/transport.h
|
|
|
776a70 |
index fcb1d25..2beda7d 100644
|
|
|
776a70 |
--- a/transport.h
|
|
|
776a70 |
+++ b/transport.h
|
|
|
776a70 |
@@ -113,6 +113,13 @@ struct transport {
|
|
|
776a70 |
/* Returns a transport suitable for the url */
|
|
|
776a70 |
struct transport *transport_get(struct remote *, const char *);
|
|
|
776a70 |
|
|
|
776a70 |
+/*
|
|
|
776a70 |
+ * Check whether a transport is allowed by the environment,
|
|
|
776a70 |
+ * and die otherwise. type should generally be the URL scheme,
|
|
|
776a70 |
+ * as described in Documentation/git.txt
|
|
|
776a70 |
+ */
|
|
|
776a70 |
+void transport_check_allowed(const char *type);
|
|
|
776a70 |
+
|
|
|
776a70 |
/* Transport options which apply to git:// and scp-style URLs */
|
|
|
776a70 |
|
|
|
776a70 |
/* The program to use on the remote side to send a pack */
|
|
|
776a70 |
--
|
|
|
776a70 |
2.1.0
|
|
|
776a70 |
|