136 lines
5.0 KiB
Diff
136 lines
5.0 KiB
Diff
From a94971b023f4583ea4b2c9c9f7a71d53f9781d58 Mon Sep 17 00:00:00 2001
|
|
From: Johannes Schindelin <johannes.schindelin@gmx.de>
|
|
Date: Fri, 6 Sep 2019 00:09:10 +0200
|
|
Subject: [PATCH] mingw: handle `subst`-ed "DOS drives"
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Over a decade ago, in 25fe217b86c (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 <Nicolas.Joly@microsoft.com>
|
|
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
|
|
---
|
|
compat/win32/path-utils.c | 24 ++++++++++++++++++++++++
|
|
compat/win32/path-utils.h | 4 ++--
|
|
connect.c | 2 +-
|
|
t/t0060-path-utils.sh | 9 +++++++++
|
|
4 files changed, 36 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/compat/win32/path-utils.c b/compat/win32/path-utils.c
|
|
index d9d3641de8..70352af283 100644
|
|
--- a/compat/win32/path-utils.c
|
|
+++ b/compat/win32/path-utils.c
|
|
@@ -1,5 +1,29 @@
|
|
#include "../../git-compat-util.h"
|
|
|
|
+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 win32_skip_dos_drive_prefix(char **path)
|
|
{
|
|
int ret = has_dos_drive_prefix(*path);
|
|
diff --git a/compat/win32/path-utils.h b/compat/win32/path-utils.h
|
|
index 0f70d43920..22b0c63349 100644
|
|
--- a/compat/win32/path-utils.h
|
|
+++ b/compat/win32/path-utils.h
|
|
@@ -1,5 +1,5 @@
|
|
-#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 win32_skip_dos_drive_prefix(char **path);
|
|
#define skip_dos_drive_prefix win32_skip_dos_drive_prefix
|
|
static inline int win32_is_dir_sep(int c)
|
|
diff --git a/connect.c b/connect.c
|
|
index 2778481264..4050a797bf 100644
|
|
--- a/connect.c
|
|
+++ b/connect.c
|
|
@@ -511,7 +511,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)
|
|
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
|
|
index c7b53e494b..e9b61efdff 100755
|
|
--- a/t/t0060-path-utils.sh
|
|
+++ b/t/t0060-path-utils.sh
|
|
@@ -165,6 +165,15 @@ test_expect_success 'absolute path rejects the empty string' '
|
|
test_must_fail test-tool 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-tool path-utils real_path ""
|
|
'
|
|
--
|
|
2.23.0
|
|
|