CVE-2020-12279: Use of Incorrectly-Resolved Name or Reference (CWE-706)
value: An issue was discovered in libgit2 before 0.28.4 and 0.9x before 0.99.0. checkout.c mishandles equivalent filenames that exist because of NTFS short names. This may allow remote code execution when cloning a repository. This issue is similar to CVE-2019-1353.
CWE description: The product uses a name or reference to access a resource, but the name/reference resolves to a resource that is outside of the intended control sphere.
CVSS v3 base score: 9.8
Published: 2020-04-27T17:15Z
Repository: https://github.com/libgit2/libgit2
Language: C
Files changed: src/checkout.c, tests/checkout/nasty.c
Commit date: 2019-12-10 18:01:06 +1000
Commit message: Protect against 8.3 "short name" attacks also on Linux/macOS

The Windows Subsystem for Linux (WSL) is getting increasingly popular,
in particular because it makes it _so_ easy to run Linux software on
Windows' files, via the auto-mounted Windows drives (`C:\` is mapped to
`/mnt/c/`, no need to set that up manually).

Unfortunately, files/directories on the Windows drives can be accessed
via their _short names_, if that feature is enabled (which it is on the
`C:` drive by default).

Which means that we have to safeguard even our Linux users against the
short name attacks.

Further, while the default options of CIFS/SMB-mounts seem to disallow
accessing files on network shares via their short names on Linux/macOS,
it _is_ possible to do so with the right options.

So let's just safe-guard against short name attacks _everywhere_.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

Diff: diff --git a/src/checkout.c b/src/checkout.c
index 5cfa7280ba..5b20ede466 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -1269,11 +1269,11 @@ static int checkout_get_remove_conflicts(
 static int checkout_verify_paths(
 	git_repository *repo,
 	int action,
 	git_diff_delta *delta)
 {
-	unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
+	unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS | GIT_PATH_REJECT_DOT_GIT_NTFS;
 
 	if (action & CHECKOUT_ACTION__REMOVE) {
 		if (!git_path_isvalid(repo, delta->old_file.path, delta->old_file.mode, flags)) {
 			git_error_set(GIT_ERROR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path);
 			return -1;
diff --git a/tests/checkout/nasty.c b/tests/checkout/nasty.c
index 3897878cef..a0ac738a81 100644
--- a/tests/checkout/nasty.c
+++ b/tests/checkout/nasty.c
@@ -204,13 +204,12 @@ void test_checkout_nasty__dot_git_dot(void)
 /* A tree that contains an entry "git~1", because that is typically the
  * short name for ".git".
  */
 void test_checkout_nasty__git_tilde1(void)
 {
-#ifdef GIT_WIN32
 	test_checkout_fails("refs/heads/git_tilde1", ".git/foobar");
-#endif
+	test_checkout_fails("refs/heads/git_tilde1", "git~1/foobar");
 }
 
 /* A tree that contains an entry "git~2", when we have forced the short
  * name for ".git" into "GIT~2".
  */

Vulnerable code: 	unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
#ifdef GIT_WIN32
#endif
Fixed code: 	unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS | GIT_PATH_REJECT_DOT_GIT_NTFS;
	test_checkout_fails("refs/heads/git_tilde1", "git~1/foobar");