mirror of
https://git.yoctoproject.org/git/poky
synced 2026-01-04 16:10:04 +00:00
CVE-2015-7545 git: arbitrary code execution via crafted URLs (From OE-Core rev: 0c4bdd61acbc1fa1b9bfb167d8eaf90c8bccc25c) Signed-off-by: Armin Kuster <akuster@mvista.com> Already in Jethro, not needed in master due to shipping a version of git which is already fixes (> 2.6.1) Signed-off-by: Joshua Lock <joshua.g.lock@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
446 lines
14 KiB
Diff
446 lines
14 KiB
Diff
From a5adaced2e13c135d5d9cc65be9eb95aa3bacedf Mon Sep 17 00:00:00 2001
|
|
From: Jeff King <peff@peff.net>
|
|
Date: Wed, 16 Sep 2015 13:12:52 -0400
|
|
Subject: [PATCH] transport: add a protocol-whitelist environment variable
|
|
|
|
If we are cloning an untrusted remote repository into a
|
|
sandbox, we may also want to fetch remote submodules in
|
|
order to get the complete view as intended by the other
|
|
side. However, that opens us up to attacks where a malicious
|
|
user gets us to clone something they would not otherwise
|
|
have access to (this is not necessarily a problem by itself,
|
|
but we may then act on the cloned contents in a way that
|
|
exposes them to the attacker).
|
|
|
|
Ideally such a setup would sandbox git entirely away from
|
|
high-value items, but this is not always practical or easy
|
|
to set up (e.g., OS network controls may block multiple
|
|
protocols, and we would want to enable some but not others).
|
|
|
|
We can help this case by providing a way to restrict
|
|
particular protocols. We use a whitelist in the environment.
|
|
This is more annoying to set up than a blacklist, but
|
|
defaults to safety if the set of protocols git supports
|
|
grows). If no whitelist is specified, we continue to default
|
|
to allowing all protocols (this is an "unsafe" default, but
|
|
since the minority of users will want this sandboxing
|
|
effect, it is the only sensible one).
|
|
|
|
A note on the tests: ideally these would all be in a single
|
|
test file, but the git-daemon and httpd test infrastructure
|
|
is an all-or-nothing proposition rather than a test-by-test
|
|
prerequisite. By putting them all together, we would be
|
|
unable to test the file-local code on machines without
|
|
apache.
|
|
|
|
Signed-off-by: Jeff King <peff@peff.net>
|
|
Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
|
|
|
Upstream-Status: Backport
|
|
/hom://kernel.googlesource.com/pub/scm/git/git/+/a5adaced2e13c135d5d9cc65be9eb95aa3bacedf%5E%21/
|
|
CVE: CVE-2015-7545 patch #1
|
|
Signed-off-by: Armin Kuster <akuster@mvista.com>
|
|
|
|
---
|
|
Documentation/git.txt | 32 ++++++++++++++
|
|
connect.c | 5 +++
|
|
t/lib-proto-disable.sh | 96 ++++++++++++++++++++++++++++++++++++++++++
|
|
t/t5810-proto-disable-local.sh | 14 ++++++
|
|
t/t5811-proto-disable-git.sh | 20 +++++++++
|
|
t/t5812-proto-disable-http.sh | 20 +++++++++
|
|
t/t5813-proto-disable-ssh.sh | 20 +++++++++
|
|
t/t5814-proto-disable-ext.sh | 18 ++++++++
|
|
transport-helper.c | 2 +
|
|
transport.c | 21 ++++++++-
|
|
transport.h | 7 +++
|
|
11 files changed, 254 insertions(+), 1 deletion(-)
|
|
create mode 100644 t/lib-proto-disable.sh
|
|
create mode 100755 t/t5810-proto-disable-local.sh
|
|
create mode 100755 t/t5811-proto-disable-git.sh
|
|
create mode 100755 t/t5812-proto-disable-http.sh
|
|
create mode 100755 t/t5813-proto-disable-ssh.sh
|
|
create mode 100755 t/t5814-proto-disable-ext.sh
|
|
|
|
Index: git-2.3.0/Documentation/git.txt
|
|
===================================================================
|
|
--- git-2.3.0.orig/Documentation/git.txt
|
|
+++ git-2.3.0/Documentation/git.txt
|
|
@@ -1023,6 +1023,38 @@ GIT_ICASE_PATHSPECS::
|
|
variable when it is invoked as the top level command by the
|
|
end user, to be recorded in the body of the reflog.
|
|
|
|
+`GIT_ALLOW_PROTOCOL`::
|
|
+ If set, provide a colon-separated list of protocols which are
|
|
+ allowed to be used with fetch/push/clone. This is useful to
|
|
+ restrict recursive submodule initialization from an untrusted
|
|
+ repository. Any protocol not mentioned will be disallowed (i.e.,
|
|
+ this is a whitelist, not a blacklist). If the variable is not
|
|
+ set at all, all protocols are enabled. The protocol names
|
|
+ currently used by git are:
|
|
+
|
|
+ - `file`: any local file-based path (including `file://` URLs,
|
|
+ or local paths)
|
|
+
|
|
+ - `git`: the anonymous git protocol over a direct TCP
|
|
+ connection (or proxy, if configured)
|
|
+
|
|
+ - `ssh`: git over ssh (including `host:path` syntax,
|
|
+ `git+ssh://`, etc).
|
|
+
|
|
+ - `rsync`: git over rsync
|
|
+
|
|
+ - `http`: git over http, both "smart http" and "dumb http".
|
|
+ Note that this does _not_ include `https`; if you want both,
|
|
+ you should specify both as `http:https`.
|
|
+
|
|
+ - any external helpers are named by their protocol (e.g., use
|
|
+ `hg` to allow the `git-remote-hg` helper)
|
|
++
|
|
+Note that this controls only git's internal protocol selection.
|
|
+If libcurl is used (e.g., by the `http` transport), it may
|
|
+redirect to other protocols. There is not currently any way to
|
|
+restrict this.
|
|
+
|
|
|
|
Discussion[[Discussion]]
|
|
------------------------
|
|
Index: git-2.3.0/connect.c
|
|
===================================================================
|
|
--- git-2.3.0.orig/connect.c
|
|
+++ git-2.3.0/connect.c
|
|
@@ -9,6 +9,7 @@
|
|
#include "url.h"
|
|
#include "string-list.h"
|
|
#include "sha1-array.h"
|
|
+#include "transport.h"
|
|
|
|
static char *server_capabilities;
|
|
static const char *parse_feature_value(const char *, const char *, int *);
|
|
@@ -674,6 +675,9 @@ struct child_process *git_connect(int fd
|
|
* cannot connect.
|
|
*/
|
|
char *target_host = xstrdup(hostandport);
|
|
+
|
|
+ transport_check_allowed("git");
|
|
+
|
|
if (git_use_proxy(hostandport))
|
|
conn = git_proxy_connect(fd, hostandport);
|
|
else
|
|
@@ -704,6 +708,7 @@ struct child_process *git_connect(int fd
|
|
int putty;
|
|
char *ssh_host = hostandport;
|
|
const char *port = NULL;
|
|
+ transport_check_allowed("ssh");
|
|
get_host_and_port(&ssh_host, &port);
|
|
port = get_port_numeric(port);
|
|
|
|
@@ -731,6 +736,7 @@ struct child_process *git_connect(int fd
|
|
/* remove repo-local variables from the environment */
|
|
conn->env = local_repo_env;
|
|
conn->use_shell = 1;
|
|
+ transport_check_allowed("file");
|
|
}
|
|
argv_array_push(&conn->args, cmd.buf);
|
|
|
|
Index: git-2.3.0/t/lib-proto-disable.sh
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ git-2.3.0/t/lib-proto-disable.sh
|
|
@@ -0,0 +1,96 @@
|
|
+# Test routines for checking protocol disabling.
|
|
+
|
|
+# test cloning a particular protocol
|
|
+# $1 - description of the protocol
|
|
+# $2 - machine-readable name of the protocol
|
|
+# $3 - the URL to try cloning
|
|
+test_proto () {
|
|
+ desc=$1
|
|
+ proto=$2
|
|
+ url=$3
|
|
+
|
|
+ test_expect_success "clone $1 (enabled)" '
|
|
+ rm -rf tmp.git &&
|
|
+ (
|
|
+ GIT_ALLOW_PROTOCOL=$proto &&
|
|
+ export GIT_ALLOW_PROTOCOL &&
|
|
+ git clone --bare "$url" tmp.git
|
|
+ )
|
|
+ '
|
|
+
|
|
+ test_expect_success "fetch $1 (enabled)" '
|
|
+ (
|
|
+ cd tmp.git &&
|
|
+ GIT_ALLOW_PROTOCOL=$proto &&
|
|
+ export GIT_ALLOW_PROTOCOL &&
|
|
+ git fetch
|
|
+ )
|
|
+ '
|
|
+
|
|
+ test_expect_success "push $1 (enabled)" '
|
|
+ (
|
|
+ cd tmp.git &&
|
|
+ GIT_ALLOW_PROTOCOL=$proto &&
|
|
+ export GIT_ALLOW_PROTOCOL &&
|
|
+ git push origin HEAD:pushed
|
|
+ )
|
|
+ '
|
|
+
|
|
+ test_expect_success "push $1 (disabled)" '
|
|
+ (
|
|
+ cd tmp.git &&
|
|
+ GIT_ALLOW_PROTOCOL=none &&
|
|
+ export GIT_ALLOW_PROTOCOL &&
|
|
+ test_must_fail git push origin HEAD:pushed
|
|
+ )
|
|
+ '
|
|
+
|
|
+ test_expect_success "fetch $1 (disabled)" '
|
|
+ (
|
|
+ cd tmp.git &&
|
|
+ GIT_ALLOW_PROTOCOL=none &&
|
|
+ export GIT_ALLOW_PROTOCOL &&
|
|
+ test_must_fail git fetch
|
|
+ )
|
|
+ '
|
|
+
|
|
+ test_expect_success "clone $1 (disabled)" '
|
|
+ rm -rf tmp.git &&
|
|
+ (
|
|
+ GIT_ALLOW_PROTOCOL=none &&
|
|
+ export GIT_ALLOW_PROTOCOL &&
|
|
+ test_must_fail git clone --bare "$url" tmp.git
|
|
+ )
|
|
+ '
|
|
+}
|
|
+
|
|
+# set up an ssh wrapper that will access $host/$repo in the
|
|
+# trash directory, and enable it for subsequent tests.
|
|
+setup_ssh_wrapper () {
|
|
+ test_expect_success 'setup ssh wrapper' '
|
|
+ write_script ssh-wrapper <<-\EOF &&
|
|
+ echo >&2 "ssh: $*"
|
|
+ host=$1; shift
|
|
+ cd "$TRASH_DIRECTORY/$host" &&
|
|
+ eval "$*"
|
|
+ EOF
|
|
+ GIT_SSH="$PWD/ssh-wrapper" &&
|
|
+ export GIT_SSH &&
|
|
+ export TRASH_DIRECTORY
|
|
+ '
|
|
+}
|
|
+
|
|
+# set up a wrapper that can be used with remote-ext to
|
|
+# access repositories in the "remote" directory of trash-dir,
|
|
+# like "ext::fake-remote %S repo.git"
|
|
+setup_ext_wrapper () {
|
|
+ test_expect_success 'setup ext wrapper' '
|
|
+ write_script fake-remote <<-\EOF &&
|
|
+ echo >&2 "fake-remote: $*"
|
|
+ cd "$TRASH_DIRECTORY/remote" &&
|
|
+ eval "$*"
|
|
+ EOF
|
|
+ PATH=$TRASH_DIRECTORY:$PATH &&
|
|
+ export TRASH_DIRECTORY
|
|
+ '
|
|
+}
|
|
Index: git-2.3.0/t/t5810-proto-disable-local.sh
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ git-2.3.0/t/t5810-proto-disable-local.sh
|
|
@@ -0,0 +1,14 @@
|
|
+#!/bin/sh
|
|
+
|
|
+test_description='test disabling of local paths in clone/fetch'
|
|
+. ./test-lib.sh
|
|
+. "$TEST_DIRECTORY/lib-proto-disable.sh"
|
|
+
|
|
+test_expect_success 'setup repository to clone' '
|
|
+ test_commit one
|
|
+'
|
|
+
|
|
+test_proto "file://" file "file://$PWD"
|
|
+test_proto "path" file .
|
|
+
|
|
+test_done
|
|
Index: git-2.3.0/t/t5811-proto-disable-git.sh
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ git-2.3.0/t/t5811-proto-disable-git.sh
|
|
@@ -0,0 +1,20 @@
|
|
+#!/bin/sh
|
|
+
|
|
+test_description='test disabling of git-over-tcp in clone/fetch'
|
|
+. ./test-lib.sh
|
|
+. "$TEST_DIRECTORY/lib-proto-disable.sh"
|
|
+. "$TEST_DIRECTORY/lib-git-daemon.sh"
|
|
+start_git_daemon
|
|
+
|
|
+test_expect_success 'create git-accessible repo' '
|
|
+ bare="$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
|
|
+ test_commit one &&
|
|
+ git --bare init "$bare" &&
|
|
+ git push "$bare" HEAD &&
|
|
+ >"$bare/git-daemon-export-ok" &&
|
|
+ git -C "$bare" config daemon.receivepack true
|
|
+'
|
|
+
|
|
+test_proto "git://" git "$GIT_DAEMON_URL/repo.git"
|
|
+
|
|
+test_done
|
|
Index: git-2.3.0/t/t5812-proto-disable-http.sh
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ git-2.3.0/t/t5812-proto-disable-http.sh
|
|
@@ -0,0 +1,20 @@
|
|
+#!/bin/sh
|
|
+
|
|
+test_description='test disabling of git-over-http in clone/fetch'
|
|
+. ./test-lib.sh
|
|
+. "$TEST_DIRECTORY/lib-proto-disable.sh"
|
|
+. "$TEST_DIRECTORY/lib-httpd.sh"
|
|
+start_httpd
|
|
+
|
|
+test_expect_success 'create git-accessible repo' '
|
|
+ bare="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
|
|
+ test_commit one &&
|
|
+ git --bare init "$bare" &&
|
|
+ git push "$bare" HEAD &&
|
|
+ git -C "$bare" config http.receivepack true
|
|
+'
|
|
+
|
|
+test_proto "smart http" http "$HTTPD_URL/smart/repo.git"
|
|
+
|
|
+stop_httpd
|
|
+test_done
|
|
Index: git-2.3.0/t/t5813-proto-disable-ssh.sh
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ git-2.3.0/t/t5813-proto-disable-ssh.sh
|
|
@@ -0,0 +1,20 @@
|
|
+#!/bin/sh
|
|
+
|
|
+test_description='test disabling of git-over-ssh in clone/fetch'
|
|
+. ./test-lib.sh
|
|
+. "$TEST_DIRECTORY/lib-proto-disable.sh"
|
|
+
|
|
+setup_ssh_wrapper
|
|
+
|
|
+test_expect_success 'setup repository to clone' '
|
|
+ test_commit one &&
|
|
+ mkdir remote &&
|
|
+ git init --bare remote/repo.git &&
|
|
+ git push remote/repo.git HEAD
|
|
+'
|
|
+
|
|
+test_proto "host:path" ssh "remote:repo.git"
|
|
+test_proto "ssh://" ssh "ssh://remote/$PWD/remote/repo.git"
|
|
+test_proto "git+ssh://" ssh "git+ssh://remote/$PWD/remote/repo.git"
|
|
+
|
|
+test_done
|
|
Index: git-2.3.0/t/t5814-proto-disable-ext.sh
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ git-2.3.0/t/t5814-proto-disable-ext.sh
|
|
@@ -0,0 +1,18 @@
|
|
+#!/bin/sh
|
|
+
|
|
+test_description='test disabling of remote-helper paths in clone/fetch'
|
|
+. ./test-lib.sh
|
|
+. "$TEST_DIRECTORY/lib-proto-disable.sh"
|
|
+
|
|
+setup_ext_wrapper
|
|
+
|
|
+test_expect_success 'setup repository to clone' '
|
|
+ test_commit one &&
|
|
+ mkdir remote &&
|
|
+ git init --bare remote/repo.git &&
|
|
+ git push remote/repo.git HEAD
|
|
+'
|
|
+
|
|
+test_proto "remote-helper" ext "ext::fake-remote %S repo.git"
|
|
+
|
|
+test_done
|
|
Index: git-2.3.0/transport-helper.c
|
|
===================================================================
|
|
--- git-2.3.0.orig/transport-helper.c
|
|
+++ git-2.3.0/transport-helper.c
|
|
@@ -1036,6 +1036,8 @@ int transport_helper_init(struct transpo
|
|
struct helper_data *data = xcalloc(1, sizeof(*data));
|
|
data->name = name;
|
|
|
|
+ transport_check_allowed(name);
|
|
+
|
|
if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
|
|
debug = 1;
|
|
|
|
Index: git-2.3.0/transport.c
|
|
===================================================================
|
|
--- git-2.3.0.orig/transport.c
|
|
+++ git-2.3.0/transport.c
|
|
@@ -907,6 +907,20 @@ static int external_specification_len(co
|
|
return strchr(url, ':') - url;
|
|
}
|
|
|
|
+void transport_check_allowed(const char *type)
|
|
+{
|
|
+ struct string_list allowed = STRING_LIST_INIT_DUP;
|
|
+ const char *v = getenv("GIT_ALLOW_PROTOCOL");
|
|
+
|
|
+ if (!v)
|
|
+ return;
|
|
+
|
|
+ string_list_split(&allowed, v, ':', -1);
|
|
+ if (!unsorted_string_list_has_string(&allowed, type))
|
|
+ die("transport '%s' not allowed", type);
|
|
+ string_list_clear(&allowed, 0);
|
|
+}
|
|
+
|
|
struct transport *transport_get(struct remote *remote, const char *url)
|
|
{
|
|
const char *helper;
|
|
@@ -938,12 +952,14 @@ struct transport *transport_get(struct r
|
|
if (helper) {
|
|
transport_helper_init(ret, helper);
|
|
} else if (starts_with(url, "rsync:")) {
|
|
+ transport_check_allowed("rsync");
|
|
ret->get_refs_list = get_refs_via_rsync;
|
|
ret->fetch = fetch_objs_via_rsync;
|
|
ret->push = rsync_transport_push;
|
|
ret->smart_options = NULL;
|
|
} else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
|
|
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
|
|
+ transport_check_allowed("file");
|
|
ret->data = data;
|
|
ret->get_refs_list = get_refs_from_bundle;
|
|
ret->fetch = fetch_refs_from_bundle;
|
|
@@ -955,7 +971,10 @@ struct transport *transport_get(struct r
|
|
|| starts_with(url, "ssh://")
|
|
|| starts_with(url, "git+ssh://")
|
|
|| starts_with(url, "ssh+git://")) {
|
|
- /* These are builtin smart transports. */
|
|
+ /*
|
|
+ * These are builtin smart transports; "allowed" transports
|
|
+ * will be checked individually in git_connect.
|
|
+ */
|
|
struct git_transport_data *data = xcalloc(1, sizeof(*data));
|
|
ret->data = data;
|
|
ret->set_option = NULL;
|
|
Index: git-2.3.0/transport.h
|
|
===================================================================
|
|
--- git-2.3.0.orig/transport.h
|
|
+++ git-2.3.0/transport.h
|
|
@@ -132,6 +132,13 @@ struct transport {
|
|
/* Returns a transport suitable for the url */
|
|
struct transport *transport_get(struct remote *, const char *);
|
|
|
|
+/*
|
|
+ * Check whether a transport is allowed by the environment,
|
|
+ * and die otherwise. type should generally be the URL scheme,
|
|
+ * as described in Documentation/git.txt
|
|
+ */
|
|
+void transport_check_allowed(const char *type);
|
|
+
|
|
/* Transport options which apply to git:// and scp-style URLs */
|
|
|
|
/* The program to use on the remote side to send a pack */
|