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

From: Sergey Lukin <[email-masked]>
Date: Thu, 15 Dec 2016 14:43:04 +0000

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 <[email-masked]>
+# Contributor: Sergey Lukin <[email-masked]>
 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 <[email-masked]>
+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 <[email-masked]>
+    Signed-off-by: Junio C Hamano <[email-masked]>
+
+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 <[email-masked]>
+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 <[email-masked]>
+    Signed-off-by: Jeff King <[email-masked]>
+    Signed-off-by: Junio C Hamano <[email-masked]>
+
+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 <[email-masked]>
+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 <[email-masked]>
+    Signed-off-by: Jeff King <[email-masked]>
+    Signed-off-by: Junio C Hamano <[email-masked]>
+
+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 <[email-masked]>
+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 <[email-masked]>
+    Signed-off-by: Junio C Hamano <[email-masked]>
+
+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 <[email-masked]>
+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 <[email-masked]>
+    Signed-off-by: Junio C Hamano <[email-masked]>
+
+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:  [email-masked]
Help:         [email-masked]
---