Skip to content

Commit f82a97e

Browse files
committed
mingw: handle subst-ed "DOS drives"
Over a decade ago, in 25fe217 (Windows: Treat Windows style path names., 2008-03-05), Git was taught to handle absolute Windows paths, i.e. paths that start with a drive letter and a colon. Unbeknownst to us, while drive letters of physical drives are limited to letters of the English alphabet, there is a way to assign virtual drive letters to arbitrary directories, via the `subst` command, which is _not_ limited to English letters. It is therefore possible to have absolute Windows paths of the form `1:\what\the\hex.txt`. Even "better": pretty much arbitrary Unicode letters can also be used, e.g. `ä:\tschibät.sch`. While it can be sensibly argued that users who set up such funny drive letters really seek adverse consequences, the Windows Operating System is known to be a platform where many users are at the mercy of administrators who have their very own idea of what constitutes a reasonable setup. Therefore, let's just make sure that such funny paths are still considered absolute paths by Git, on Windows. In addition to Unicode characters, pretty much any character is a valid drive letter, as far as `subst` is concerned, even `:` and `"` or even a space character. While it is probably the opposite of smart to use them, let's safeguard `is_dos_drive_prefix()` against all of them. Note: `[::1]:repo` is a valid URL, but not a valid path on Windows. As `[` is now considered a valid drive letter, we need to be very careful to avoid misinterpreting such a string as valid local path in `url_is_local_not_ssh()`. To do that, we use the just-introduced function `is_valid_path()` (which will label the string as invalid file name because of the colon characters). This fixes CVE-2019-1351. Reported-by: Nicolas Joly <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 817ddd6 commit f82a97e

File tree

4 files changed

+36
-3
lines changed

4 files changed

+36
-3
lines changed

compat/mingw.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,30 @@ pid_t waitpid(pid_t pid, int *status, int options)
19861986
return -1;
19871987
}
19881988

1989+
int mingw_has_dos_drive_prefix(const char *path)
1990+
{
1991+
int i;
1992+
1993+
/*
1994+
* Does it start with an ASCII letter (i.e. highest bit not set),
1995+
* followed by a colon?
1996+
*/
1997+
if (!(0x80 & (unsigned char)*path))
1998+
return *path && path[1] == ':' ? 2 : 0;
1999+
2000+
/*
2001+
* While drive letters must be letters of the English alphabet, it is
2002+
* possible to assign virtually _any_ Unicode character via `subst` as
2003+
* a drive letter to "virtual drives". Even `1`, or `ä`. Or fun stuff
2004+
* like this:
2005+
*
2006+
* subst ֍: %USERPROFILE%\Desktop
2007+
*/
2008+
for (i = 1; i < 4 && (0x80 & (unsigned char)path[i]); i++)
2009+
; /* skip first UTF-8 character */
2010+
return path[i] == ':' ? i + 1 : 0;
2011+
}
2012+
19892013
int mingw_skip_dos_drive_prefix(char **path)
19902014
{
19912015
int ret = has_dos_drive_prefix(*path);

compat/mingw.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,8 @@ HANDLE winansi_get_osfhandle(int fd);
394394
* git specific compatibility
395395
*/
396396

397-
#define has_dos_drive_prefix(path) \
398-
(isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
397+
int mingw_has_dos_drive_prefix(const char *path);
398+
#define has_dos_drive_prefix mingw_has_dos_drive_prefix
399399
int mingw_skip_dos_drive_prefix(char **path);
400400
#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix
401401
static inline int mingw_is_dir_sep(int c)

connect.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ int url_is_local_not_ssh(const char *url)
264264
const char *colon = strchr(url, ':');
265265
const char *slash = strchr(url, '/');
266266
return !colon || (slash && slash < colon) ||
267-
has_dos_drive_prefix(url);
267+
(has_dos_drive_prefix(url) && is_valid_path(url));
268268
}
269269

270270
static const char *prot_name(enum protocol protocol)

t/t0060-path-utils.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,15 @@ test_expect_success 'absolute path rejects the empty string' '
165165
test_must_fail test-path-utils absolute_path ""
166166
'
167167

168+
test_expect_success MINGW '<drive-letter>:\\abc is an absolute path' '
169+
for letter in : \" C Z 1 ä
170+
do
171+
path=$letter:\\abc &&
172+
absolute="$(test-path-utils absolute_path "$path")" &&
173+
test "$path" = "$absolute" || return 1
174+
done
175+
'
176+
168177
test_expect_success 'real path rejects the empty string' '
169178
test_must_fail test-path-utils real_path ""
170179
'

0 commit comments

Comments
 (0)