Skip to content

Commit f2df310

Browse files
committed
Merge branch 'jk/transfer-limit-redirection' into maint-2.3
2 parents df37727 + b258116 commit f2df310

File tree

6 files changed

+78
-15
lines changed

6 files changed

+78
-15
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: 18 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");
@@ -350,11 +352,27 @@ static CURL *get_curl_handle(void)
350352
}
351353

352354
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
355+
curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20);
353356
#if LIBCURL_VERSION_NUM >= 0x071301
354357
curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
355358
#elif LIBCURL_VERSION_NUM >= 0x071101
356359
curl_easy_setopt(result, CURLOPT_POST301, 1);
357360
#endif
361+
#if LIBCURL_VERSION_NUM >= 0x071304
362+
if (is_transport_allowed("http"))
363+
allowed_protocols |= CURLPROTO_HTTP;
364+
if (is_transport_allowed("https"))
365+
allowed_protocols |= CURLPROTO_HTTPS;
366+
if (is_transport_allowed("ftp"))
367+
allowed_protocols |= CURLPROTO_FTP;
368+
if (is_transport_allowed("ftps"))
369+
allowed_protocols |= CURLPROTO_FTPS;
370+
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols);
371+
#else
372+
if (transport_restrict_protocols())
373+
warning("protocol restrictions not applied to curl redirects because\n"
374+
"your curl version is too old (>= 7.19.4)");
375+
#endif
358376

359377
if (getenv("GIT_CURL_VERBOSE"))
360378
curl_easy_setopt(result, CURLOPT_VERBOSE, 1);

t/lib-httpd/apache.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ 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]
123+
124+
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]
125+
RewriteRule ^/loop-redir/(.*)$ /loop-redir/x-$1 [R=302]
122126

123127
<IfDefine SSL>
124128
LoadModule ssl_module modules/mod_ssl.so

t/t5812-proto-disable-http.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,18 @@ 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+
28+
test_expect_success 'curl limits redirects' '
29+
test_must_fail git clone "$HTTPD_URL/loop-redir/smart/repo.git"
30+
'
31+
1932
stop_httpd
2033
test_done

transport.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -909,18 +909,40 @@ static int external_specification_len(const char *url)
909909
return strchr(url, ':') - url;
910910
}
911911

912-
void transport_check_allowed(const char *type)
912+
static const struct string_list *protocol_whitelist(void)
913913
{
914-
struct string_list allowed = STRING_LIST_INIT_DUP;
915-
const char *v = getenv("GIT_ALLOW_PROTOCOL");
914+
static int enabled = -1;
915+
static struct string_list allowed = STRING_LIST_INIT_DUP;
916+
917+
if (enabled < 0) {
918+
const char *v = getenv("GIT_ALLOW_PROTOCOL");
919+
if (v) {
920+
string_list_split(&allowed, v, ':', -1);
921+
string_list_sort(&allowed);
922+
enabled = 1;
923+
} else {
924+
enabled = 0;
925+
}
926+
}
916927

917-
if (!v)
918-
return;
928+
return enabled ? &allowed : NULL;
929+
}
930+
931+
int is_transport_allowed(const char *type)
932+
{
933+
const struct string_list *allowed = protocol_whitelist();
934+
return !allowed || string_list_has_string(allowed, type);
935+
}
919936

920-
string_list_split(&allowed, v, ':', -1);
921-
if (!unsorted_string_list_has_string(&allowed, type))
937+
void transport_check_allowed(const char *type)
938+
{
939+
if (!is_transport_allowed(type))
922940
die("transport '%s' not allowed", type);
923-
string_list_clear(&allowed, 0);
941+
}
942+
943+
int transport_restrict_protocols(void)
944+
{
945+
return !!protocol_whitelist();
924946
}
925947

926948
struct transport *transport_get(struct remote *remote, const char *url)

transport.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,24 @@ struct transport {
132132
/* Returns a transport suitable for the url */
133133
struct transport *transport_get(struct remote *, const char *);
134134

135+
/*
136+
* Check whether a transport is allowed by the environment. Type should
137+
* generally be the URL scheme, as described in Documentation/git.txt
138+
*/
139+
int is_transport_allowed(const char *type);
140+
135141
/*
136142
* Check whether a transport is allowed by the environment,
137-
* and die otherwise. type should generally be the URL scheme,
138-
* as described in Documentation/git.txt
143+
* and die otherwise.
139144
*/
140145
void transport_check_allowed(const char *type);
141146

147+
/*
148+
* Returns true if the user has attempted to turn on protocol
149+
* restrictions at all.
150+
*/
151+
int transport_restrict_protocols(void);
152+
142153
/* Transport options which apply to git:// and scp-style URLs */
143154

144155
/* The program to use on the remote side to send a pack */

0 commit comments

Comments
 (0)