Skip to content

Commit f4113ca

Browse files
bburkygitster
authored andcommitted
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 protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5088d3b commit f4113ca

File tree

4 files changed

+27
-5
lines changed

4 files changed

+27
-5
lines changed

Documentation/git.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,11 +1071,6 @@ GIT_ICASE_PATHSPECS::
10711071

10721072
- any external helpers are named by their protocol (e.g., use
10731073
`hg` to allow the `git-remote-hg` helper)
1074-
+
1075-
Note that this controls only git's internal protocol selection.
1076-
If libcurl is used (e.g., by the `http` transport), it may
1077-
redirect to other protocols. There is not currently any way to
1078-
restrict this.
10791074

10801075

10811076
Discussion[[Discussion]]

http.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "credential.h"
99
#include "version.h"
1010
#include "pkt-line.h"
11+
#include "transport.h"
1112

1213
int active_requests;
1314
int http_is_verbose;
@@ -303,6 +304,7 @@ static void set_curl_keepalive(CURL *c)
303304
static CURL *get_curl_handle(void)
304305
{
305306
CURL *result = curl_easy_init();
307+
long allowed_protocols = 0;
306308

307309
if (!result)
308310
die("curl_easy_init failed");
@@ -355,6 +357,21 @@ static CURL *get_curl_handle(void)
355357
#elif LIBCURL_VERSION_NUM >= 0x071101
356358
curl_easy_setopt(result, CURLOPT_POST301, 1);
357359
#endif
360+
#if LIBCURL_VERSION_NUM >= 0x071304
361+
if (is_transport_allowed("http"))
362+
allowed_protocols |= CURLPROTO_HTTP;
363+
if (is_transport_allowed("https"))
364+
allowed_protocols |= CURLPROTO_HTTPS;
365+
if (is_transport_allowed("ftp"))
366+
allowed_protocols |= CURLPROTO_FTP;
367+
if (is_transport_allowed("ftps"))
368+
allowed_protocols |= CURLPROTO_FTPS;
369+
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols);
370+
#else
371+
if (transport_restrict_protocols())
372+
warning("protocol restrictions not applied to curl redirects because\n"
373+
"your curl version is too old (>= 7.19.4)");
374+
#endif
358375

359376
if (getenv("GIT_CURL_VERBOSE"))
360377
curl_easy_setopt(result, CURLOPT_VERBOSE, 1);

t/lib-httpd/apache.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ RewriteRule ^/smart-redir-perm/(.*)$ /smart/$1 [R=301]
119119
RewriteRule ^/smart-redir-temp/(.*)$ /smart/$1 [R=302]
120120
RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301]
121121
RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301]
122+
RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302]
122123

123124
<IfDefine SSL>
124125
LoadModule ssl_module modules/mod_ssl.so

t/t5812-proto-disable-http.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,14 @@ test_expect_success 'create git-accessible repo' '
1616

1717
test_proto "smart http" http "$HTTPD_URL/smart/repo.git"
1818

19+
test_expect_success 'curl redirects respect whitelist' '
20+
test_must_fail env GIT_ALLOW_PROTOCOL=http:https \
21+
git clone "$HTTPD_URL/ftp-redir/repo.git" 2>stderr &&
22+
{
23+
test_i18ngrep "ftp.*disabled" stderr ||
24+
test_i18ngrep "your curl version is too old"
25+
}
26+
'
27+
1928
stop_httpd
2029
test_done

0 commit comments

Comments
 (0)