aboutsummaryrefslogtreecommitdiff
path: root/src/path/filepath/path_test.go
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2023-09-01 11:17:19 -0700
committerGopher Robot <gobot@golang.org>2023-11-07 16:29:18 +0000
commitcae35cd2582878341452547378ffdc14fdb0a022 (patch)
treef926c5df4dfb9769e9711142f10e5906b3839e1f /src/path/filepath/path_test.go
parentdc74a3dd4f30c4a3df235aac8a9e84575767ba69 (diff)
downloadgo-cae35cd2582878341452547378ffdc14fdb0a022.tar.xz
path/filepath: fix various issues in parsing Windows paths
On Windows, A root local device path is a path which begins with \\?\ or \??\. A root local device path accesses the DosDevices object directory, and permits access to any file or device on the system. For example \??\C:\foo is equivalent to common C:\foo. The Clean, IsAbs, IsLocal, and VolumeName functions did not recognize root local device paths beginning with \??\. Clean could convert a rooted path such as \a\..\??\b into the root local device path \??\b. It will now convert this path into .\??\b. IsAbs now correctly reports paths beginning with \??\ as absolute. IsLocal now correctly reports paths beginning with \??\ as non-local. VolumeName now reports the \??\ prefix as a volume name. Join(`\`, `??`, `b`) could convert a seemingly innocent sequence of path elements into the root local device path \??\b. It will now convert this to \.\??\b. In addition, the IsLocal function did not correctly detect reserved names in some cases: - reserved names followed by spaces, such as "COM1 ". - "COM" or "LPT" followed by a superscript 1, 2, or 3. IsLocal now correctly reports these names as non-local. Fixes #63713 Fixes CVE-2023-45283 Fixes CVE-2023-45284 Change-Id: I446674a58977adfa54de7267d716ac23ab496c54 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2040691 Reviewed-by: Roland Shoemaker <bracewell@google.com> Reviewed-by: Tatiana Bradley <tatianabradley@google.com> Run-TryBot: Damien Neil <dneil@google.com> Reviewed-on: https://go-review.googlesource.com/c/go/+/540277 Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Heschi Kreinick <heschi@google.com>
Diffstat (limited to 'src/path/filepath/path_test.go')
-rw-r--r--src/path/filepath/path_test.go67
1 files changed, 65 insertions, 2 deletions
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index 51e6a20554..cd9f5632c9 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -116,6 +116,9 @@ var wincleantests = []PathTest{
{`a/../c:/a`, `.\c:\a`},
{`a/../../c:`, `..\c:`},
{`foo:bar`, `foo:bar`},
+
+ // Don't allow cleaning to create a Root Local Device path like \??\a.
+ {`/a/../??/a`, `\.\??\a`},
}
func TestClean(t *testing.T) {
@@ -177,8 +180,28 @@ var islocaltests = []IsLocalTest{
var winislocaltests = []IsLocalTest{
{"NUL", false},
{"nul", false},
+ {"nul ", false},
{"nul.", false},
+ {"a/nul:", false},
+ {"a/nul : a", false},
+ {"com0", true},
{"com1", false},
+ {"com2", false},
+ {"com3", false},
+ {"com4", false},
+ {"com5", false},
+ {"com6", false},
+ {"com7", false},
+ {"com8", false},
+ {"com9", false},
+ {"com¹", false},
+ {"com²", false},
+ {"com³", false},
+ {"com¹ : a", false},
+ {"cOm1", false},
+ {"lpt1", false},
+ {"LPT1", false},
+ {"lpt³", false},
{"./nul", false},
{`\`, false},
{`\a`, false},
@@ -384,6 +407,7 @@ var winjointests = []JoinTest{
{[]string{`\\a\`, `b`, `c`}, `\\a\b\c`},
{[]string{`//`, `a`}, `\\a`},
{[]string{`a:\b\c`, `x\..\y:\..\..\z`}, `a:\b\z`},
+ {[]string{`\`, `??\a`}, `\.\??\a`},
}
func TestJoin(t *testing.T) {
@@ -1047,6 +1071,8 @@ var winisabstests = []IsAbsTest{
{`\\host\share\`, true},
{`\\host\share\foo`, true},
{`//host/share/foo/bar`, true},
+ {`\\?\a\b\c`, true},
+ {`\??\a\b\c`, true},
}
func TestIsAbs(t *testing.T) {
@@ -1547,7 +1573,8 @@ type VolumeNameTest struct {
var volumenametests = []VolumeNameTest{
{`c:/foo/bar`, `c:`},
{`c:`, `c:`},
- {`2:`, ``},
+ {`c:\`, `c:`},
+ {`2:`, `2:`},
{``, ``},
{`\\\host`, `\\\host`},
{`\\\host\`, `\\\host`},
@@ -1567,12 +1594,23 @@ var volumenametests = []VolumeNameTest{
{`//host/share//foo///bar////baz`, `\\host\share`},
{`\\host\share\foo\..\bar`, `\\host\share`},
{`//host/share/foo/../bar`, `\\host\share`},
+ {`//.`, `\\.`},
+ {`//./`, `\\.\`},
{`//./NUL`, `\\.\NUL`},
- {`//?/NUL`, `\\?\NUL`},
+ {`//?/`, `\\?`},
+ {`//./a/b`, `\\.\a`},
+ {`//?/`, `\\?`},
+ {`//?/`, `\\?`},
{`//./C:`, `\\.\C:`},
+ {`//./C:/`, `\\.\C:`},
{`//./C:/a/b/c`, `\\.\C:`},
{`//./UNC/host/share/a/b/c`, `\\.\UNC\host\share`},
{`//./UNC/host`, `\\.\UNC\host`},
+ {`//./UNC/host\`, `\\.\UNC\host\`},
+ {`//./UNC`, `\\.\UNC`},
+ {`//./UNC/`, `\\.\UNC\`},
+ {`\\?\x`, `\\?`},
+ {`\??\x`, `\??`},
}
func TestVolumeName(t *testing.T) {
@@ -1842,3 +1880,28 @@ func TestIssue51617(t *testing.T) {
t.Errorf("got directories %v, want %v", saw, want)
}
}
+
+func TestEscaping(t *testing.T) {
+ dir1 := t.TempDir()
+ dir2 := t.TempDir()
+ chdir(t, dir1)
+
+ for _, p := range []string{
+ filepath.Join(dir2, "x"),
+ } {
+ if !filepath.IsLocal(p) {
+ continue
+ }
+ f, err := os.Create(p)
+ if err != nil {
+ f.Close()
+ }
+ ents, err := os.ReadDir(dir2)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, e := range ents {
+ t.Fatalf("found: %v", e.Name())
+ }
+ }
+}