Skip to content

Commit 0a3a972

Browse files
ttaylorrpeff
authored andcommitted
contrib/credential: embiggen fixed-size buffer in wincred
As in previous commits, harden the wincred credential helper against the aforementioned protocol injection attack. Unlike the approached used for osxkeychain and libsecret, where a fixed-size buffer was replaced with `getline()`, we must take a different approach here. There is no `getline()` equivalent in Windows, and the function is not available to us with ordinary compiler settings. Instead, allocate a larger (still fixed-size) buffer in which to process each line. The value of 100 KiB is chosen to match the maximum-length header that curl will allow, CURL_MAX_HTTP_HEADER. To ensure that we are reading complete lines at a time, and that we aren't susceptible to a similar injection attack (albeit with more padding), ensure that each read terminates at a newline (i.e., that no line is more than 100 KiB long). Note that it isn't sufficient to turn the old loop into something like: while (len && strchr("\r\n", buf[len - 1])) { buf[--len] = 0; ends_in_newline = 1; } because if an attacker sends something like: [aaaaa.....]\r host=example.com\r\n the credential helper would fill its buffer after reading up through the first '\r', call fgets() again, and then see "host=example.com\r\n" on its line. Note that the original code was written in a way that would trim an arbitrary number of "\r" and "\n" from the end of the string. We should get only a single "\n" (since the point of `fgets()` is to return the buffer to us when it sees one), and likewise would not expect to see more than one associated "\r". The new code trims a single "\r\n", which matches the original intent. [1]: https://curl.se/libcurl/c/CURLOPT_HEADERFUNCTION.html Tested-by: Matthew John Cheetham <[email protected]> Helped-by: Matthew John Cheetham <[email protected]> Co-authored-by: Jeff King <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 64f1e65 commit 0a3a972

File tree

1 file changed

+17
-4
lines changed

1 file changed

+17
-4
lines changed

contrib/credential/wincred/git-credential-wincred.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,17 +249,28 @@ static WCHAR *utf8_to_utf16_dup(const char *str)
249249
return wstr;
250250
}
251251

252+
#define KB (1024)
253+
252254
static void read_credential(void)
253255
{
254-
char buf[1024];
256+
size_t alloc = 100 * KB;
257+
char *buf = calloc(alloc, sizeof(*buf));
255258

256-
while (fgets(buf, sizeof(buf), stdin)) {
259+
while (fgets(buf, alloc, stdin)) {
257260
char *v;
258-
int len = strlen(buf);
261+
size_t len = strlen(buf);
262+
int ends_in_newline = 0;
259263
/* strip trailing CR / LF */
260-
while (len && strchr("\r\n", buf[len - 1]))
264+
if (len && buf[len - 1] == '\n') {
265+
buf[--len] = 0;
266+
ends_in_newline = 1;
267+
}
268+
if (len && buf[len - 1] == '\r')
261269
buf[--len] = 0;
262270

271+
if (!ends_in_newline)
272+
die("bad input: %s", buf);
273+
263274
if (!*buf)
264275
break;
265276

@@ -284,6 +295,8 @@ static void read_credential(void)
284295
* learn new lines, and the helpers are updated to match.
285296
*/
286297
}
298+
299+
free(buf);
287300
}
288301

289302
int main(int argc, char *argv[])

0 commit comments

Comments
 (0)