1
0
mirror of https://github.com/git/git.git synced 2024-09-22 04:20:47 +02:00

Merge branch 'win32-accommodate-funny-drive-names'

While the only permitted drive letters for physical drives on Windows
are letters of the US-English alphabet, this restriction does not apply
to virtual drives assigned via `subst <letter>: <path>`.

To prevent targeted attacks against systems where "funny" drive letters
such as `1` or `!` are assigned, let's handle them as regular drive
letters on Windows.

This fixes CVE-2019-1351.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin 2019-09-16 13:26:40 +02:00
commit 2ddcccf97a
4 changed files with 54 additions and 6 deletions

View File

@ -1989,6 +1989,30 @@ pid_t waitpid(pid_t pid, int *status, int options)
return -1;
}
int mingw_has_dos_drive_prefix(const char *path)
{
int i;
/*
* Does it start with an ASCII letter (i.e. highest bit not set),
* followed by a colon?
*/
if (!(0x80 & (unsigned char)*path))
return *path && path[1] == ':' ? 2 : 0;
/*
* While drive letters must be letters of the English alphabet, it is
* possible to assign virtually _any_ Unicode character via `subst` as
* a drive letter to "virtual drives". Even `1`, or `ä`. Or fun stuff
* like this:
*
* subst ֍: %USERPROFILE%\Desktop
*/
for (i = 1; i < 4 && (0x80 & (unsigned char)path[i]); i++)
; /* skip first UTF-8 character */
return path[i] == ':' ? i + 1 : 0;
}
int mingw_skip_dos_drive_prefix(char **path)
{
int ret = has_dos_drive_prefix(*path);
@ -2137,6 +2161,8 @@ int is_valid_win32_path(const char *path)
if (!protect_ntfs)
return 1;
skip_dos_drive_prefix((char **)&path);
for (;;) {
char c = *(path++);
switch (c) {
@ -2158,6 +2184,14 @@ int is_valid_win32_path(const char *path)
preceding_space_or_period = 1;
i++;
continue;
case ':': /* DOS drive prefix was already skipped */
case '<': case '>': case '"': case '|': case '?': case '*':
/* illegal character */
return 0;
default:
if (c > '\0' && c < '\x20')
/* illegal character */
return 0;
}
preceding_space_or_period = 0;
i++;

View File

@ -394,8 +394,8 @@ HANDLE winansi_get_osfhandle(int fd);
* git specific compatibility
*/
#define has_dos_drive_prefix(path) \
(isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
int mingw_has_dos_drive_prefix(const char *path);
#define has_dos_drive_prefix mingw_has_dos_drive_prefix
int mingw_skip_dos_drive_prefix(char **path);
#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix
static inline int mingw_is_dir_sep(int c)
@ -431,8 +431,11 @@ int mingw_offset_1st_component(const char *path);
/**
* Verifies that the given path is a valid one on Windows.
*
* In particular, path segments are disallowed which end in a period or a
* space (except the special directories `.` and `..`).
* In particular, path segments are disallowed which
*
* - end in a period or a space (except the special directories `.` and `..`).
*
* - contain any of the reserved characters, e.g. `:`, `;`, `*`, etc
*
* Returns 1 upon success, otherwise 0.
*/

View File

@ -264,7 +264,7 @@ int url_is_local_not_ssh(const char *url)
const char *colon = strchr(url, ':');
const char *slash = strchr(url, '/');
return !colon || (slash && slash < colon) ||
has_dos_drive_prefix(url);
(has_dos_drive_prefix(url) && is_valid_path(url));
}
static const char *prot_name(enum protocol protocol)

View File

@ -165,6 +165,15 @@ test_expect_success 'absolute path rejects the empty string' '
test_must_fail test-path-utils absolute_path ""
'
test_expect_success MINGW '<drive-letter>:\\abc is an absolute path' '
for letter in : \" C Z 1 ä
do
path=$letter:\\abc &&
absolute="$(test-path-utils absolute_path "$path")" &&
test "$path" = "$absolute" || return 1
done
'
test_expect_success 'real path rejects the empty string' '
test_must_fail test-path-utils real_path ""
'
@ -445,13 +454,15 @@ test_expect_success MINGW 'is_valid_path() on Windows' '
win32 \
"win32 x" \
../hello.txt \
C:\\git \
\
--not \
"win32 " \
"win32 /x " \
"win32." \
"win32 . ." \
.../hello.txt
.../hello.txt \
colon:test
'
test_done