Skip to content

Commit 1a3609e

Browse files
committed
fsck: reject URL with empty host in .gitmodules
Git's URL parser interprets https:///example.com/repo.git to have no host and a path of "example.com/repo.git". Curl, on the other hand, internally redirects it to https://example.com/repo.git. As a result, until "credential: parse URL without host as empty host, not unset", tricking a user into fetching from such a URL would cause Git to send credentials for another host to example.com. Teach fsck to block and detect .gitmodules files using such a URL to prevent sharing them with Git versions that are not yet protected. A relative URL in a .gitmodules file could also be used to trigger this. The relative URL resolver used for .gitmodules does not normalize sequences of slashes and can follow ".." components out of the path part and to the host part of a URL, meaning that such a relative URL can be used to traverse from a https://foo.example.com/innocent superproject to a https:///attacker.example.com/exploit submodule. Fortunately, redundant extra slashes in .gitmodules are rare, so we can catch this by detecting one after a leading sequence of "./" and "../" components. Helped-by: Jeff King <[email protected]> Signed-off-by: Jonathan Nieder <[email protected]> Reviewed-by: Jeff King <[email protected]>
1 parent e7fab62 commit 1a3609e

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

fsck.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,17 +1064,21 @@ static int check_submodule_url(const char *url)
10641064
/*
10651065
* URLs which escape their root via "../" can overwrite
10661066
* the host field and previous components, resolving to
1067-
* URLs like https::example.com/submodule.git that were
1067+
* URLs like https::example.com/submodule.git and
1068+
* https:///example.com/submodule.git that were
10681069
* susceptible to CVE-2020-11008.
10691070
*/
10701071
if (count_leading_dotdots(url, &next) > 0 &&
1071-
*next == ':')
1072+
(*next == ':' || *next == '/'))
10721073
return -1;
10731074
}
10741075

10751076
else if (url_to_curl_url(url, &curl_url)) {
10761077
struct credential c = CREDENTIAL_INIT;
1077-
int ret = credential_from_url_gently(&c, curl_url, 1);
1078+
int ret = 0;
1079+
if (credential_from_url_gently(&c, curl_url, 1) ||
1080+
!*c.host)
1081+
ret = -1;
10781082
credential_clear(&c);
10791083
return ret;
10801084
}

t/t7416-submodule-dash-url.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,38 @@ test_expect_success 'fsck rejects relative URL resolving to empty scheme' '
124124
grep gitmodulesUrl err
125125
'
126126

127+
test_expect_success 'fsck rejects empty hostname' '
128+
git checkout --orphan empty-host &&
129+
cat >.gitmodules <<-\EOF &&
130+
[submodule "foo"]
131+
url = http:///one.example.com/foo.git
132+
EOF
133+
git add .gitmodules &&
134+
test_tick &&
135+
git commit -m "gitmodules with extra slashes" &&
136+
test_when_finished "rm -rf dst" &&
137+
git init --bare dst &&
138+
git -C dst config transfer.fsckObjects true &&
139+
test_must_fail git push dst HEAD 2>err &&
140+
grep gitmodulesUrl err
141+
'
142+
143+
test_expect_success 'fsck rejects relative url that produced empty hostname' '
144+
git checkout --orphan messy-relative &&
145+
cat >.gitmodules <<-\EOF &&
146+
[submodule "foo"]
147+
url = ../../..//one.example.com/foo.git
148+
EOF
149+
git add .gitmodules &&
150+
test_tick &&
151+
git commit -m "gitmodules abusing relative_path" &&
152+
test_when_finished "rm -rf dst" &&
153+
git init --bare dst &&
154+
git -C dst config transfer.fsckObjects true &&
155+
test_must_fail git push dst HEAD 2>err &&
156+
grep gitmodulesUrl err
157+
'
158+
127159
test_expect_success 'fsck permits embedded newline with unrecognized scheme' '
128160
git checkout --orphan newscheme &&
129161
cat >.gitmodules <<-\EOF &&

0 commit comments

Comments
 (0)