diff options
author | Johannes Schindelin <johannes.schindelin@gmx.de> | 2019-09-16 13:26:40 +0200 |
---|---|---|
committer | Johannes Schindelin <johannes.schindelin@gmx.de> | 2019-12-05 15:37:09 +0100 |
commit | 2ddcccf97a717f9df17a4843c39e3c4f1df49fec (patch) | |
tree | 6d63983b124cf3793eee811811281ca131cebbb7 /compat | |
parent | Merge branch 'win32-filenames-cannot-have-trailing-spaces-or-periods' (diff) | |
parent | mingw: handle `subst`-ed "DOS drives" (diff) | |
download | tgif-2ddcccf97a717f9df17a4843c39e3c4f1df49fec.tar.xz |
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>
Diffstat (limited to 'compat')
-rw-r--r-- | compat/mingw.c | 34 | ||||
-rw-r--r-- | compat/mingw.h | 11 |
2 files changed, 41 insertions, 4 deletions
diff --git a/compat/mingw.c b/compat/mingw.c index 11fb2de241..22adb7a8cb 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -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++; diff --git a/compat/mingw.h b/compat/mingw.h index 8c49c1d09b..17064665d9 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -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. */ |