| From 9198107f367183b53c8bdc44c917bc334f09e21f Mon Sep 17 00:00:00 2001 |
| From: Johannes Schindelin <johannes.schindelin@gmx.de> |
| Date: Thu, 5 Sep 2019 13:44:21 +0200 |
| Subject: mingw: refuse to access paths with illegal characters |
| |
| Certain characters are not admissible in file names on Windows, even if |
| Cygwin/MSYS2 (and therefore, Git for Windows' Bash) pretend that they |
| are, e.g. `:`, `<`, `>`, etc |
| |
| Let's disallow those characters explicitly in Windows builds of Git. |
| |
| Note: just like trailing spaces or periods, it _is_ possible on Windows |
| to create commits adding files with such illegal characters, as long as |
| the operation leaves the worktree untouched. To allow for that, we |
| continue to guard `is_valid_win32_path()` behind the config setting |
| `core.protectNTFS`, so that users _can_ continue to do that, as long as |
| they turn the protections off via that config setting. |
| |
| Among other problems, this prevents Git from trying to write to an "NTFS |
| Alternate Data Stream" (which refers to metadata stored alongside a |
| file, under a special name: "<filename>:<stream-name>"). This fix |
| therefore also prevents an attack vector that was exploited in |
| demonstrations of a number of recently-fixed security bugs. |
| |
| Further reading on illegal characters in Win32 filenames: |
| https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file |
| |
| Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> |
| (cherry picked from commit 817ddd64c20b29b2d86b3a0589f7ff88d1279109) |
| Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> |
| --- |
| compat/mingw.c | 10 ++++++++++ |
| compat/mingw.h | 7 +++++-- |
| t/t0060-path-utils.sh | 4 +++- |
| 3 files changed, 18 insertions(+), 3 deletions(-) |
| |
| diff --git a/compat/mingw.c b/compat/mingw.c |
| index 386aa94acb..806822744f 100644 |
| --- a/compat/mingw.c |
| +++ b/compat/mingw.c |
| @@ -2447,6 +2447,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) { |
| @@ -2468,6 +2470,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 1d7e9d7c9d..38fee3482e 100644 |
| --- a/compat/mingw.h |
| +++ b/compat/mingw.h |
| @@ -482,8 +482,11 @@ extern char *mingw_query_user_email(void); |
| /** |
| * 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. |
| */ |
| diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh |
| index dc245c7dfe..2052583489 100755 |
| --- a/t/t0060-path-utils.sh |
| +++ b/t/t0060-path-utils.sh |
| @@ -460,13 +460,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 |
| -- |
| 2.24.0.393.g34dc348eaf |
| |