~alpine/aports

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch

[alpine-aports] [PATCH v3.1] main/git: security upgrade - fixes #5005

Details
Message ID
<1481812984-12782-1-git-send-email-sergej.lukin@gmail.com>
Sender timestamp
1481812984
DKIM signature
missing
Download raw message
Patch: +845 -4
CVE-2015-7545
---
 main/git/APKBUILD                   |  29 ++-
 main/git/CVE-2015-7545-patch1.patch | 427 ++++++++++++++++++++++++++++++++++++
 main/git/CVE-2015-7545-patch2.patch | 100 +++++++++
 main/git/CVE-2015-7545-patch3.patch | 101 +++++++++
 main/git/CVE-2015-7545-patch4.patch | 135 ++++++++++++
 main/git/CVE-2015-7545-patch5.patch |  57 +++++
 6 files changed, 845 insertions(+), 4 deletions(-)
 create mode 100644 main/git/CVE-2015-7545-patch1.patch
 create mode 100644 main/git/CVE-2015-7545-patch2.patch
 create mode 100644 main/git/CVE-2015-7545-patch3.patch
 create mode 100644 main/git/CVE-2015-7545-patch4.patch
 create mode 100644 main/git/CVE-2015-7545-patch5.patch

diff --git a/main/git/APKBUILD b/main/git/APKBUILD
index 37299ed..2fec308 100644
--- a/main/git/APKBUILD
+++ b/main/git/APKBUILD
@@ -1,7 +1,8 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
# Contributor: Sergey Lukin <sergej.lukin@gmail.com>
pkgname=git
pkgver=2.2.1
pkgrel=0
pkgrel=1
pkgdesc="A distributed version control system"
url="http://git.or.cz/"
arch="all"
@@ -31,6 +32,11 @@ source="git-$pkgver.tar.gz::https://github.com/git/git/archive/v$pkgver.tar.gz
	bb-tar.patch
	git-daemon.initd
	git-daemon.confd
	CVE-2015-7545-patch1.patch
	CVE-2015-7545-patch2.patch
	CVE-2015-7545-patch3.patch
	CVE-2015-7545-patch4.patch
	CVE-2015-7545-patch5.patch
	"

_makeopts="
@@ -203,12 +209,27 @@ _git_perl() {
md5sums="d1110e35369bc37aa204915f64c5d1c8  git-2.2.1.tar.gz
e63a201556c4f089de790805c09a2e5b  bb-tar.patch
53546650670c0ab8858e91474e5ffee9  git-daemon.initd
2258e95d389ccc6de0b5111d53d9eed6  git-daemon.confd"
2258e95d389ccc6de0b5111d53d9eed6  git-daemon.confd
33f105ea489d55f9cece57deed8a27bd  CVE-2015-7545-patch1.patch
2e666466fb83c3b9af065142d410408f  CVE-2015-7545-patch2.patch
08199293b22e258492f3f35ff1245c22  CVE-2015-7545-patch3.patch
84af0023dff4e7f5cbd9da708a296e90  CVE-2015-7545-patch4.patch
0c8c2b7f681c335d405aeedf9f8401e6  CVE-2015-7545-patch5.patch"
sha256sums="aca76e204d2ad3ea783f5309261dc5fcadbd7a996afd841bdb7bf4a29658c067  git-2.2.1.tar.gz
cb6319f47d81605e199771350154cbed0a6e85ef9042a689f2b405c64039f49c  bb-tar.patch
817cd58dcb9a5ff32759d2132bb805a5dd34ad6fa0b0a5cbe4ab8786f3b7c0d9  git-daemon.initd
aaa80bd059db549dadf4c4e27a9aa41a4b5def844f8e563c493bc8513dcd981e  git-daemon.confd"
aaa80bd059db549dadf4c4e27a9aa41a4b5def844f8e563c493bc8513dcd981e  git-daemon.confd
aeae9d25df30a59e15f30c6047bb627de120cab1c724558140941514ae782229  CVE-2015-7545-patch1.patch
d34690d72179773a6b1769ea3a85ab91d17e7ba6f38abec683d911c598dd12fb  CVE-2015-7545-patch2.patch
ab5a8070e6c47bb6d7d553c3f7f12e864490b6cd139b2e03e04b9cffac7bd358  CVE-2015-7545-patch3.patch
cf75d74b185fa2bf5bcfd33764ea6cd6ec66a072182def4d34493a4a4b69d1ed  CVE-2015-7545-patch4.patch
2f23f815b4508edf1f39293de31b2874b1702fe79f3b45954bd2125b9fb2131a  CVE-2015-7545-patch5.patch"
sha512sums="b723dff750b8fad34b7268158c74f17a403ebc4358944b0c2986922090366e87840d6d3bd14b4574f63157acd1b69799715fbbe7decd70fa4edc18b1584a8ae8  git-2.2.1.tar.gz
6fa088a753c2a697e8dbef2032ed63e8c2a0553a41cff2fcff893c2f35c51d2c697054cc921c23ee606f77b93d0f340df85220b15e1c470bd352f7fba3986cd0  bb-tar.patch
47f35d1553408236502f936d0ce5dbc6c44b6593ad5ef9ddebbfd8dbca5f968c21452df7053ac271445830d36a147a7124e2ea1cf9fb98340d975fdb0346011a  git-daemon.initd
9640f8078d68ed2678e5249da3f946fc21f50e858b94127a4221de73c6132101afcd46bc1fe33861e9a7f731c0dc9591915b8ebf376b8e690cd7135703966509  git-daemon.confd"
9640f8078d68ed2678e5249da3f946fc21f50e858b94127a4221de73c6132101afcd46bc1fe33861e9a7f731c0dc9591915b8ebf376b8e690cd7135703966509  git-daemon.confd
f1db673f02a685cc27c8272bf5debe912e1a46fce49196f946df84678f778939f5789c6964c9fb74f2f604ebf8f51a3b9e859a6e26818110febef4413697b8c0  CVE-2015-7545-patch1.patch
ec985321aa9aa7bc157f965f2f40c622855578c6e25fa7f05cf1e865820b22b6a159751c1cf8591226a3de35476d1df0275ae468d93e0c6d3db2447f4820f2ed  CVE-2015-7545-patch2.patch
8a0b6ee85c33fc6012afd4b7677f698423ddf7a4e97c0008af288d716bc884f28f057e7ea000e548311699a779b7b84c3c6ab792f9f8ebc91c99d01691b25cde  CVE-2015-7545-patch3.patch
07d474f08dd338a7a36dff84274973f49350724d422aa3e5f2cb192a4d6bbd942176567623580a8dcfc309a3c656f6838303fd6aae0820173ee989c98114904e  CVE-2015-7545-patch4.patch
feb4be2594cca6a9fc34633fca75389bfbf6230e22d697b54c2c02d24586407d717b9173ad5942d3e9652c7c3dc14c3d6cf08d33ed26d0e94cd46c06bd28be96  CVE-2015-7545-patch5.patch"
diff --git a/main/git/CVE-2015-7545-patch1.patch b/main/git/CVE-2015-7545-patch1.patch
new file mode 100644
index 0000000..4cf9483
--- /dev/null
+++ b/main/git/CVE-2015-7545-patch1.patch
@@ -0,0 +1,427 @@
commit a5adaced2e13c135d5d9cc65be9eb95aa3bacedf
Author: Jeff King <peff@peff.net>
Date:   Wed Sep 16 13:12:52 2015 -0400

    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>

diff --git a/Documentation/git.txt b/Documentation/git.txt
index a62ed6f..b6a12b3 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -1045,6 +1045,38 @@ GIT_ICASE_PATHSPECS::
 	an operation has touched every ref (e.g., because you are
 	cloning a repository to make a backup).
 
+`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]]
 ------------------------
diff --git a/connect.c b/connect.c
index 14c924b..bd4b50e 100644
--- a/connect.c
+++ b/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 *);
@@ -694,6 +695,9 @@ struct child_process *git_connect(int fd[2], const char *url,
 		* cannot connect.
 		*/
 		char *target_host = xstrdup(hostandport);
+
+		transport_check_allowed("git");
+
 		if (git_use_proxy(hostandport))
 			conn = git_proxy_connect(fd, hostandport);
 		else
@@ -727,6 +730,7 @@ struct child_process *git_connect(int fd[2], const char *url,
 			int putty;
 			char *ssh_host = hostandport;
 			const char *port = NULL;
+			transport_check_allowed("ssh");
 			get_host_and_port(&ssh_host, &port);
 
 			if (!port)
@@ -768,6 +772,7 @@ struct child_process *git_connect(int fd[2], const char *url,
 			/* 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);
 
diff --git a/t/lib-proto-disable.sh b/t/lib-proto-disable.sh
new file mode 100644
index 0000000..b0917d9
--- /dev/null
+++ b/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
+	'
+}
diff --git a/t/t5810-proto-disable-local.sh b/t/t5810-proto-disable-local.sh
new file mode 100755
index 0000000..563592d
--- /dev/null
+++ b/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
diff --git a/t/t5811-proto-disable-git.sh b/t/t5811-proto-disable-git.sh
new file mode 100755
index 0000000..8ac6b2a
--- /dev/null
+++ b/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
diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh
new file mode 100755
index 0000000..dd5001c
--- /dev/null
+++ b/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
diff --git a/t/t5813-proto-disable-ssh.sh b/t/t5813-proto-disable-ssh.sh
new file mode 100755
index 0000000..ad877d7
--- /dev/null
+++ b/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
diff --git a/t/t5814-proto-disable-ext.sh b/t/t5814-proto-disable-ext.sh
new file mode 100755
index 0000000..9d6f7df
--- /dev/null
+++ b/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
diff --git a/transport-helper.c b/transport-helper.c
index 7dc4a44..0b5362c 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -1038,6 +1038,8 @@ int transport_helper_init(struct transport *transport, const char *name)
 	struct helper_data *data = xcalloc(1, sizeof(*data));
 	data->name = name;
 
+	transport_check_allowed(name);
+
 	if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
 		debug = 1;
 
diff --git a/transport.c b/transport.c
index 88bde1d..94fe865 100644
--- a/transport.c
+++ b/transport.c
@@ -909,6 +909,20 @@ static int external_specification_len(const char *url)
 	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;
@@ -940,12 +954,14 @@ struct transport *transport_get(struct remote *remote, const char *url)
 	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;
@@ -957,7 +973,10 @@ struct transport *transport_get(struct remote *remote, const char *url)
 		|| 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;
diff --git a/transport.h b/transport.h
index 3e0091e..f7df6ec 100644
--- a/transport.h
+++ b/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 */
diff --git a/main/git/CVE-2015-7545-patch2.patch b/main/git/CVE-2015-7545-patch2.patch
new file mode 100644
index 0000000..7a6be12
--- /dev/null
+++ b/main/git/CVE-2015-7545-patch2.patch
@@ -0,0 +1,100 @@
commit 33cfccbbf35a56e190b79bdec5c85457c952a021
Author: Jeff King <peff@peff.net>
Date:   Wed Sep 16 13:13:12 2015 -0400

    submodule: allow only certain protocols for submodule fetches
    
    Some protocols (like git-remote-ext) can execute arbitrary
    code found in the URL. The URLs that submodules use may come
    from arbitrary sources (e.g., .gitmodules files in a remote
    repository). Let's restrict submodules to fetching from a
    known-good subset of protocols.
    
    Note that we apply this restriction to all submodule
    commands, whether the URL comes from .gitmodules or not.
    This is more restrictive than we need to be; for example, in
    the tests we run:
    
      git submodule add ext::...
    
    which should be trusted, as the URL comes directly from the
    command line provided by the user. But doing it this way is
    simpler, and makes it much less likely that we would miss a
    case. And since such protocols should be an exception
    (especially because nobody who clones from them will be able
    to update the submodules!), it's not likely to inconvenience
    anyone in practice.
    
    Reported-by: Blake Burkhart <bburky@bburky.com>
    Signed-off-by: Jeff King <peff@peff.net>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

diff --git a/git-submodule.sh b/git-submodule.sh
index 36797c3..78c2740 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -22,6 +22,15 @@ require_work_tree
 wt_prefix=$(git rev-parse --show-prefix)
 cd_to_toplevel
 
+# Restrict ourselves to a vanilla subset of protocols; the URLs
+# we get are under control of a remote repository, and we do not
+# want them kicking off arbitrary git-remote-* programs.
+#
+# If the user has already specified a set of allowed protocols,
+# we assume they know what they're doing and use that instead.
+: ${GIT_ALLOW_PROTOCOL=file:git:http:https:ssh}
+export GIT_ALLOW_PROTOCOL
+
 command=
 branch=
 force=
diff --git a/t/t5815-submodule-protos.sh b/t/t5815-submodule-protos.sh
new file mode 100755
index 0000000..06f55a1
--- /dev/null
+++ b/t/t5815-submodule-protos.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+test_description='test protocol whitelisting with submodules'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-proto-disable.sh
+
+setup_ext_wrapper
+setup_ssh_wrapper
+
+test_expect_success 'setup repository with submodules' '
+	mkdir remote &&
+	git init remote/repo.git &&
+	(cd remote/repo.git && test_commit one) &&
+	# submodule-add should probably trust what we feed it on the cmdline,
+	# but its implementation is overly conservative.
+	GIT_ALLOW_PROTOCOL=ssh git submodule add remote:repo.git ssh-module &&
+	GIT_ALLOW_PROTOCOL=ext git submodule add "ext::fake-remote %S repo.git" ext-module &&
+	git commit -m "add submodules"
+'
+
+test_expect_success 'clone with recurse-submodules fails' '
+	test_must_fail git clone --recurse-submodules . dst
+'
+
+test_expect_success 'setup individual updates' '
+	rm -rf dst &&
+	git clone . dst &&
+	git -C dst submodule init
+'
+
+test_expect_success 'update of ssh allowed' '
+	git -C dst submodule update ssh-module
+'
+
+test_expect_success 'update of ext not allowed' '
+	test_must_fail git -C dst submodule update ext-module
+'
+
+test_expect_success 'user can override whitelist' '
+	GIT_ALLOW_PROTOCOL=ext git -C dst submodule update ext-module
+'
+
+test_done
diff --git a/main/git/CVE-2015-7545-patch3.patch b/main/git/CVE-2015-7545-patch3.patch
new file mode 100644
index 0000000..2df1fdd
--- /dev/null
+++ b/main/git/CVE-2015-7545-patch3.patch
@@ -0,0 +1,101 @@
commit 5088d3b38775f8ac12d7f77636775b16059b67ef
Author: Jeff King <peff@peff.net>
Date:   Tue Sep 22 18:03:49 2015 -0400

    transport: refactor protocol whitelist code
    
    The current callers only want to die when their transport is
    prohibited. But future callers want to query the mechanism
    without dying.
    
    Let's break out a few query functions, and also save the
    results in a static list so we don't have to re-parse for
    each query.
    
    Based-on-a-patch-by: Blake Burkhart <bburky@bburky.com>
    Signed-off-by: Jeff King <peff@peff.net>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

diff --git a/transport.c b/transport.c
index 94fe865..647d2c2 100644
--- a/transport.c
+++ b/transport.c
@@ -909,18 +909,40 @@ static int external_specification_len(const char *url)
 	return strchr(url, ':') - url;
 }
 
-void transport_check_allowed(const char *type)
+static const struct string_list *protocol_whitelist(void)
 {
-	struct string_list allowed = STRING_LIST_INIT_DUP;
-	const char *v = getenv("GIT_ALLOW_PROTOCOL");
+	static int enabled = -1;
+	static struct string_list allowed = STRING_LIST_INIT_DUP;
+
+	if (enabled < 0) {
+		const char *v = getenv("GIT_ALLOW_PROTOCOL");
+		if (v) {
+			string_list_split(&allowed, v, ':', -1);
+			sort_string_list(&allowed);
+			enabled = 1;
+		} else {
+			enabled = 0;
+		}
+	}
 
-	if (!v)
-		return;
+	return enabled ? &allowed : NULL;
+}
+
+int is_transport_allowed(const char *type)
+{
+	const struct string_list *allowed = protocol_whitelist();
+	return !allowed || string_list_has_string(allowed, type);
+}
 
-	string_list_split(&allowed, v, ':', -1);
-	if (!unsorted_string_list_has_string(&allowed, type))
+void transport_check_allowed(const char *type)
+{
+	if (!is_transport_allowed(type))
 		die("transport '%s' not allowed", type);
-	string_list_clear(&allowed, 0);
+}
+
+int transport_restrict_protocols(void)
+{
+	return !!protocol_whitelist();
 }
 
 struct transport *transport_get(struct remote *remote, const char *url)
diff --git a/transport.h b/transport.h
index f7df6ec..ed84da2 100644
--- a/transport.h
+++ b/transport.h
@@ -133,12 +133,23 @@ struct transport {
 struct transport *transport_get(struct remote *, const char *);
 
 /*
+ * Check whether a transport is allowed by the environment. Type should
+ * generally be the URL scheme, as described in Documentation/git.txt
+ */
+int is_transport_allowed(const char *type);
+
+/*
  * 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
+ * and die otherwise.
  */
 void transport_check_allowed(const char *type);
 
+/*
+ * Returns true if the user has attempted to turn on protocol
+ * restrictions at all.
+ */
+int transport_restrict_protocols(void);
+
 /* Transport options which apply to git:// and scp-style URLs */
 
 /* The program to use on the remote side to send a pack */
diff --git a/main/git/CVE-2015-7545-patch4.patch b/main/git/CVE-2015-7545-patch4.patch
new file mode 100644
index 0000000..8e76516
--- /dev/null
+++ b/main/git/CVE-2015-7545-patch4.patch
@@ -0,0 +1,135 @@
commit f4113cac0c88b4f36ee6f3abf3218034440a68e3
Author: Blake Burkhart <bburky@bburky.com>
Date:   Tue Sep 22 18:06:04 2015 -0400

    http: limit redirection to protocol-whitelist
    
    Previously, libcurl would follow redirection to any protocol
    it was compiled for support with. This is desirable to allow
    redirection from HTTP to HTTPS. However, it would even
    successfully allow redirection from HTTP to SFTP, a protocol
    that git does not otherwise support at all. Furthermore
    git's new protocol-whitelisting could be bypassed by
    following a redirect within the remote helper, as it was
    only enforced at transport selection time.
    
    This patch limits redirects within libcurl to HTTP, HTTPS,
    FTP and FTPS. If there is a protocol-whitelist present, this
    list is limited to those also allowed by the whitelist. As
    redirection happens from within libcurl, it is impossible
    for an HTTP redirect to a protocol implemented within
    another remote helper.
    
    When the curl version git was compiled with is too old to
    support restrictions on protocol redirection, we warn the
    user if GIT_ALLOW_PROTOCOL restrictions were requested. This
    is a little inaccurate, as even without that variable in the
    environment, we would still restrict SFTP, etc, and we do
    not warn in that case. But anything else means we would
    literally warn every time git accesses an http remote.
    
    This commit includes a test, but it is not as robust as we
    would hope. It redirects an http request to ftp, and checks
    that curl complained about the protocol, which means that we
    are relying on curl's specific error message to know what
    happened. Ideally we would redirect to a working ftp server
    and confirm that we can clone without protocol restrictions,
    and not with them. But we do not have a portable way of
    providing an ftp server, nor any other protocol that curl
    supports (https is the closest, but we would have to deal
    with certificates).
    
    [jk: added test and version warning]
    
    Signed-off-by: Jeff King <peff@peff.net>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

diff --git a/Documentation/git.txt b/Documentation/git.txt
index b6a12b3..41a09ca 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -1071,11 +1071,6 @@ GIT_ICASE_PATHSPECS::
 
 	  - 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]]
diff --git a/http.c b/http.c
index 6798620..5a57bcc 100644
--- a/http.c
+++ b/http.c
@@ -8,6 +8,7 @@
 #include "credential.h"
 #include "version.h"
 #include "pkt-line.h"
+#include "transport.h"
 
 int active_requests;
 int http_is_verbose;
@@ -303,6 +304,7 @@ static void set_curl_keepalive(CURL *c)
 static CURL *get_curl_handle(void)
 {
 	CURL *result = curl_easy_init();
+	long allowed_protocols = 0;
 
 	if (!result)
 		die("curl_easy_init failed");
@@ -355,6 +357,21 @@ static CURL *get_curl_handle(void)
 #elif LIBCURL_VERSION_NUM >= 0x071101
 	curl_easy_setopt(result, CURLOPT_POST301, 1);
 #endif
+#if LIBCURL_VERSION_NUM >= 0x071304
+	if (is_transport_allowed("http"))
+		allowed_protocols |= CURLPROTO_HTTP;
+	if (is_transport_allowed("https"))
+		allowed_protocols |= CURLPROTO_HTTPS;
+	if (is_transport_allowed("ftp"))
+		allowed_protocols |= CURLPROTO_FTP;
+	if (is_transport_allowed("ftps"))
+		allowed_protocols |= CURLPROTO_FTPS;
+	curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols);
+#else
+	if (transport_restrict_protocols())
+		warning("protocol restrictions not applied to curl redirects because\n"
+			"your curl version is too old (>= 7.19.4)");
+#endif
 
 	if (getenv("GIT_CURL_VERBOSE"))
 		curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 0b81a00..68ef8ad 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -119,6 +119,7 @@ RewriteRule ^/smart-redir-perm/(.*)$ /smart/$1 [R=301]
 RewriteRule ^/smart-redir-temp/(.*)$ /smart/$1 [R=302]
 RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301]
 RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301]
+RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302]
 
 <IfDefine SSL>
 LoadModule ssl_module modules/mod_ssl.so
diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh
index dd5001c..6a4f816 100755
--- a/t/t5812-proto-disable-http.sh
+++ b/t/t5812-proto-disable-http.sh
@@ -16,5 +16,14 @@ test_expect_success 'create git-accessible repo' '
 
 test_proto "smart http" http "$HTTPD_URL/smart/repo.git"
 
+test_expect_success 'curl redirects respect whitelist' '
+	test_must_fail env GIT_ALLOW_PROTOCOL=http:https \
+		git clone "$HTTPD_URL/ftp-redir/repo.git" 2>stderr &&
+	{
+		test_i18ngrep "ftp.*disabled" stderr ||
+		test_i18ngrep "your curl version is too old"
+	}
+'
+
 stop_httpd
 test_done
diff --git a/main/git/CVE-2015-7545-patch5.patch b/main/git/CVE-2015-7545-patch5.patch
new file mode 100644
index 0000000..8845540
--- /dev/null
+++ b/main/git/CVE-2015-7545-patch5.patch
@@ -0,0 +1,57 @@
commit b258116462399b318c86165c61a5c7123043cfd4
Author: Blake Burkhart <bburky@bburky.com>
Date:   Tue Sep 22 18:06:20 2015 -0400

    http: limit redirection depth
    
    By default, libcurl will follow circular http redirects
    forever. Let's put a cap on this so that somebody who can
    trigger an automated fetch of an arbitrary repository (e.g.,
    for CI) cannot convince git to loop infinitely.
    
    The value chosen is 20, which is the same default that
    Firefox uses.
    
    Signed-off-by: Jeff King <peff@peff.net>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

diff --git a/http.c b/http.c
index 5a57bcc..00e3fc8 100644
--- a/http.c
+++ b/http.c
@@ -352,6 +352,7 @@ static CURL *get_curl_handle(void)
 	}
 
 	curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
+	curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20);
 #if LIBCURL_VERSION_NUM >= 0x071301
 	curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
 #elif LIBCURL_VERSION_NUM >= 0x071101
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 68ef8ad..7d15e6d 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -121,6 +121,9 @@ RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301]
 RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301]
 RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302]
 
+RewriteRule ^/loop-redir/x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-(.*) /$1 [R=302]
+RewriteRule ^/loop-redir/(.*)$ /loop-redir/x-$1 [R=302]
+
 <IfDefine SSL>
 LoadModule ssl_module modules/mod_ssl.so
 
diff --git a/t/t5812-proto-disable-http.sh b/t/t5812-proto-disable-http.sh
index 6a4f816..0d105d5 100755
--- a/t/t5812-proto-disable-http.sh
+++ b/t/t5812-proto-disable-http.sh
@@ -25,5 +25,9 @@ test_expect_success 'curl redirects respect whitelist' '
 	}
 '
 
+test_expect_success 'curl limits redirects' '
+	test_must_fail git clone "$HTTPD_URL/loop-redir/smart/repo.git"
+'
+
 stop_httpd
 test_done
-- 
2.2.1



---
Unsubscribe:  alpine-aports+unsubscribe@lists.alpinelinux.org
Help:         alpine-aports+help@lists.alpinelinux.org
---
Reply to thread Export thread (mbox)