diff options
Diffstat (limited to 'meta/recipes-devtools/git/git/CVE-2020-11008-7.patch')
-rw-r--r-- | meta/recipes-devtools/git/git/CVE-2020-11008-7.patch | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/meta/recipes-devtools/git/git/CVE-2020-11008-7.patch b/meta/recipes-devtools/git/git/CVE-2020-11008-7.patch new file mode 100644 index 0000000000..5e3b6f1454 --- /dev/null +++ b/meta/recipes-devtools/git/git/CVE-2020-11008-7.patch | |||
@@ -0,0 +1,206 @@ | |||
1 | From 68acf8724e9cb2f67664dd980581c0022401daf0 Mon Sep 17 00:00:00 2001 | ||
2 | From: Jonathan Nieder <jrnieder@gmail.com> | ||
3 | Date: Sat, 18 Apr 2020 20:54:13 -0700 | ||
4 | Subject: [PATCH 10/12] credential: treat URL without scheme as invalid | ||
5 | |||
6 | libcurl permits making requests without a URL scheme specified. In | ||
7 | this case, it guesses the URL from the hostname, so I can run | ||
8 | |||
9 | git ls-remote http::ftp.example.com/path/to/repo | ||
10 | |||
11 | and it would make an FTP request. | ||
12 | |||
13 | Any user intentionally using such a URL is likely to have made a typo. | ||
14 | Unfortunately, credential_from_url is not able to determine the host and | ||
15 | protocol in order to determine appropriate credentials to send, and | ||
16 | until "credential: refuse to operate when missing host or protocol", | ||
17 | this resulted in another host's credentials being leaked to the named | ||
18 | host. | ||
19 | |||
20 | Teach credential_from_url_gently to consider such a URL to be invalid | ||
21 | so that fsck can detect and block gitmodules files with such URLs, | ||
22 | allowing server operators to avoid serving them to downstream users | ||
23 | running older versions of Git. | ||
24 | |||
25 | This also means that when such URLs are passed on the command line, Git | ||
26 | will print a clearer error so affected users can switch to the simpler | ||
27 | URL that explicitly specifies the host and protocol they intend. | ||
28 | |||
29 | One subtlety: .gitmodules files can contain relative URLs, representing | ||
30 | a URL relative to the URL they were cloned from. The relative URL | ||
31 | resolver used for .gitmodules can follow ".." components out of the path | ||
32 | part and past the host part of a URL, meaning that such a relative URL | ||
33 | can be used to traverse from a https://foo.example.com/innocent | ||
34 | superproject to a https::attacker.example.com/exploit submodule. | ||
35 | Fortunately a leading ':' in the first path component after a series of | ||
36 | leading './' and '../' components is unlikely to show up in other | ||
37 | contexts, so we can catch this by detecting that pattern. | ||
38 | |||
39 | Reported-by: Jeff King <peff@peff.net> | ||
40 | Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> | ||
41 | Reviewed-by: Jeff King <peff@peff.net> | ||
42 | |||
43 | Upstream-Status: Backport | ||
44 | CVE: CVE-2020-11008 (7) | ||
45 | Signed-off-by: Li Zhou <li.zhou@windriver.com> | ||
46 | --- | ||
47 | credential.c | 7 +++++-- | ||
48 | fsck.c | 47 +++++++++++++++++++++++++++++++++++++++++-- | ||
49 | t/t5550-http-fetch-dumb.sh | 7 ++----- | ||
50 | t/t7416-submodule-dash-url.sh | 32 +++++++++++++++++++++++++++++ | ||
51 | 4 files changed, 84 insertions(+), 9 deletions(-) | ||
52 | |||
53 | diff --git a/credential.c b/credential.c | ||
54 | index 22649d5..1e1aed5 100644 | ||
55 | --- a/credential.c | ||
56 | +++ b/credential.c | ||
57 | @@ -360,8 +360,11 @@ int credential_from_url_gently(struct credential *c, const char *url, | ||
58 | * (3) proto://<user>:<pass>@<host>/... | ||
59 | */ | ||
60 | proto_end = strstr(url, "://"); | ||
61 | - if (!proto_end) | ||
62 | - return 0; | ||
63 | + if (!proto_end) { | ||
64 | + if (!quiet) | ||
65 | + warning(_("url has no scheme: %s"), url); | ||
66 | + return -1; | ||
67 | + } | ||
68 | cp = proto_end + 3; | ||
69 | at = strchr(cp, '@'); | ||
70 | colon = strchr(cp, ':'); | ||
71 | diff --git a/fsck.c b/fsck.c | ||
72 | index 0f21eb1..30eac29 100644 | ||
73 | --- a/fsck.c | ||
74 | +++ b/fsck.c | ||
75 | @@ -978,6 +978,34 @@ static int submodule_url_is_relative(const char *url) | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | + * Count directory components that a relative submodule URL should chop | ||
80 | + * from the remote_url it is to be resolved against. | ||
81 | + * | ||
82 | + * In other words, this counts "../" components at the start of a | ||
83 | + * submodule URL. | ||
84 | + * | ||
85 | + * Returns the number of directory components to chop and writes a | ||
86 | + * pointer to the next character of url after all leading "./" and | ||
87 | + * "../" components to out. | ||
88 | + */ | ||
89 | +static int count_leading_dotdots(const char *url, const char **out) | ||
90 | +{ | ||
91 | + int result = 0; | ||
92 | + while (1) { | ||
93 | + if (starts_with_dot_dot_slash(url)) { | ||
94 | + result++; | ||
95 | + url += strlen("../"); | ||
96 | + continue; | ||
97 | + } | ||
98 | + if (starts_with_dot_slash(url)) { | ||
99 | + url += strlen("./"); | ||
100 | + continue; | ||
101 | + } | ||
102 | + *out = url; | ||
103 | + return result; | ||
104 | + } | ||
105 | +} | ||
106 | +/* | ||
107 | * Check whether a transport is implemented by git-remote-curl. | ||
108 | * | ||
109 | * If it is, returns 1 and writes the URL that would be passed to | ||
110 | @@ -1024,15 +1052,30 @@ static int check_submodule_url(const char *url) | ||
111 | return -1; | ||
112 | |||
113 | if (submodule_url_is_relative(url)) { | ||
114 | + char *decoded; | ||
115 | + const char *next; | ||
116 | + int has_nl; | ||
117 | + | ||
118 | /* | ||
119 | * This could be appended to an http URL and url-decoded; | ||
120 | * check for malicious characters. | ||
121 | */ | ||
122 | - char *decoded = url_decode(url); | ||
123 | - int has_nl = !!strchr(decoded, '\n'); | ||
124 | + decoded = url_decode(url); | ||
125 | + has_nl = !!strchr(decoded, '\n'); | ||
126 | + | ||
127 | free(decoded); | ||
128 | if (has_nl) | ||
129 | return -1; | ||
130 | + | ||
131 | + /* | ||
132 | + * URLs which escape their root via "../" can overwrite | ||
133 | + * the host field and previous components, resolving to | ||
134 | + * URLs like https::example.com/submodule.git that were | ||
135 | + * susceptible to CVE-2020-11008. | ||
136 | + */ | ||
137 | + if (count_leading_dotdots(url, &next) > 0 && | ||
138 | + *next == ':') | ||
139 | + return -1; | ||
140 | } | ||
141 | |||
142 | else if (url_to_curl_url(url, &curl_url)) { | ||
143 | diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh | ||
144 | index b811d89..1c9e5d3 100755 | ||
145 | --- a/t/t5550-http-fetch-dumb.sh | ||
146 | +++ b/t/t5550-http-fetch-dumb.sh | ||
147 | @@ -321,11 +321,8 @@ test_expect_success 'git client does not send an empty Accept-Language' ' | ||
148 | ' | ||
149 | |||
150 | test_expect_success 'remote-http complains cleanly about malformed urls' ' | ||
151 | - # do not actually issue "list" or other commands, as we do not | ||
152 | - # want to rely on what curl would actually do with such a broken | ||
153 | - # URL. This is just about making sure we do not segfault during | ||
154 | - # initialization. | ||
155 | - test_must_fail git remote-http http::/example.com/repo.git | ||
156 | + test_must_fail git remote-http http::/example.com/repo.git 2>stderr && | ||
157 | + test_i18ngrep "url has no scheme" stderr | ||
158 | ' | ||
159 | |||
160 | test_expect_success 'redirects can be forbidden/allowed' ' | ||
161 | diff --git a/t/t7416-submodule-dash-url.sh b/t/t7416-submodule-dash-url.sh | ||
162 | index afdd255..249dc3d 100755 | ||
163 | --- a/t/t7416-submodule-dash-url.sh | ||
164 | +++ b/t/t7416-submodule-dash-url.sh | ||
165 | @@ -60,6 +60,38 @@ test_expect_success 'trailing backslash is handled correctly' ' | ||
166 | test_i18ngrep ! "unknown option" err | ||
167 | ' | ||
168 | |||
169 | +test_expect_success 'fsck rejects missing URL scheme' ' | ||
170 | + git checkout --orphan missing-scheme && | ||
171 | + cat >.gitmodules <<-\EOF && | ||
172 | + [submodule "foo"] | ||
173 | + url = http::one.example.com/foo.git | ||
174 | + EOF | ||
175 | + git add .gitmodules && | ||
176 | + test_tick && | ||
177 | + git commit -m "gitmodules with missing URL scheme" && | ||
178 | + test_when_finished "rm -rf dst" && | ||
179 | + git init --bare dst && | ||
180 | + git -C dst config transfer.fsckObjects true && | ||
181 | + test_must_fail git push dst HEAD 2>err && | ||
182 | + grep gitmodulesUrl err | ||
183 | +' | ||
184 | + | ||
185 | +test_expect_success 'fsck rejects relative URL resolving to missing scheme' ' | ||
186 | + git checkout --orphan relative-missing-scheme && | ||
187 | + cat >.gitmodules <<-\EOF && | ||
188 | + [submodule "foo"] | ||
189 | + url = "..\\../.\\../:one.example.com/foo.git" | ||
190 | + EOF | ||
191 | + git add .gitmodules && | ||
192 | + test_tick && | ||
193 | + git commit -m "gitmodules with relative URL that strips off scheme" && | ||
194 | + test_when_finished "rm -rf dst" && | ||
195 | + git init --bare dst && | ||
196 | + git -C dst config transfer.fsckObjects true && | ||
197 | + test_must_fail git push dst HEAD 2>err && | ||
198 | + grep gitmodulesUrl err | ||
199 | +' | ||
200 | + | ||
201 | test_expect_success 'fsck permits embedded newline with unrecognized scheme' ' | ||
202 | git checkout --orphan newscheme && | ||
203 | cat >.gitmodules <<-\EOF && | ||
204 | -- | ||
205 | 1.9.1 | ||
206 | |||