From 8350c0093b2e589b912808c9348dabcfc68c7863 Mon Sep 17 00:00:00 2001 From: <> Date: Tue, 7 Nov 2023 11:31:20 -0800 Subject: [PATCH 01/12] Update EKS Go files for version v1.19.13 --- projects/golang/go/1.19/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/projects/golang/go/1.19/README.md b/projects/golang/go/1.19/README.md index 1e76a04ac..27064d5cd 100644 --- a/projects/golang/go/1.19/README.md +++ b/projects/golang/go/1.19/README.md @@ -1,17 +1,17 @@ # EKS Golang 1.19 -Current Release: `12` +Current Release: `13` Tracking Tag: `go1.19.13` ### Artifacts: |Arch|Artifact|sha| |:---:|:---:|:---:| -|noarch|[golang-src-1.19.13-12.amzn2.eks.noarch.rpm](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/x86_64/RPMS/noarch/golang-src-1.19.13-12.amzn2.eks.noarch.rpm)|[golang-src-1.19.13-12.amzn2.eks.noarch.rpm.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/x86_64/RPMS/noarch/golang-src-1.19.13-12.amzn2.eks.noarch.rpm.sha256)| -|x86_64|[golang-1.19.13-12.amzn2.eks.x86_64.rpm](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/x86_64/RPMS/x86_64/golang-1.19.13-12.amzn2.eks.x86_64.rpm)|[golang-1.19.13-12.amzn2.eks.x86_64.rpm.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/x86_64/RPMS/x86_64/golang-1.19.13-12.amzn2.eks.x86_64.rpm.sha256)| -|aarch64|[golang-1.19.13-12.amzn2.eks.aarch64.rpm](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/aarch64/RPMS/aarch64/golang-1.19.13-12.amzn2.eks.aarch64.rpm)|[golang-1.19.13-12.amzn2.eks.aarch64.rpm.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/aarch64/RPMS/aarch64/golang-1.19.13-12.amzn2.eks.aarch64.rpm.sha256)| -|arm64|[go1.19.13.linux-arm64.tar.gz](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/archives/linux/arm64/go1.19.13.linux-arm64.tar.gz)|[go1.19.13.linux-arm64.tar.gz.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/archives/linux/arm64/go1.19.13.linux-arm64.tar.gz.sha256)| -|amd64|[go1.19.13.linux-amd64.tar.gz](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/archives/linux/amd64/go1.19.13.linux-amd64.tar.gz)|[go1.19.13.linux-amd64.tar.gz.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/12/archives/linux/amd64/go1.19.13.linux-amd64.tar.gz.sha256)| +|noarch|[golang-src-1.19.13-13.amzn2.eks.noarch.rpm](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/x86_64/RPMS/noarch/golang-src-1.19.13-13.amzn2.eks.noarch.rpm)|[golang-src-1.19.13-13.amzn2.eks.noarch.rpm.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/x86_64/RPMS/noarch/golang-src-1.19.13-13.amzn2.eks.noarch.rpm.sha256)| +|x86_64|[golang-1.19.13-13.amzn2.eks.x86_64.rpm](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/x86_64/RPMS/x86_64/golang-1.19.13-13.amzn2.eks.x86_64.rpm)|[golang-1.19.13-13.amzn2.eks.x86_64.rpm.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/x86_64/RPMS/x86_64/golang-1.19.13-13.amzn2.eks.x86_64.rpm.sha256)| +|aarch64|[golang-1.19.13-13.amzn2.eks.aarch64.rpm](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/aarch64/RPMS/aarch64/golang-1.19.13-13.amzn2.eks.aarch64.rpm)|[golang-1.19.13-13.amzn2.eks.aarch64.rpm.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/aarch64/RPMS/aarch64/golang-1.19.13-13.amzn2.eks.aarch64.rpm.sha256)| +|arm64|[go1.19.13.linux-arm64.tar.gz](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/archives/linux/arm64/go1.19.13.linux-arm64.tar.gz)|[go1.19.13.linux-arm64.tar.gz.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/archives/linux/arm64/go1.19.13.linux-arm64.tar.gz.sha256)| +|amd64|[go1.19.13.linux-amd64.tar.gz](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/archives/linux/amd64/go1.19.13.linux-amd64.tar.gz)|[go1.19.13.linux-amd64.tar.gz.sha256](https://distro.eks.amazonaws.com/golang-go1.19.13/releases/13/archives/linux/amd64/go1.19.13.linux-amd64.tar.gz.sha256)| ### ARM64 Builds @@ -24,4 +24,4 @@ Tracking Tag: `go1.19.13` The patches in `./patches` include relevant utility fixes for go `1.19`. ### Spec -The RPM spec file in `./rpmbuild/SPECS` is sourced from the go 1.19 SRPM available on Fedora, and modified to include the relevant patches and build the `go1.19.13` source. +The RPM spec file in `./rpmbuild/SPECS` is sourced from the go 1.19 SRPM available on Fedora, and modified to include the relevant patches and build the `go1.19.13` source." From 538f28760c67805f58b365460a17cee2e7dd304a Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Tue, 7 Nov 2023 12:14:35 -0800 Subject: [PATCH 02/12] add patch and update spec file to 1.19.13 --- ...3-eks-path-filepath-fix-various-issu.patch | 728 ++++++++++++++++++ 1 file changed, 728 insertions(+) create mode 100644 projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch diff --git a/projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch new file mode 100644 index 000000000..17cbccd7f --- /dev/null +++ b/projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch @@ -0,0 +1,728 @@ +From 4c734c9a4a25f16f26a05a7c71763654f8407ae7 Mon Sep 17 00:00:00 2001 +From: Damien Neil +Date: Fri, 1 Sep 2023 11:17:19 -0700 +Subject: [PATCH] [release-branch.go1.20] 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. + +For #63713 +Fixes #63714 +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 +Reviewed-by: Tatiana Bradley +Run-TryBot: Damien Neil +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2072597 +Reviewed-by: Cherry Mui +Reviewed-on: https://go-review.googlesource.com/c/go/+/539276 +Auto-Submit: Heschi Kreinick +LUCI-TryBot-Result: Go LUCI +--- + src/go/build/deps_test.go | 2 +- + src/internal/safefilepath/path_windows.go | 98 ++++++--- + src/path/filepath/path.go | 1 + + src/path/filepath/path_nonwindows.go | 9 + + src/path/filepath/path_test.go | 141 ++++++++++++- + src/path/filepath/path_windows.go | 229 ++++++++++++++++++---- + 6 files changed, 410 insertions(+), 70 deletions(-) + create mode 100644 src/path/filepath/path_nonwindows.go + +diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go +index 69ba8b7f52..83da402bb4 100644 +--- a/src/go/build/deps_test.go ++++ b/src/go/build/deps_test.go +@@ -176,7 +176,7 @@ var depsRules = ` + + unicode, fmt !< net, os, os/signal; + +- os/signal, STR ++ os/signal, internal/safefilepath, STR + < path/filepath + < io/ioutil; + +diff --git a/src/internal/safefilepath/path_windows.go b/src/internal/safefilepath/path_windows.go +index 909c150edc..7cfd6ce2ea 100644 +--- a/src/internal/safefilepath/path_windows.go ++++ b/src/internal/safefilepath/path_windows.go +@@ -20,15 +20,10 @@ func fromFS(path string) (string, error) { + for p := path; p != ""; { + // Find the next path element. + i := 0 +- dot := -1 + for i < len(p) && p[i] != '/' { + switch p[i] { + case 0, '\\', ':': + return "", errInvalidPath +- case '.': +- if dot < 0 { +- dot = i +- } + } + i++ + } +@@ -39,22 +34,8 @@ func fromFS(path string) (string, error) { + } else { + p = "" + } +- // Trim the extension and look for a reserved name. +- base := part +- if dot >= 0 { +- base = part[:dot] +- } +- if isReservedName(base) { +- if dot < 0 { +- return "", errInvalidPath +- } +- // The path element is a reserved name with an extension. +- // Some Windows versions consider this a reserved name, +- // while others do not. Use FullPath to see if the name is +- // reserved. +- if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` { +- return "", errInvalidPath +- } ++ if IsReservedName(part) { ++ return "", errInvalidPath + } + } + if containsSlash { +@@ -70,23 +51,88 @@ func fromFS(path string) (string, error) { + return path, nil + } + +-// isReservedName reports if name is a Windows reserved device name. ++// IsReservedName reports if name is a Windows reserved device name. + // It does not detect names with an extension, which are also reserved on some Windows versions. + // + // For details, search for PRN in + // https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. +-func isReservedName(name string) bool { +- if 3 <= len(name) && len(name) <= 4 { ++func IsReservedName(name string) bool { ++ // Device names can have arbitrary trailing characters following a dot or colon. ++ base := name ++ for i := 0; i < len(base); i++ { ++ switch base[i] { ++ case ':', '.': ++ base = base[:i] ++ } ++ } ++ // Trailing spaces in the last path element are ignored. ++ for len(base) > 0 && base[len(base)-1] == ' ' { ++ base = base[:len(base)-1] ++ } ++ if !isReservedBaseName(base) { ++ return false ++ } ++ if len(base) == len(name) { ++ return true ++ } ++ // The path element is a reserved name with an extension. ++ // Some Windows versions consider this a reserved name, ++ // while others do not. Use FullPath to see if the name is ++ // reserved. ++ if p, _ := syscall.FullPath(name); len(p) >= 4 && p[:4] == `\\.\` { ++ return true ++ } ++ return false ++} ++ ++func isReservedBaseName(name string) bool { ++ if len(name) == 3 { + switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { + case "CON", "PRN", "AUX", "NUL": +- return len(name) == 3 ++ return true ++ } ++ } ++ if len(name) >= 4 { ++ switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { + case "COM", "LPT": +- return len(name) == 4 && '1' <= name[3] && name[3] <= '9' ++ if len(name) == 4 && '1' <= name[3] && name[3] <= '9' { ++ return true ++ } ++ // Superscript ¹, ², and ³ are considered numbers as well. ++ switch name[3:] { ++ case "\u00b2", "\u00b3", "\u00b9": ++ return true ++ } ++ return false + } + } ++ ++ // Passing CONIN$ or CONOUT$ to CreateFile opens a console handle. ++ // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles ++ // ++ // While CONIN$ and CONOUT$ aren't documented as being files, ++ // they behave the same as CON. For example, ./CONIN$ also opens the console input. ++ if len(name) == 6 && name[5] == '$' && equalFold(name, "CONIN$") { ++ return true ++ } ++ if len(name) == 7 && name[6] == '$' && equalFold(name, "CONOUT$") { ++ return true ++ } + return false + } + ++func equalFold(a, b string) bool { ++ if len(a) != len(b) { ++ return false ++ } ++ for i := 0; i < len(a); i++ { ++ if toUpper(a[i]) != toUpper(b[i]) { ++ return false ++ } ++ } ++ return true ++} ++ + func toUpper(c byte) byte { + if 'a' <= c && c <= 'z' { + return c - ('a' - 'A') +diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go +index 9b1f5ed7c0..09d5bbb3a3 100644 +--- a/src/path/filepath/path.go ++++ b/src/path/filepath/path.go +@@ -170,6 +170,7 @@ func Clean(path string) string { + out.append('.') + } + ++ postClean(&out) // avoid creating absolute paths on Windows + return FromSlash(out.string()) + } + +diff --git a/src/path/filepath/path_nonwindows.go b/src/path/filepath/path_nonwindows.go +new file mode 100644 +index 0000000000..db69f0228b +--- /dev/null ++++ b/src/path/filepath/path_nonwindows.go +@@ -0,0 +1,9 @@ ++// Copyright 2023 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++//go:build !windows ++ ++package filepath ++ ++func postClean(out *lazybuf) {} +diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go +index 9a57920dd7..27c38ebe6a 100644 +--- a/src/path/filepath/path_test.go ++++ b/src/path/filepath/path_test.go +@@ -7,7 +7,6 @@ package filepath_test + import ( + "errors" + "fmt" +- "internal/testenv" + "io/fs" + "os" + "path/filepath" +@@ -17,6 +16,8 @@ import ( + "strings" + "syscall" + "testing" ++ ++ "internal/testenv" + ) + + type PathTest struct { +@@ -103,6 +104,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) { +@@ -138,6 +142,85 @@ func TestClean(t *testing.T) { + } + } + ++type IsLocalTest struct { ++ path string ++ isLocal bool ++} ++ ++var islocaltests = []IsLocalTest{ ++ {"", false}, ++ {".", true}, ++ {"..", false}, ++ {"../a", false}, ++ {"/", false}, ++ {"/a", false}, ++ {"/a/../..", false}, ++ {"a", true}, ++ {"a/../a", true}, ++ {"a/", true}, ++ {"a/.", true}, ++ {"a/./b/./c", true}, ++ {`a/../b:/../../c`, false}, ++} ++ ++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}, ++ {`C:`, false}, ++ {`C:\a`, false}, ++ {`..\a`, false}, ++ {`a/../c:`, false}, ++ {`CONIN$`, false}, ++ {`conin$`, false}, ++ {`CONOUT$`, false}, ++ {`conout$`, false}, ++ {`dollar$`, true}, // not a special file name ++} ++ ++var plan9islocaltests = []IsLocalTest{ ++ {"#a", false}, ++} ++ ++func TestIsLocal(t *testing.T) { ++ tests := islocaltests ++ if runtime.GOOS == "windows" { ++ tests = append(tests, winislocaltests...) ++ } ++ if runtime.GOOS == "plan9" { ++ tests = append(tests, plan9islocaltests...) ++ } ++ for _, test := range tests { ++ if got := filepath.IsLocal(test.path); got != test.isLocal { ++ t.Errorf("IsLocal(%q) = %v, want %v", test.path, got, test.isLocal) ++ } ++ } ++} ++ + const sep = filepath.Separator + + var slashtests = []PathTest{ +@@ -299,8 +382,11 @@ var winjointests = []JoinTest{ + {[]string{`\`, `a`, `b`}, `\a\b`}, + {[]string{`\\`, `a`, `b`}, `\a\b`}, + {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`}, +- {[]string{`\\a`, `b`, `c`}, `\a\b\c`}, +- {[]string{`\\a\`, `b`, `c`}, `\a\b\c`}, ++ {[]string{`\\a`, `b`, `c`}, `\\a\b\c`}, ++ {[]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) { +@@ -805,6 +891,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) { +@@ -1279,7 +1367,8 @@ type VolumeNameTest struct { + var volumenametests = []VolumeNameTest{ + {`c:/foo/bar`, `c:`}, + {`c:`, `c:`}, +- {`2:`, ``}, ++ {`c:\`, `c:`}, ++ {`2:`, `2:`}, + {``, ``}, + {`\\\host`, ``}, + {`\\\host\`, ``}, +@@ -1298,7 +1387,24 @@ var volumenametests = []VolumeNameTest{ + {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`}, + {`//host/share//foo///bar////baz`, `//host/share`}, + {`\\host\share\foo\..\bar`, `\\host\share`}, +- {`//host/share/foo/../bar`, `//host/share`}, ++ {`//host/share/foo/../bar`, `\\host\share`}, ++ {`//.`, `\\.`}, ++ {`//./`, `\\.\`}, ++ {`//./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) { +@@ -1571,3 +1677,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()) ++ } ++ } ++} +diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go +index b4d8ac3301..8c5513737d 100644 +--- a/src/path/filepath/path_windows.go ++++ b/src/path/filepath/path_windows.go +@@ -5,8 +5,11 @@ + package filepath + + import ( ++ "os" + "strings" + "syscall" ++ ++ "internal/safefilepath" + ) + + func isSlash(c uint8) bool { +@@ -22,18 +25,37 @@ var reservedNames = []string{ + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", + } + +-// isReservedName returns true, if path is Windows reserved name. +-// See reservedNames for the full list. +-func isReservedName(path string) bool { +- if len(path) == 0 { ++func isLocal(path string) bool { ++ if path == "" { ++ return false ++ } ++ if isSlash(path[0]) { ++ // Path rooted in the current drive. ++ return false ++ } ++ if strings.IndexByte(path, ':') >= 0 { ++ // Colons are only valid when marking a drive letter ("C:foo"). ++ // Rejecting any path with a colon is conservative but safe. + return false + } +- for _, reserved := range reservedNames { +- if strings.EqualFold(path, reserved) { +- return true ++ hasDots := false // contains . or .. path elements ++ for p := path; p != ""; { ++ var part string ++ part, p, _ = cutPath(p) ++ if part == "." || part == ".." { ++ hasDots = true + } ++ if safefilepath.IsReservedName(part) { ++ return false ++ } ++ } ++ if hasDots { ++ path = Clean(path) ++ } ++ if path == ".." || strings.HasPrefix(path, `..\`) { ++ return false + } +- return false ++ return true + } + + // IsAbs reports whether the path is absolute. +@@ -58,40 +80,110 @@ func IsAbs(path string) (b bool) { + + // volumeNameLen returns length of the leading volume name on Windows. + // It returns 0 elsewhere. ++// ++// See: ++// https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats ++// https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + func volumeNameLen(path string) int { +- if len(path) < 2 { ++ switch { ++ case len(path) >= 2 && path[1] == ':': ++ // Path starts with a drive letter. ++ // ++ // Not all Windows functions necessarily enforce the requirement that ++ // drive letters be in the set A-Z, and we don't try to here. ++ // ++ // We don't handle the case of a path starting with a non-ASCII character, ++ // in which case the "drive letter" might be multiple bytes long. ++ return 2 ++ ++ case len(path) == 0 || !isSlash(path[0]): ++ // Path does not have a volume component. + return 0 ++ ++ case pathHasPrefixFold(path, `\\.\UNC`): ++ // We're going to treat the UNC host and share as part of the volume ++ // prefix for historical reasons, but this isn't really principled; ++ // Windows's own GetFullPathName will happily remove the first ++ // component of the path in this space, converting ++ // \\.\unc\a\b\..\c into \\.\unc\a\c. ++ return uncLen(path, len(`\\.\UNC\`)) ++ ++ case pathHasPrefixFold(path, `\\.`): ++ // Path starts with \\., and is a Local Device path. ++ // ++ // We currently treat the next component after the \\.\ prefix ++ // as part of the volume name, although there doesn't seem to be ++ // a principled reason to do this. ++ if len(path) == 3 { ++ return 3 // exactly \\. ++ } ++ _, rest, ok := cutPath(path[4:]) ++ if !ok { ++ return len(path) ++ } ++ return len(path) - len(rest) - 1 ++ ++ case pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`): ++ // Path starts with \\?\ or \??\, and is a Root Local Device path. ++ // ++ // While Windows usually treats / and \ as equivalent, ++ // /??/ does not seem to be recognized as a Root Local Device path. ++ // We treat it as one anyway here to be safe. ++ return 3 ++ ++ case len(path) >= 2 && isSlash(path[1]): ++ // Path starts with \\, and is a UNC path. ++ return uncLen(path, 2) + } +- // with drive letter +- c := path[0] +- if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { +- return 2 ++ return 0 ++} ++ ++// pathHasPrefixFold tests whether the path s begins with prefix, ++// ignoring case and treating all path separators as equivalent. ++// If s is longer than prefix, then s[len(prefix)] must be a path separator. ++func pathHasPrefixFold(s, prefix string) bool { ++ if len(s) < len(prefix) { ++ return false + } +- // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx +- if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) && +- !isSlash(path[2]) && path[2] != '.' { +- // first, leading `\\` and next shouldn't be `\`. its server name. +- for n := 3; n < l-1; n++ { +- // second, next '\' shouldn't be repeated. +- if isSlash(path[n]) { +- n++ +- // third, following something characters. its share name. +- if !isSlash(path[n]) { +- if path[n] == '.' { +- break +- } +- for ; n < l; n++ { +- if isSlash(path[n]) { +- break +- } +- } +- return n +- } +- break ++ for i := 0; i < len(prefix); i++ { ++ if isSlash(prefix[i]) { ++ if !isSlash(s[i]) { ++ return false + } ++ } else if toUpper(prefix[i]) != toUpper(s[i]) { ++ return false + } + } +- return 0 ++ if len(s) > len(prefix) && !isSlash(s[len(prefix)]) { ++ return false ++ } ++ return true ++} ++ ++// uncLen returns the length of the volume prefix of a UNC path. ++// prefixLen is the prefix prior to the start of the UNC host; ++// for example, for "//host/share", the prefixLen is len("//")==2. ++func uncLen(path string, prefixLen int) int { ++ count := 0 ++ for i := prefixLen; i < len(path); i++ { ++ if isSlash(path[i]) { ++ count++ ++ if count == 2 { ++ return i ++ } ++ } ++ } ++ return len(path) ++} ++ ++// cutPath slices path around the first path separator. ++func cutPath(path string) (before, after string, found bool) { ++ for i := range path { ++ if isSlash(path[i]) { ++ return path[:i], path[i+1:], true ++ } ++ } ++ return path, "", false + } + + // HasPrefix exists for historical compatibility and should not be used. +@@ -151,9 +243,44 @@ func abs(path string) (string, error) { + } + + func join(elem []string) string { +- for i, e := range elem { +- if e != "" { +- return joinNonEmpty(elem[i:]) ++ var b strings.Builder ++ var lastChar byte ++ for _, e := range elem { ++ switch { ++ case b.Len() == 0: ++ // Add the first non-empty path element unchanged. ++ case isSlash(lastChar): ++ // If the path ends in a slash, strip any leading slashes from the next ++ // path element to avoid creating a UNC path (any path starting with "\\") ++ // from non-UNC elements. ++ // ++ // The correct behavior for Join when the first element is an incomplete UNC ++ // path (for example, "\\") is underspecified. We currently join subsequent ++ // elements so Join("\\", "host", "share") produces "\\host\share". ++ for len(e) > 0 && isSlash(e[0]) { ++ e = e[1:] ++ } ++ // If the path is \ and the next path element is ??, ++ // add an extra .\ to create \.\?? rather than \??\ ++ // (a Root Local Device path). ++ if b.Len() == 1 && pathHasPrefixFold(e, "??") { ++ b.WriteString(`.\`) ++ } ++ case lastChar == ':': ++ // If the path ends in a colon, keep the path relative to the current directory ++ // on a drive and don't add a separator. Preserve leading slashes in the next ++ // path element, which may make the path absolute. ++ // ++ // Join(`C:`, `f`) = `C:f` ++ // Join(`C:`, `\f`) = `C:\f` ++ default: ++ // In all other cases, add a separator between elements. ++ b.WriteByte('\\') ++ lastChar = '\\' ++ } ++ if len(e) > 0 { ++ b.WriteString(e) ++ lastChar = e[len(e)-1] + } + } + return "" +@@ -202,3 +329,29 @@ func isUNC(path string) bool { + func sameWord(a, b string) bool { + return strings.EqualFold(a, b) + } ++ ++// postClean adjusts the results of Clean to avoid turning a relative path ++// into an absolute or rooted one. ++func postClean(out *lazybuf) { ++ if out.volLen != 0 || out.buf == nil { ++ return ++ } ++ // If a ':' appears in the path element at the start of a path, ++ // insert a .\ at the beginning to avoid converting relative paths ++ // like a/../c: into c:. ++ for _, c := range out.buf { ++ if os.IsPathSeparator(c) { ++ break ++ } ++ if c == ':' { ++ out.prepend('.', Separator) ++ return ++ } ++ } ++ // If a path begins with \??\, insert a \. at the beginning ++ // to avoid converting paths like \a\..\??\c:\x into \??\c:\x ++ // (equivalent to c:\x). ++ if len(out.buf) >= 3 && os.IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' { ++ out.prepend(Separator, '.') ++ } ++} +-- +2.42.0 + From 04756e0f933f2ed2e56a548397d8a3c2d6848563 Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Tue, 7 Nov 2023 12:14:55 -0800 Subject: [PATCH 03/12] update specfile to add patch --- projects/golang/go/1.19/rpmbuild/SPECS/golang.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/golang/go/1.19/rpmbuild/SPECS/golang.spec b/projects/golang/go/1.19/rpmbuild/SPECS/golang.spec index e94b8bd1c..9c2bf3a3c 100644 --- a/projects/golang/go/1.19/rpmbuild/SPECS/golang.spec +++ b/projects/golang/go/1.19/rpmbuild/SPECS/golang.spec @@ -162,6 +162,7 @@ Patch1: 0001-go-1.19.12-eks-html-template-support-HTML-lik.patch Patch2: 0002-go-1.19.12-eks-html-template-properly-handle-.patch Patch3: 0003-go-1.19.13-eks-cmd-compile-use-absolute-file-.patch Patch4: 0004-go-1.19-13-eks-net-http-regenerate-h2_bundle-.patch +Patch5: 0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch Patch102: 0102-syscall-expose-IfInfomsg.X__ifi_pad-on-s390x.patch Patch103: 0103-cmd-go-disable-Google-s-proxy-and-sumdb.patch @@ -541,6 +542,9 @@ fi %endif %changelog +* Tue Nov 07 2023 Cameron Rozean - 1.19.13-6 +- Includes security fix for CVE-2023-45283 and CVE-2023-45284 + * Thu Oct 12 2023 Cameron Rozean - 1.19.13-5 - Includes security fix for CVE-2023-39325 From cb74f2e47c3231cf8514577f0d4c839c021a03ce Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Tue, 7 Nov 2023 12:28:21 -0800 Subject: [PATCH 04/12] update patch information --- ...o-1.19-13-eks-path-filepath-fix-various-issu.patch | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch index 17cbccd7f..babf2c3cd 100644 --- a/projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch +++ b/projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch @@ -4,6 +4,17 @@ Date: Fri, 1 Sep 2023 11:17:19 -0700 Subject: [PATCH] [release-branch.go1.20] path/filepath: fix various issues in parsing Windows paths +# AWS EKS + +Backported To: go-1.19.13-eks +Backported On: Tue, 07 Nov 2023 +Backported By: rcrozean@amazon.com +Backported From: release-branch.go1.20 +Source Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae + +# Original Information + + 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 From 369f152a22f9d475018fbd552f2c028c2d8c5109 Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Tue, 7 Nov 2023 12:57:24 -0800 Subject: [PATCH 05/12] update patch in gospec to match convention --- ...=> 0004-go-1.19.13-eks-net-http-regenerate-h2_bundle-.patch} | 0 ...=> 0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch} | 0 projects/golang/go/1.19/rpmbuild/SPECS/golang.spec | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename projects/golang/go/1.19/patches/{0004-go-1.19-13-eks-net-http-regenerate-h2_bundle-.patch => 0004-go-1.19.13-eks-net-http-regenerate-h2_bundle-.patch} (100%) rename projects/golang/go/1.19/patches/{0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch => 0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch} (100%) diff --git a/projects/golang/go/1.19/patches/0004-go-1.19-13-eks-net-http-regenerate-h2_bundle-.patch b/projects/golang/go/1.19/patches/0004-go-1.19.13-eks-net-http-regenerate-h2_bundle-.patch similarity index 100% rename from projects/golang/go/1.19/patches/0004-go-1.19-13-eks-net-http-regenerate-h2_bundle-.patch rename to projects/golang/go/1.19/patches/0004-go-1.19.13-eks-net-http-regenerate-h2_bundle-.patch diff --git a/projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch similarity index 100% rename from projects/golang/go/1.19/patches/0005-go-1.19-13-eks-path-filepath-fix-various-issu.patch rename to projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch diff --git a/projects/golang/go/1.19/rpmbuild/SPECS/golang.spec b/projects/golang/go/1.19/rpmbuild/SPECS/golang.spec index 9c2bf3a3c..c68a9573a 100644 --- a/projects/golang/go/1.19/rpmbuild/SPECS/golang.spec +++ b/projects/golang/go/1.19/rpmbuild/SPECS/golang.spec @@ -161,7 +161,7 @@ Requires: %{name}-src = %{version}-%{release} Patch1: 0001-go-1.19.12-eks-html-template-support-HTML-lik.patch Patch2: 0002-go-1.19.12-eks-html-template-properly-handle-.patch Patch3: 0003-go-1.19.13-eks-cmd-compile-use-absolute-file-.patch -Patch4: 0004-go-1.19-13-eks-net-http-regenerate-h2_bundle-.patch +Patch4: 0004-go-1.19.13-eks-net-http-regenerate-h2_bundle-.patch Patch5: 0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch Patch102: 0102-syscall-expose-IfInfomsg.X__ifi_pad-on-s390x.patch From 6aa412d38ee7e4cc22b5767aa51957d3b8e97009 Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Tue, 7 Nov 2023 13:06:32 -0800 Subject: [PATCH 06/12] remove extra quote at end of readme --- projects/golang/go/1.19/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/golang/go/1.19/README.md b/projects/golang/go/1.19/README.md index 27064d5cd..c2a049374 100644 --- a/projects/golang/go/1.19/README.md +++ b/projects/golang/go/1.19/README.md @@ -24,4 +24,4 @@ Tracking Tag: `go1.19.13` The patches in `./patches` include relevant utility fixes for go `1.19`. ### Spec -The RPM spec file in `./rpmbuild/SPECS` is sourced from the go 1.19 SRPM available on Fedora, and modified to include the relevant patches and build the `go1.19.13` source." +The RPM spec file in `./rpmbuild/SPECS` is sourced from the go 1.19 SRPM available on Fedora, and modified to include the relevant patches and build the `go1.19.13` source. From 38b32b0ec17fe8b35c0f566485b033eddd43ddaf Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Tue, 7 Nov 2023 13:47:35 -0800 Subject: [PATCH 07/12] update patch to include additional commit for required tests and functions --- ...3-eks-path-filepath-fix-various-issu.patch | 247 +++++++++++++++--- 1 file changed, 209 insertions(+), 38 deletions(-) diff --git a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch index babf2c3cd..2d7291b14 100644 --- a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch +++ b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch @@ -1,8 +1,7 @@ -From 4c734c9a4a25f16f26a05a7c71763654f8407ae7 Mon Sep 17 00:00:00 2001 +From ce5b0672ce8daa1f8583f92f47582b85ffbb727f Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 1 Sep 2023 11:17:19 -0700 -Subject: [PATCH] [release-branch.go1.20] path/filepath: fix various issues in - parsing Windows paths +Subject: [PATCH] path/filepath: fix various issues in parsing Windows paths # AWS EKS @@ -10,10 +9,14 @@ Backported To: go-1.19.13-eks Backported On: Tue, 07 Nov 2023 Backported By: rcrozean@amazon.com Backported From: release-branch.go1.20 -Source Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae +Source Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae \ + https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 -# Original Information +In addition to the CVE fix https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae, +https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 was cherry-picked to include expected functions and +tests expected in the CVE fix commit +# Original Information On Windows, A root local device path is a path which begins with \\?\ or \??\. A root local device path accesses the DosDevices @@ -62,16 +65,46 @@ Reviewed-by: Cherry Mui Reviewed-on: https://go-review.googlesource.com/c/go/+/539276 Auto-Submit: Heschi Kreinick LUCI-TryBot-Result: Go LUCI + +path/filepath: add IsLocal + +IsLocal reports whether a path lexically refers to a location +contained within the directory in which it is evaluated. +It identifies paths that are absolute, escape a directory +with ".." elements, and (on Windows) paths that reference +reserved device names. + +For #56219. + +Change-Id: I35edfa3ce77b40b8e66f1fc8e0ff73cfd06f2313 +Reviewed-on: https://go-review.googlesource.com/c/go/+/449239 +Run-TryBot: Damien Neil +Reviewed-by: Joseph Tsai +TryBot-Result: Gopher Robot +Reviewed-by: Ian Lance Taylor +Reviewed-by: Ian Lance Taylor +Reviewed-by: Joedian Reid --- + api/next/56219.txt | 1 + src/go/build/deps_test.go | 2 +- - src/internal/safefilepath/path_windows.go | 98 ++++++--- - src/path/filepath/path.go | 1 + + src/internal/safefilepath/path_windows.go | 98 ++++++-- + src/path/filepath/path.go | 41 +++ src/path/filepath/path_nonwindows.go | 9 + - src/path/filepath/path_test.go | 141 ++++++++++++- - src/path/filepath/path_windows.go | 229 ++++++++++++++++++---- - 6 files changed, 410 insertions(+), 70 deletions(-) + src/path/filepath/path_plan9.go | 4 + + src/path/filepath/path_test.go | 138 +++++++++- + src/path/filepath/path_unix.go | 4 + + src/path/filepath/path_windows.go | 294 +++++++++++++++++++--- + 9 files changed, 522 insertions(+), 69 deletions(-) + create mode 100644 api/next/56219.txt create mode 100644 src/path/filepath/path_nonwindows.go +diff --git a/api/next/56219.txt b/api/next/56219.txt +new file mode 100644 +index 0000000000..6379c06a2e +--- /dev/null ++++ b/api/next/56219.txt +@@ -0,0 +1 @@ ++pkg path/filepath, func IsLocal(string) bool #56219 diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 69ba8b7f52..83da402bb4 100644 --- a/src/go/build/deps_test.go @@ -225,10 +258,10 @@ index 909c150edc..7cfd6ce2ea 100644 if 'a' <= c && c <= 'z' { return c - ('a' - 'A') diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go -index 9b1f5ed7c0..09d5bbb3a3 100644 +index 9b1f5ed7c0..1c0d18531e 100644 --- a/src/path/filepath/path.go +++ b/src/path/filepath/path.go -@@ -170,6 +170,7 @@ func Clean(path string) string { +@@ -170,9 +170,50 @@ func Clean(path string) string { out.append('.') } @@ -236,6 +269,49 @@ index 9b1f5ed7c0..09d5bbb3a3 100644 return FromSlash(out.string()) } ++// IsLocal reports whether path, using lexical analysis only, has all of these properties: ++// ++// - is within the subtree rooted at the directory in which path is evaluated ++// - is not an absolute path ++// - is not empty ++// - on Windows, is not a reserved name such as "NUL" ++// ++// If IsLocal(path) returns true, then ++// Join(base, path) will always produce a path contained within base and ++// Clean(path) will always produce an unrooted path with no ".." path elements. ++// ++// IsLocal is a purely lexical operation. ++// In particular, it does not account for the effect of any symbolic links ++// that may exist in the filesystem. ++func IsLocal(path string) bool { ++ return isLocal(path) ++} ++ ++func unixIsLocal(path string) bool { ++ if IsAbs(path) || path == "" { ++ return false ++ } ++ hasDots := false ++ for p := path; p != ""; { ++ var part string ++ part, p, _ = strings.Cut(p, "/") ++ if part == "." || part == ".." { ++ hasDots = true ++ break ++ } ++ } ++ if hasDots { ++ path = Clean(path) ++ } ++ if path == ".." || strings.HasPrefix(path, "../") { ++ return false ++ } ++ return true ++} ++ + // ToSlash returns the result of replacing each separator character + // in path with a slash ('/') character. Multiple separators are + // replaced by multiple slashes. diff --git a/src/path/filepath/path_nonwindows.go b/src/path/filepath/path_nonwindows.go new file mode 100644 index 0000000000..db69f0228b @@ -251,8 +327,23 @@ index 0000000000..db69f0228b +package filepath + +func postClean(out *lazybuf) {} +diff --git a/src/path/filepath/path_plan9.go b/src/path/filepath/path_plan9.go +index ec792fc831..453206aee3 100644 +--- a/src/path/filepath/path_plan9.go ++++ b/src/path/filepath/path_plan9.go +@@ -6,6 +6,10 @@ package filepath + + import "strings" + ++func isLocal(path string) bool { ++ return unixIsLocal(path) ++} ++ + // IsAbs reports whether the path is absolute. + func IsAbs(path string) bool { + return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go -index 9a57920dd7..27c38ebe6a 100644 +index 9a57920dd7..c18b0f124f 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -7,7 +7,6 @@ package filepath_test @@ -282,7 +373,7 @@ index 9a57920dd7..27c38ebe6a 100644 } func TestClean(t *testing.T) { -@@ -138,6 +142,85 @@ func TestClean(t *testing.T) { +@@ -138,6 +142,82 @@ func TestClean(t *testing.T) { } } @@ -304,7 +395,6 @@ index 9a57920dd7..27c38ebe6a 100644 + {"a/", true}, + {"a/.", true}, + {"a/./b/./c", true}, -+ {`a/../b:/../../c`, false}, +} + +var winislocaltests = []IsLocalTest{ @@ -332,18 +422,16 @@ index 9a57920dd7..27c38ebe6a 100644 + {"lpt1", false}, + {"LPT1", false}, + {"lpt³", false}, ++ {"nul.", false}, ++ {"nul.txt", false}, ++ {"com1", false}, + {"./nul", false}, ++ {"a/nul.txt/b", false}, + {`\`, false}, + {`\a`, false}, + {`C:`, false}, + {`C:\a`, false}, + {`..\a`, false}, -+ {`a/../c:`, false}, -+ {`CONIN$`, false}, -+ {`conin$`, false}, -+ {`CONOUT$`, false}, -+ {`conout$`, false}, -+ {`dollar$`, true}, // not a special file name +} + +var plan9islocaltests = []IsLocalTest{ @@ -368,7 +456,7 @@ index 9a57920dd7..27c38ebe6a 100644 const sep = filepath.Separator var slashtests = []PathTest{ -@@ -299,8 +382,11 @@ var winjointests = []JoinTest{ +@@ -299,8 +379,11 @@ var winjointests = []JoinTest{ {[]string{`\`, `a`, `b`}, `\a\b`}, {[]string{`\\`, `a`, `b`}, `\a\b`}, {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`}, @@ -382,7 +470,7 @@ index 9a57920dd7..27c38ebe6a 100644 } func TestJoin(t *testing.T) { -@@ -805,6 +891,8 @@ var winisabstests = []IsAbsTest{ +@@ -805,6 +888,8 @@ var winisabstests = []IsAbsTest{ {`\\host\share\`, true}, {`\\host\share\foo`, true}, {`//host/share/foo/bar`, true}, @@ -391,7 +479,7 @@ index 9a57920dd7..27c38ebe6a 100644 } func TestIsAbs(t *testing.T) { -@@ -1279,7 +1367,8 @@ type VolumeNameTest struct { +@@ -1279,7 +1364,8 @@ type VolumeNameTest struct { var volumenametests = []VolumeNameTest{ {`c:/foo/bar`, `c:`}, {`c:`, `c:`}, @@ -401,7 +489,7 @@ index 9a57920dd7..27c38ebe6a 100644 {``, ``}, {`\\\host`, ``}, {`\\\host\`, ``}, -@@ -1298,7 +1387,24 @@ var volumenametests = []VolumeNameTest{ +@@ -1298,7 +1384,24 @@ var volumenametests = []VolumeNameTest{ {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`}, {`//host/share//foo///bar////baz`, `//host/share`}, {`\\host\share\foo\..\bar`, `\\host\share`}, @@ -427,7 +515,7 @@ index 9a57920dd7..27c38ebe6a 100644 } func TestVolumeName(t *testing.T) { -@@ -1571,3 +1677,28 @@ func TestIssue51617(t *testing.T) { +@@ -1571,3 +1674,28 @@ func TestIssue51617(t *testing.T) { t.Errorf("got directories %v, want %v", saw, want) } } @@ -456,8 +544,23 @@ index 9a57920dd7..27c38ebe6a 100644 + } + } +} +diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go +index 93fdfdd8a0..ab1d08d356 100644 +--- a/src/path/filepath/path_unix.go ++++ b/src/path/filepath/path_unix.go +@@ -8,6 +8,10 @@ package filepath + + import "strings" + ++func isLocal(path string) bool { ++ return unixIsLocal(path) ++} ++ + // IsAbs reports whether the path is absolute. + func IsAbs(path string) bool { + return strings.HasPrefix(path, "/") diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go -index b4d8ac3301..8c5513737d 100644 +index b4d8ac3301..84e495b698 100644 --- a/src/path/filepath/path_windows.go +++ b/src/path/filepath/path_windows.go @@ -5,8 +5,11 @@ @@ -472,7 +575,7 @@ index b4d8ac3301..8c5513737d 100644 ) func isSlash(c uint8) bool { -@@ -22,18 +25,37 @@ var reservedNames = []string{ +@@ -22,20 +25,106 @@ var reservedNames = []string{ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", } @@ -491,20 +594,87 @@ index b4d8ac3301..8c5513737d 100644 + if strings.IndexByte(path, ':') >= 0 { + // Colons are only valid when marking a drive letter ("C:foo"). + // Rejecting any path with a colon is conservative but safe. ++ return false ++ } ++ hasDots := false // contains . or .. path elements ++ for p := path; p != ""; { ++ var part string ++ part, p, _ = cutPath(p) ++ if part == "." || part == ".." { ++ hasDots = true ++ } ++ if safefilepath.IsReservedName(part) { ++ return false ++ } ++ } ++ if hasDots { ++ path = Clean(path) ++ } ++ if path == ".." || strings.HasPrefix(path, `..\`) { return false } - for _, reserved := range reservedNames { - if strings.EqualFold(path, reserved) { - return true ++ return true ++} ++ ++// isReservedName reports if name is a Windows reserved device name. ++// It does not detect names with an extension, which are also reserved on some Windows versions. ++// ++// For details, search for PRN in ++// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. ++func isReservedName(name string) bool { ++ if 3 <= len(name) && len(name) <= 4 { ++ switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { ++ case "CON", "PRN", "AUX", "NUL": ++ return len(name) == 3 ++ case "COM", "LPT": ++ return len(name) == 4 && '1' <= name[3] && name[3] <= '9' + } + } + return false + } + ++func isLocal(path string) bool { ++ if path == "" { ++ return false ++ } ++ if isSlash(path[0]) { ++ // Path rooted in the current drive. ++ return false ++ } ++ if strings.IndexByte(path, ':') >= 0 { ++ // Colons are only valid when marking a drive letter ("C:foo"). ++ // Rejecting any path with a colon is conservative but safe. ++ return false ++ } + hasDots := false // contains . or .. path elements + for p := path; p != ""; { + var part string + part, p, _ = cutPath(p) + if part == "." || part == ".." { + hasDots = true - } -+ if safefilepath.IsReservedName(part) { -+ return false ++ } ++ // Trim the extension and look for a reserved name. ++ base, _, hasExt := strings.Cut(part, ".") ++ if isReservedName(base) { ++ if !hasExt { ++ return false ++ } ++ // The path element is a reserved name with an extension. Some Windows ++ // versions consider this a reserved name, while others do not. Use ++ // FullPath to see if the name is reserved. ++ // ++ // FullPath will convert references to reserved device names to their ++ // canonical form: \\.\${DEVICE_NAME} ++ // ++ // FullPath does not perform this conversion for paths which contain ++ // a reserved device name anywhere other than in the last element, ++ // so check the part rather than the full path. ++ if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` { ++ return false ++ } + } + } + if hasDots { @@ -512,13 +682,14 @@ index b4d8ac3301..8c5513737d 100644 + } + if path == ".." || strings.HasPrefix(path, `..\`) { + return false - } -- return false ++ } + return true - } - ++} ++ // IsAbs reports whether the path is absolute. -@@ -58,40 +80,110 @@ func IsAbs(path string) (b bool) { + func IsAbs(path string) (b bool) { + if isReservedName(path) { +@@ -58,40 +147,110 @@ func IsAbs(path string) (b bool) { // volumeNameLen returns length of the leading volume name on Windows. // It returns 0 elsewhere. @@ -656,7 +827,7 @@ index b4d8ac3301..8c5513737d 100644 } // HasPrefix exists for historical compatibility and should not be used. -@@ -151,9 +243,44 @@ func abs(path string) (string, error) { +@@ -151,9 +310,44 @@ func abs(path string) (string, error) { } func join(elem []string) string { @@ -704,7 +875,7 @@ index b4d8ac3301..8c5513737d 100644 } } return "" -@@ -202,3 +329,29 @@ func isUNC(path string) bool { +@@ -202,3 +396,29 @@ func isUNC(path string) bool { func sameWord(a, b string) bool { return strings.EqualFold(a, b) } From 36b836a02cd4859b43f5c98ed7d3de55e0ac2eeb Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Tue, 7 Nov 2023 14:59:27 -0800 Subject: [PATCH 08/12] correct the patches and the api/go1.19.txt file --- ...3-eks-path-filepath-fix-various-issu.patch | 147 +++++------------- 1 file changed, 41 insertions(+), 106 deletions(-) diff --git a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch index 2d7291b14..dda2d4df1 100644 --- a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch +++ b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch @@ -1,6 +1,6 @@ -From ce5b0672ce8daa1f8583f92f47582b85ffbb727f Mon Sep 17 00:00:00 2001 +From 25b961b528a73ea9f2b6424f88c2ab1732eb7e9d Mon Sep 17 00:00:00 2001 From: Damien Neil -Date: Fri, 1 Sep 2023 11:17:19 -0700 +Date: Wed, 9 Nov 2022 17:49:44 -0800 Subject: [PATCH] path/filepath: fix various issues in parsing Windows paths # AWS EKS @@ -14,7 +14,9 @@ Source Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb In addition to the CVE fix https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae, https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 was cherry-picked to include expected functions and -tests expected in the CVE fix commit +tests expected in the CVE fix commit. Additionally, for the purpose of +tests I added the line to api/go1.19.txt which is used for checking the +function calls exist as expected. # Original Information @@ -85,26 +87,30 @@ Reviewed-by: Ian Lance Taylor Reviewed-by: Ian Lance Taylor Reviewed-by: Joedian Reid --- - api/next/56219.txt | 1 + + api/go1.19.txt | 1 + src/go/build/deps_test.go | 2 +- - src/internal/safefilepath/path_windows.go | 98 ++++++-- - src/path/filepath/path.go | 41 +++ + src/internal/safefilepath/path_windows.go | 98 ++++++--- + src/path/filepath/path.go | 41 ++++ src/path/filepath/path_nonwindows.go | 9 + src/path/filepath/path_plan9.go | 4 + - src/path/filepath/path_test.go | 138 +++++++++- + src/path/filepath/path_test.go | 135 ++++++++++++- src/path/filepath/path_unix.go | 4 + - src/path/filepath/path_windows.go | 294 +++++++++++++++++++--- - 9 files changed, 522 insertions(+), 69 deletions(-) - create mode 100644 api/next/56219.txt + src/path/filepath/path_windows.go | 229 ++++++++++++++++++---- + 9 files changed, 453 insertions(+), 70 deletions(-) create mode 100644 src/path/filepath/path_nonwindows.go -diff --git a/api/next/56219.txt b/api/next/56219.txt -new file mode 100644 -index 0000000000..6379c06a2e ---- /dev/null -+++ b/api/next/56219.txt -@@ -0,0 +1 @@ +diff --git a/api/go1.19.txt b/api/go1.19.txt +index 523f752d70..fe9aee3050 100644 +--- a/api/go1.19.txt ++++ b/api/go1.19.txt +@@ -244,6 +244,7 @@ pkg net/url, type URL struct, OmitHost bool #46059 + pkg os/exec, method (*Cmd) Environ() []string #50599 + pkg os/exec, type Cmd struct, Err error #43724 + pkg os/exec, var ErrDot error #43724 +pkg path/filepath, func IsLocal(string) bool #56219 + pkg regexp/syntax, const ErrNestingDepth = "expression nests too deeply" #51684 + pkg regexp/syntax, const ErrNestingDepth ErrorCode #51684 + pkg runtime/debug, func SetMemoryLimit(int64) int64 #48409 diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 69ba8b7f52..83da402bb4 100644 --- a/src/go/build/deps_test.go @@ -343,7 +349,7 @@ index ec792fc831..453206aee3 100644 func IsAbs(path string) bool { return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go -index 9a57920dd7..c18b0f124f 100644 +index 9a57920dd7..b472a228a0 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -7,7 +7,6 @@ package filepath_test @@ -373,7 +379,7 @@ index 9a57920dd7..c18b0f124f 100644 } func TestClean(t *testing.T) { -@@ -138,6 +142,82 @@ func TestClean(t *testing.T) { +@@ -138,6 +142,79 @@ func TestClean(t *testing.T) { } } @@ -422,9 +428,6 @@ index 9a57920dd7..c18b0f124f 100644 + {"lpt1", false}, + {"LPT1", false}, + {"lpt³", false}, -+ {"nul.", false}, -+ {"nul.txt", false}, -+ {"com1", false}, + {"./nul", false}, + {"a/nul.txt/b", false}, + {`\`, false}, @@ -456,7 +459,7 @@ index 9a57920dd7..c18b0f124f 100644 const sep = filepath.Separator var slashtests = []PathTest{ -@@ -299,8 +379,11 @@ var winjointests = []JoinTest{ +@@ -299,8 +376,11 @@ var winjointests = []JoinTest{ {[]string{`\`, `a`, `b`}, `\a\b`}, {[]string{`\\`, `a`, `b`}, `\a\b`}, {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`}, @@ -470,7 +473,7 @@ index 9a57920dd7..c18b0f124f 100644 } func TestJoin(t *testing.T) { -@@ -805,6 +888,8 @@ var winisabstests = []IsAbsTest{ +@@ -805,6 +885,8 @@ var winisabstests = []IsAbsTest{ {`\\host\share\`, true}, {`\\host\share\foo`, true}, {`//host/share/foo/bar`, true}, @@ -479,7 +482,7 @@ index 9a57920dd7..c18b0f124f 100644 } func TestIsAbs(t *testing.T) { -@@ -1279,7 +1364,8 @@ type VolumeNameTest struct { +@@ -1279,7 +1361,8 @@ type VolumeNameTest struct { var volumenametests = []VolumeNameTest{ {`c:/foo/bar`, `c:`}, {`c:`, `c:`}, @@ -489,7 +492,7 @@ index 9a57920dd7..c18b0f124f 100644 {``, ``}, {`\\\host`, ``}, {`\\\host\`, ``}, -@@ -1298,7 +1384,24 @@ var volumenametests = []VolumeNameTest{ +@@ -1298,7 +1381,24 @@ var volumenametests = []VolumeNameTest{ {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`}, {`//host/share//foo///bar////baz`, `//host/share`}, {`\\host\share\foo\..\bar`, `\\host\share`}, @@ -515,7 +518,7 @@ index 9a57920dd7..c18b0f124f 100644 } func TestVolumeName(t *testing.T) { -@@ -1571,3 +1674,28 @@ func TestIssue51617(t *testing.T) { +@@ -1571,3 +1671,28 @@ func TestIssue51617(t *testing.T) { t.Errorf("got directories %v, want %v", saw, want) } } @@ -560,7 +563,7 @@ index 93fdfdd8a0..ab1d08d356 100644 func IsAbs(path string) bool { return strings.HasPrefix(path, "/") diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go -index b4d8ac3301..84e495b698 100644 +index b4d8ac3301..8c5513737d 100644 --- a/src/path/filepath/path_windows.go +++ b/src/path/filepath/path_windows.go @@ -5,8 +5,11 @@ @@ -575,7 +578,7 @@ index b4d8ac3301..84e495b698 100644 ) func isSlash(c uint8) bool { -@@ -22,20 +25,106 @@ var reservedNames = []string{ +@@ -22,18 +25,37 @@ var reservedNames = []string{ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", } @@ -594,87 +597,20 @@ index b4d8ac3301..84e495b698 100644 + if strings.IndexByte(path, ':') >= 0 { + // Colons are only valid when marking a drive letter ("C:foo"). + // Rejecting any path with a colon is conservative but safe. -+ return false -+ } -+ hasDots := false // contains . or .. path elements -+ for p := path; p != ""; { -+ var part string -+ part, p, _ = cutPath(p) -+ if part == "." || part == ".." { -+ hasDots = true -+ } -+ if safefilepath.IsReservedName(part) { -+ return false -+ } -+ } -+ if hasDots { -+ path = Clean(path) -+ } -+ if path == ".." || strings.HasPrefix(path, `..\`) { return false } - for _, reserved := range reservedNames { - if strings.EqualFold(path, reserved) { - return true -+ return true -+} -+ -+// isReservedName reports if name is a Windows reserved device name. -+// It does not detect names with an extension, which are also reserved on some Windows versions. -+// -+// For details, search for PRN in -+// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. -+func isReservedName(name string) bool { -+ if 3 <= len(name) && len(name) <= 4 { -+ switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { -+ case "CON", "PRN", "AUX", "NUL": -+ return len(name) == 3 -+ case "COM", "LPT": -+ return len(name) == 4 && '1' <= name[3] && name[3] <= '9' - } - } - return false - } - -+func isLocal(path string) bool { -+ if path == "" { -+ return false -+ } -+ if isSlash(path[0]) { -+ // Path rooted in the current drive. -+ return false -+ } -+ if strings.IndexByte(path, ':') >= 0 { -+ // Colons are only valid when marking a drive letter ("C:foo"). -+ // Rejecting any path with a colon is conservative but safe. -+ return false -+ } + hasDots := false // contains . or .. path elements + for p := path; p != ""; { + var part string + part, p, _ = cutPath(p) + if part == "." || part == ".." { + hasDots = true -+ } -+ // Trim the extension and look for a reserved name. -+ base, _, hasExt := strings.Cut(part, ".") -+ if isReservedName(base) { -+ if !hasExt { -+ return false -+ } -+ // The path element is a reserved name with an extension. Some Windows -+ // versions consider this a reserved name, while others do not. Use -+ // FullPath to see if the name is reserved. -+ // -+ // FullPath will convert references to reserved device names to their -+ // canonical form: \\.\${DEVICE_NAME} -+ // -+ // FullPath does not perform this conversion for paths which contain -+ // a reserved device name anywhere other than in the last element, -+ // so check the part rather than the full path. -+ if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` { -+ return false -+ } + } ++ if safefilepath.IsReservedName(part) { ++ return false + } + } + if hasDots { @@ -682,14 +618,13 @@ index b4d8ac3301..84e495b698 100644 + } + if path == ".." || strings.HasPrefix(path, `..\`) { + return false -+ } + } +- return false + return true -+} -+ + } + // IsAbs reports whether the path is absolute. - func IsAbs(path string) (b bool) { - if isReservedName(path) { -@@ -58,40 +147,110 @@ func IsAbs(path string) (b bool) { +@@ -58,40 +80,110 @@ func IsAbs(path string) (b bool) { // volumeNameLen returns length of the leading volume name on Windows. // It returns 0 elsewhere. @@ -827,7 +762,7 @@ index b4d8ac3301..84e495b698 100644 } // HasPrefix exists for historical compatibility and should not be used. -@@ -151,9 +310,44 @@ func abs(path string) (string, error) { +@@ -151,9 +243,44 @@ func abs(path string) (string, error) { } func join(elem []string) string { @@ -875,7 +810,7 @@ index b4d8ac3301..84e495b698 100644 } } return "" -@@ -202,3 +396,29 @@ func isUNC(path string) bool { +@@ -202,3 +329,29 @@ func isUNC(path string) bool { func sameWord(a, b string) bool { return strings.EqualFold(a, b) } From 19177b1e6396b8dc47c8a9b45ae94d0db87cea6b Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Tue, 7 Nov 2023 17:33:56 -0800 Subject: [PATCH 09/12] just keep trying --- ...3-eks-path-filepath-fix-various-issu.patch | 303 +++++------------- 1 file changed, 77 insertions(+), 226 deletions(-) diff --git a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch index dda2d4df1..c960da590 100644 --- a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch +++ b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch @@ -1,7 +1,8 @@ -From 25b961b528a73ea9f2b6424f88c2ab1732eb7e9d Mon Sep 17 00:00:00 2001 +From 36ee9a5d9eeff5b6bcc395653bf2c20bcadaaa7f Mon Sep 17 00:00:00 2001 From: Damien Neil -Date: Wed, 9 Nov 2022 17:49:44 -0800 -Subject: [PATCH] path/filepath: fix various issues in parsing Windows paths +Date: Fri, 1 Sep 2023 11:17:19 -0700 +Subject: [PATCH] [release-branch.go1.20] path/filepath: fix various issues in + parsing Windows paths # AWS EKS @@ -67,50 +68,16 @@ Reviewed-by: Cherry Mui Reviewed-on: https://go-review.googlesource.com/c/go/+/539276 Auto-Submit: Heschi Kreinick LUCI-TryBot-Result: Go LUCI - -path/filepath: add IsLocal - -IsLocal reports whether a path lexically refers to a location -contained within the directory in which it is evaluated. -It identifies paths that are absolute, escape a directory -with ".." elements, and (on Windows) paths that reference -reserved device names. - -For #56219. - -Change-Id: I35edfa3ce77b40b8e66f1fc8e0ff73cfd06f2313 -Reviewed-on: https://go-review.googlesource.com/c/go/+/449239 -Run-TryBot: Damien Neil -Reviewed-by: Joseph Tsai -TryBot-Result: Gopher Robot -Reviewed-by: Ian Lance Taylor -Reviewed-by: Ian Lance Taylor -Reviewed-by: Joedian Reid --- - api/go1.19.txt | 1 + src/go/build/deps_test.go | 2 +- src/internal/safefilepath/path_windows.go | 98 ++++++--- - src/path/filepath/path.go | 41 ++++ + src/path/filepath/path.go | 1 + src/path/filepath/path_nonwindows.go | 9 + - src/path/filepath/path_plan9.go | 4 + - src/path/filepath/path_test.go | 135 ++++++++++++- - src/path/filepath/path_unix.go | 4 + - src/path/filepath/path_windows.go | 229 ++++++++++++++++++---- - 9 files changed, 453 insertions(+), 70 deletions(-) + src/path/filepath/path_test.go | 83 +++++++- + src/path/filepath/path_windows.go | 233 ++++++++++++++++------ + 6 files changed, 330 insertions(+), 96 deletions(-) create mode 100644 src/path/filepath/path_nonwindows.go -diff --git a/api/go1.19.txt b/api/go1.19.txt -index 523f752d70..fe9aee3050 100644 ---- a/api/go1.19.txt -+++ b/api/go1.19.txt -@@ -244,6 +244,7 @@ pkg net/url, type URL struct, OmitHost bool #46059 - pkg os/exec, method (*Cmd) Environ() []string #50599 - pkg os/exec, type Cmd struct, Err error #43724 - pkg os/exec, var ErrDot error #43724 -+pkg path/filepath, func IsLocal(string) bool #56219 - pkg regexp/syntax, const ErrNestingDepth = "expression nests too deeply" #51684 - pkg regexp/syntax, const ErrNestingDepth ErrorCode #51684 - pkg runtime/debug, func SetMemoryLimit(int64) int64 #48409 diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 69ba8b7f52..83da402bb4 100644 --- a/src/go/build/deps_test.go @@ -264,10 +231,10 @@ index 909c150edc..7cfd6ce2ea 100644 if 'a' <= c && c <= 'z' { return c - ('a' - 'A') diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go -index 9b1f5ed7c0..1c0d18531e 100644 +index ffb7c7794a..1c0d18531e 100644 --- a/src/path/filepath/path.go +++ b/src/path/filepath/path.go -@@ -170,9 +170,50 @@ func Clean(path string) string { +@@ -170,6 +170,7 @@ func Clean(path string) string { out.append('.') } @@ -275,49 +242,6 @@ index 9b1f5ed7c0..1c0d18531e 100644 return FromSlash(out.string()) } -+// IsLocal reports whether path, using lexical analysis only, has all of these properties: -+// -+// - is within the subtree rooted at the directory in which path is evaluated -+// - is not an absolute path -+// - is not empty -+// - on Windows, is not a reserved name such as "NUL" -+// -+// If IsLocal(path) returns true, then -+// Join(base, path) will always produce a path contained within base and -+// Clean(path) will always produce an unrooted path with no ".." path elements. -+// -+// IsLocal is a purely lexical operation. -+// In particular, it does not account for the effect of any symbolic links -+// that may exist in the filesystem. -+func IsLocal(path string) bool { -+ return isLocal(path) -+} -+ -+func unixIsLocal(path string) bool { -+ if IsAbs(path) || path == "" { -+ return false -+ } -+ hasDots := false -+ for p := path; p != ""; { -+ var part string -+ part, p, _ = strings.Cut(p, "/") -+ if part == "." || part == ".." { -+ hasDots = true -+ break -+ } -+ } -+ if hasDots { -+ path = Clean(path) -+ } -+ if path == ".." || strings.HasPrefix(path, "../") { -+ return false -+ } -+ return true -+} -+ - // ToSlash returns the result of replacing each separator character - // in path with a slash ('/') character. Multiple separators are - // replaced by multiple slashes. diff --git a/src/path/filepath/path_nonwindows.go b/src/path/filepath/path_nonwindows.go new file mode 100644 index 0000000000..db69f0228b @@ -333,23 +257,8 @@ index 0000000000..db69f0228b +package filepath + +func postClean(out *lazybuf) {} -diff --git a/src/path/filepath/path_plan9.go b/src/path/filepath/path_plan9.go -index ec792fc831..453206aee3 100644 ---- a/src/path/filepath/path_plan9.go -+++ b/src/path/filepath/path_plan9.go -@@ -6,6 +6,10 @@ package filepath - - import "strings" - -+func isLocal(path string) bool { -+ return unixIsLocal(path) -+} -+ - // IsAbs reports whether the path is absolute. - func IsAbs(path string) bool { - return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go -index 9a57920dd7..b472a228a0 100644 +index 8c19a6c641..b472a228a0 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -7,7 +7,6 @@ package filepath_test @@ -379,39 +288,17 @@ index 9a57920dd7..b472a228a0 100644 } func TestClean(t *testing.T) { -@@ -138,6 +142,79 @@ func TestClean(t *testing.T) { - } - } - -+type IsLocalTest struct { -+ path string -+ isLocal bool -+} -+ -+var islocaltests = []IsLocalTest{ -+ {"", false}, -+ {".", true}, -+ {"..", false}, -+ {"../a", false}, -+ {"/", false}, -+ {"/a", false}, -+ {"/a/../..", false}, -+ {"a", true}, -+ {"a/../a", true}, -+ {"a/", true}, -+ {"a/.", true}, -+ {"a/./b/./c", true}, -+} -+ -+var winislocaltests = []IsLocalTest{ -+ {"NUL", false}, -+ {"nul", false}, +@@ -161,9 +165,28 @@ var islocaltests = []IsLocalTest{ + var winislocaltests = []IsLocalTest{ + {"NUL", false}, + {"nul", false}, + {"nul ", false}, -+ {"nul.", false}, + {"nul.", false}, +- {"nul.txt", false}, + {"a/nul:", false}, + {"a/nul : a", false}, + {"com0", true}, -+ {"com1", false}, + {"com1", false}, + {"com2", false}, + {"com3", false}, + {"com4", false}, @@ -428,38 +315,10 @@ index 9a57920dd7..b472a228a0 100644 + {"lpt1", false}, + {"LPT1", false}, + {"lpt³", false}, -+ {"./nul", false}, -+ {"a/nul.txt/b", false}, -+ {`\`, false}, -+ {`\a`, false}, -+ {`C:`, false}, -+ {`C:\a`, false}, -+ {`..\a`, false}, -+} -+ -+var plan9islocaltests = []IsLocalTest{ -+ {"#a", false}, -+} -+ -+func TestIsLocal(t *testing.T) { -+ tests := islocaltests -+ if runtime.GOOS == "windows" { -+ tests = append(tests, winislocaltests...) -+ } -+ if runtime.GOOS == "plan9" { -+ tests = append(tests, plan9islocaltests...) -+ } -+ for _, test := range tests { -+ if got := filepath.IsLocal(test.path); got != test.isLocal { -+ t.Errorf("IsLocal(%q) = %v, want %v", test.path, got, test.isLocal) -+ } -+ } -+} -+ - const sep = filepath.Separator - - var slashtests = []PathTest{ -@@ -299,8 +376,11 @@ var winjointests = []JoinTest{ + {"./nul", false}, + {"a/nul.txt/b", false}, + {`\`, false}, +@@ -353,8 +376,11 @@ var winjointests = []JoinTest{ {[]string{`\`, `a`, `b`}, `\a\b`}, {[]string{`\\`, `a`, `b`}, `\a\b`}, {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`}, @@ -473,7 +332,7 @@ index 9a57920dd7..b472a228a0 100644 } func TestJoin(t *testing.T) { -@@ -805,6 +885,8 @@ var winisabstests = []IsAbsTest{ +@@ -859,6 +885,8 @@ var winisabstests = []IsAbsTest{ {`\\host\share\`, true}, {`\\host\share\foo`, true}, {`//host/share/foo/bar`, true}, @@ -482,7 +341,7 @@ index 9a57920dd7..b472a228a0 100644 } func TestIsAbs(t *testing.T) { -@@ -1279,7 +1361,8 @@ type VolumeNameTest struct { +@@ -1333,7 +1361,8 @@ type VolumeNameTest struct { var volumenametests = []VolumeNameTest{ {`c:/foo/bar`, `c:`}, {`c:`, `c:`}, @@ -492,7 +351,7 @@ index 9a57920dd7..b472a228a0 100644 {``, ``}, {`\\\host`, ``}, {`\\\host\`, ``}, -@@ -1298,7 +1381,24 @@ var volumenametests = []VolumeNameTest{ +@@ -1352,7 +1381,24 @@ var volumenametests = []VolumeNameTest{ {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`}, {`//host/share//foo///bar////baz`, `//host/share`}, {`\\host\share\foo\..\bar`, `\\host\share`}, @@ -518,7 +377,7 @@ index 9a57920dd7..b472a228a0 100644 } func TestVolumeName(t *testing.T) { -@@ -1571,3 +1671,28 @@ func TestIssue51617(t *testing.T) { +@@ -1625,3 +1671,28 @@ func TestIssue51617(t *testing.T) { t.Errorf("got directories %v, want %v", saw, want) } } @@ -547,26 +406,11 @@ index 9a57920dd7..b472a228a0 100644 + } + } +} -diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go -index 93fdfdd8a0..ab1d08d356 100644 ---- a/src/path/filepath/path_unix.go -+++ b/src/path/filepath/path_unix.go -@@ -8,6 +8,10 @@ package filepath - - import "strings" - -+func isLocal(path string) bool { -+ return unixIsLocal(path) -+} -+ - // IsAbs reports whether the path is absolute. - func IsAbs(path string) bool { - return strings.HasPrefix(path, "/") diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go -index b4d8ac3301..8c5513737d 100644 +index 2865dd2659..d074a87a92 100644 --- a/src/path/filepath/path_windows.go +++ b/src/path/filepath/path_windows.go -@@ -5,8 +5,11 @@ +@@ -5,29 +5,22 @@ package filepath import ( @@ -578,53 +422,60 @@ index b4d8ac3301..8c5513737d 100644 ) func isSlash(c uint8) bool { -@@ -22,18 +25,37 @@ var reservedNames = []string{ - "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", + return c == '\\' || c == '/' } --// isReservedName returns true, if path is Windows reserved name. --// See reservedNames for the full list. --func isReservedName(path string) bool { -- if len(path) == 0 { -+func isLocal(path string) bool { -+ if path == "" { -+ return false -+ } -+ if isSlash(path[0]) { -+ // Path rooted in the current drive. -+ return false -+ } -+ if strings.IndexByte(path, ':') >= 0 { -+ // Colons are only valid when marking a drive letter ("C:foo"). -+ // Rejecting any path with a colon is conservative but safe. - return false +-// isReservedName reports if name is a Windows reserved device name. +-// It does not detect names with an extension, which are also reserved on some Windows versions. +-// +-// For details, search for PRN in +-// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. +-func isReservedName(name string) bool { +- if 3 <= len(name) && len(name) <= 4 { +- switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { +- case "CON", "PRN", "AUX", "NUL": +- return len(name) == 3 +- case "COM", "LPT": +- return len(name) == 4 && '1' <= name[3] && name[3] <= '9' +- } ++func toUpper(c byte) byte { ++ if 'a' <= c && c <= 'z' { ++ return c - ('a' - 'A') } -- for _, reserved := range reservedNames { -- if strings.EqualFold(path, reserved) { -- return true -+ hasDots := false // contains . or .. path elements -+ for p := path; p != ""; { -+ var part string -+ part, p, _ = cutPath(p) -+ if part == "." || part == ".." { -+ hasDots = true +- return false ++ return c + } + + func isLocal(path string) bool { +@@ -50,25 +43,8 @@ func isLocal(path string) bool { + if part == "." || part == ".." { + hasDots = true } +- // Trim the extension and look for a reserved name. +- base, _, hasExt := strings.Cut(part, ".") +- if isReservedName(base) { +- if !hasExt { +- return false +- } +- // The path element is a reserved name with an extension. Some Windows +- // versions consider this a reserved name, while others do not. Use +- // FullPath to see if the name is reserved. +- // +- // FullPath will convert references to reserved device names to their +- // canonical form: \\.\${DEVICE_NAME} +- // +- // FullPath does not perform this conversion for paths which contain +- // a reserved device name anywhere other than in the last element, +- // so check the part rather than the full path. +- if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` { +- return false +- } + if safefilepath.IsReservedName(part) { + return false -+ } -+ } -+ if hasDots { -+ path = Clean(path) -+ } -+ if path == ".." || strings.HasPrefix(path, `..\`) { -+ return false + } } -- return false -+ return true - } - - // IsAbs reports whether the path is absolute. -@@ -58,40 +80,110 @@ func IsAbs(path string) (b bool) { + if hasDots { +@@ -102,40 +78,110 @@ func IsAbs(path string) (b bool) { // volumeNameLen returns length of the leading volume name on Windows. // It returns 0 elsewhere. @@ -762,7 +613,7 @@ index b4d8ac3301..8c5513737d 100644 } // HasPrefix exists for historical compatibility and should not be used. -@@ -151,9 +243,44 @@ func abs(path string) (string, error) { +@@ -195,9 +241,44 @@ func abs(path string) (string, error) { } func join(elem []string) string { @@ -810,7 +661,7 @@ index b4d8ac3301..8c5513737d 100644 } } return "" -@@ -202,3 +329,29 @@ func isUNC(path string) bool { +@@ -246,3 +327,29 @@ func isUNC(path string) bool { func sameWord(a, b string) bool { return strings.EqualFold(a, b) } From 9ab8f477f26a84c98184e5e18adcceae0eb93cef Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Thu, 9 Nov 2023 15:39:15 -0800 Subject: [PATCH 10/12] regenerate patch again --- ...3-eks-path-filepath-fix-various-issu.patch | 313 +++++++++++++----- 1 file changed, 234 insertions(+), 79 deletions(-) diff --git a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch index c960da590..102728efa 100644 --- a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch +++ b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch @@ -1,13 +1,12 @@ -From 36ee9a5d9eeff5b6bcc395653bf2c20bcadaaa7f Mon Sep 17 00:00:00 2001 +From cfa56c91c12c547eba21b516180d02350181132c Mon Sep 17 00:00:00 2001 From: Damien Neil -Date: Fri, 1 Sep 2023 11:17:19 -0700 -Subject: [PATCH] [release-branch.go1.20] path/filepath: fix various issues in - parsing Windows paths +Date: Wed, 9 Nov 2022 17:49:44 -0800 +Subject: [PATCH] path/filepath: fix various issues in parsing Windows paths # AWS EKS Backported To: go-1.19.13-eks -Backported On: Tue, 07 Nov 2023 +Backported On: Thu, 00 Nov 2023 Backported By: rcrozean@amazon.com Backported From: release-branch.go1.20 Source Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae \ @@ -21,6 +20,8 @@ function calls exist as expected. # Original Information +Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae + 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 @@ -68,16 +69,54 @@ Reviewed-by: Cherry Mui Reviewed-on: https://go-review.googlesource.com/c/go/+/539276 Auto-Submit: Heschi Kreinick LUCI-TryBot-Result: Go LUCI + +----- + +Commit: https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 + +path/filepath: add IsLocal + +IsLocal reports whether a path lexically refers to a location +contained within the directory in which it is evaluated. +It identifies paths that are absolute, escape a directory +with ".." elements, and (on Windows) paths that reference +reserved device names. + +For #56219. + +Change-Id: I35edfa3ce77b40b8e66f1fc8e0ff73cfd06f2313 +Reviewed-on: https://go-review.googlesource.com/c/go/+/449239 +Run-TryBot: Damien Neil +Reviewed-by: Joseph Tsai +TryBot-Result: Gopher Robot +Reviewed-by: Ian Lance Taylor +Reviewed-by: Ian Lance Taylor +Reviewed-by: Joedian Reid --- + api/go1.19.txt | 1 + src/go/build/deps_test.go | 2 +- src/internal/safefilepath/path_windows.go | 98 ++++++--- - src/path/filepath/path.go | 1 + + src/path/filepath/path.go | 41 ++++ src/path/filepath/path_nonwindows.go | 9 + - src/path/filepath/path_test.go | 83 +++++++- - src/path/filepath/path_windows.go | 233 ++++++++++++++++------ - 6 files changed, 330 insertions(+), 96 deletions(-) + src/path/filepath/path_plan9.go | 4 + + src/path/filepath/path_test.go | 135 ++++++++++++- + src/path/filepath/path_unix.go | 4 + + src/path/filepath/path_windows.go | 229 ++++++++++++++++++---- + 9 files changed, 453 insertions(+), 70 deletions(-) create mode 100644 src/path/filepath/path_nonwindows.go +diff --git a/api/go1.19.txt b/api/go1.19.txt +index 523f752d70..fe9aee3050 100644 +--- a/api/go1.19.txt ++++ b/api/go1.19.txt +@@ -244,6 +244,7 @@ pkg net/url, type URL struct, OmitHost bool #46059 + pkg os/exec, method (*Cmd) Environ() []string #50599 + pkg os/exec, type Cmd struct, Err error #43724 + pkg os/exec, var ErrDot error #43724 ++pkg path/filepath, func IsLocal(string) bool #56219 + pkg regexp/syntax, const ErrNestingDepth = "expression nests too deeply" #51684 + pkg regexp/syntax, const ErrNestingDepth ErrorCode #51684 + pkg runtime/debug, func SetMemoryLimit(int64) int64 #48409 diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 69ba8b7f52..83da402bb4 100644 --- a/src/go/build/deps_test.go @@ -231,10 +270,10 @@ index 909c150edc..7cfd6ce2ea 100644 if 'a' <= c && c <= 'z' { return c - ('a' - 'A') diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go -index ffb7c7794a..1c0d18531e 100644 +index 9b1f5ed7c0..1c0d18531e 100644 --- a/src/path/filepath/path.go +++ b/src/path/filepath/path.go -@@ -170,6 +170,7 @@ func Clean(path string) string { +@@ -170,9 +170,50 @@ func Clean(path string) string { out.append('.') } @@ -242,6 +281,49 @@ index ffb7c7794a..1c0d18531e 100644 return FromSlash(out.string()) } ++// IsLocal reports whether path, using lexical analysis only, has all of these properties: ++// ++// - is within the subtree rooted at the directory in which path is evaluated ++// - is not an absolute path ++// - is not empty ++// - on Windows, is not a reserved name such as "NUL" ++// ++// If IsLocal(path) returns true, then ++// Join(base, path) will always produce a path contained within base and ++// Clean(path) will always produce an unrooted path with no ".." path elements. ++// ++// IsLocal is a purely lexical operation. ++// In particular, it does not account for the effect of any symbolic links ++// that may exist in the filesystem. ++func IsLocal(path string) bool { ++ return isLocal(path) ++} ++ ++func unixIsLocal(path string) bool { ++ if IsAbs(path) || path == "" { ++ return false ++ } ++ hasDots := false ++ for p := path; p != ""; { ++ var part string ++ part, p, _ = strings.Cut(p, "/") ++ if part == "." || part == ".." { ++ hasDots = true ++ break ++ } ++ } ++ if hasDots { ++ path = Clean(path) ++ } ++ if path == ".." || strings.HasPrefix(path, "../") { ++ return false ++ } ++ return true ++} ++ + // ToSlash returns the result of replacing each separator character + // in path with a slash ('/') character. Multiple separators are + // replaced by multiple slashes. diff --git a/src/path/filepath/path_nonwindows.go b/src/path/filepath/path_nonwindows.go new file mode 100644 index 0000000000..db69f0228b @@ -257,8 +339,23 @@ index 0000000000..db69f0228b +package filepath + +func postClean(out *lazybuf) {} +diff --git a/src/path/filepath/path_plan9.go b/src/path/filepath/path_plan9.go +index ec792fc831..453206aee3 100644 +--- a/src/path/filepath/path_plan9.go ++++ b/src/path/filepath/path_plan9.go +@@ -6,6 +6,10 @@ package filepath + + import "strings" + ++func isLocal(path string) bool { ++ return unixIsLocal(path) ++} ++ + // IsAbs reports whether the path is absolute. + func IsAbs(path string) bool { + return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go -index 8c19a6c641..b472a228a0 100644 +index 9a57920dd7..b472a228a0 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -7,7 +7,6 @@ package filepath_test @@ -288,17 +385,39 @@ index 8c19a6c641..b472a228a0 100644 } func TestClean(t *testing.T) { -@@ -161,9 +165,28 @@ var islocaltests = []IsLocalTest{ - var winislocaltests = []IsLocalTest{ - {"NUL", false}, - {"nul", false}, +@@ -138,6 +142,79 @@ func TestClean(t *testing.T) { + } + } + ++type IsLocalTest struct { ++ path string ++ isLocal bool ++} ++ ++var islocaltests = []IsLocalTest{ ++ {"", false}, ++ {".", true}, ++ {"..", false}, ++ {"../a", false}, ++ {"/", false}, ++ {"/a", false}, ++ {"/a/../..", false}, ++ {"a", true}, ++ {"a/../a", true}, ++ {"a/", true}, ++ {"a/.", true}, ++ {"a/./b/./c", true}, ++} ++ ++var winislocaltests = []IsLocalTest{ ++ {"NUL", false}, ++ {"nul", false}, + {"nul ", false}, - {"nul.", false}, -- {"nul.txt", false}, ++ {"nul.", false}, + {"a/nul:", false}, + {"a/nul : a", false}, + {"com0", true}, - {"com1", false}, ++ {"com1", false}, + {"com2", false}, + {"com3", false}, + {"com4", false}, @@ -315,10 +434,38 @@ index 8c19a6c641..b472a228a0 100644 + {"lpt1", false}, + {"LPT1", false}, + {"lpt³", false}, - {"./nul", false}, - {"a/nul.txt/b", false}, - {`\`, false}, -@@ -353,8 +376,11 @@ var winjointests = []JoinTest{ ++ {"./nul", false}, ++ {"a/nul.txt/b", false}, ++ {`\`, false}, ++ {`\a`, false}, ++ {`C:`, false}, ++ {`C:\a`, false}, ++ {`..\a`, false}, ++} ++ ++var plan9islocaltests = []IsLocalTest{ ++ {"#a", false}, ++} ++ ++func TestIsLocal(t *testing.T) { ++ tests := islocaltests ++ if runtime.GOOS == "windows" { ++ tests = append(tests, winislocaltests...) ++ } ++ if runtime.GOOS == "plan9" { ++ tests = append(tests, plan9islocaltests...) ++ } ++ for _, test := range tests { ++ if got := filepath.IsLocal(test.path); got != test.isLocal { ++ t.Errorf("IsLocal(%q) = %v, want %v", test.path, got, test.isLocal) ++ } ++ } ++} ++ + const sep = filepath.Separator + + var slashtests = []PathTest{ +@@ -299,8 +376,11 @@ var winjointests = []JoinTest{ {[]string{`\`, `a`, `b`}, `\a\b`}, {[]string{`\\`, `a`, `b`}, `\a\b`}, {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`}, @@ -332,7 +479,7 @@ index 8c19a6c641..b472a228a0 100644 } func TestJoin(t *testing.T) { -@@ -859,6 +885,8 @@ var winisabstests = []IsAbsTest{ +@@ -805,6 +885,8 @@ var winisabstests = []IsAbsTest{ {`\\host\share\`, true}, {`\\host\share\foo`, true}, {`//host/share/foo/bar`, true}, @@ -341,7 +488,7 @@ index 8c19a6c641..b472a228a0 100644 } func TestIsAbs(t *testing.T) { -@@ -1333,7 +1361,8 @@ type VolumeNameTest struct { +@@ -1279,7 +1361,8 @@ type VolumeNameTest struct { var volumenametests = []VolumeNameTest{ {`c:/foo/bar`, `c:`}, {`c:`, `c:`}, @@ -351,7 +498,7 @@ index 8c19a6c641..b472a228a0 100644 {``, ``}, {`\\\host`, ``}, {`\\\host\`, ``}, -@@ -1352,7 +1381,24 @@ var volumenametests = []VolumeNameTest{ +@@ -1298,7 +1381,24 @@ var volumenametests = []VolumeNameTest{ {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`}, {`//host/share//foo///bar////baz`, `//host/share`}, {`\\host\share\foo\..\bar`, `\\host\share`}, @@ -377,7 +524,7 @@ index 8c19a6c641..b472a228a0 100644 } func TestVolumeName(t *testing.T) { -@@ -1625,3 +1671,28 @@ func TestIssue51617(t *testing.T) { +@@ -1571,3 +1671,28 @@ func TestIssue51617(t *testing.T) { t.Errorf("got directories %v, want %v", saw, want) } } @@ -406,11 +553,26 @@ index 8c19a6c641..b472a228a0 100644 + } + } +} +diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go +index 93fdfdd8a0..ab1d08d356 100644 +--- a/src/path/filepath/path_unix.go ++++ b/src/path/filepath/path_unix.go +@@ -8,6 +8,10 @@ package filepath + + import "strings" + ++func isLocal(path string) bool { ++ return unixIsLocal(path) ++} ++ + // IsAbs reports whether the path is absolute. + func IsAbs(path string) bool { + return strings.HasPrefix(path, "/") diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go -index 2865dd2659..d074a87a92 100644 +index b4d8ac3301..8c5513737d 100644 --- a/src/path/filepath/path_windows.go +++ b/src/path/filepath/path_windows.go -@@ -5,29 +5,22 @@ +@@ -5,8 +5,11 @@ package filepath import ( @@ -422,60 +584,53 @@ index 2865dd2659..d074a87a92 100644 ) func isSlash(c uint8) bool { - return c == '\\' || c == '/' +@@ -22,18 +25,37 @@ var reservedNames = []string{ + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", } --// isReservedName reports if name is a Windows reserved device name. --// It does not detect names with an extension, which are also reserved on some Windows versions. --// --// For details, search for PRN in --// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. --func isReservedName(name string) bool { -- if 3 <= len(name) && len(name) <= 4 { -- switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { -- case "CON", "PRN", "AUX", "NUL": -- return len(name) == 3 -- case "COM", "LPT": -- return len(name) == 4 && '1' <= name[3] && name[3] <= '9' -- } -+func toUpper(c byte) byte { -+ if 'a' <= c && c <= 'z' { -+ return c - ('a' - 'A') +-// isReservedName returns true, if path is Windows reserved name. +-// See reservedNames for the full list. +-func isReservedName(path string) bool { +- if len(path) == 0 { ++func isLocal(path string) bool { ++ if path == "" { ++ return false ++ } ++ if isSlash(path[0]) { ++ // Path rooted in the current drive. ++ return false ++ } ++ if strings.IndexByte(path, ':') >= 0 { ++ // Colons are only valid when marking a drive letter ("C:foo"). ++ // Rejecting any path with a colon is conservative but safe. + return false } -- return false -+ return c - } - - func isLocal(path string) bool { -@@ -50,25 +43,8 @@ func isLocal(path string) bool { - if part == "." || part == ".." { - hasDots = true +- for _, reserved := range reservedNames { +- if strings.EqualFold(path, reserved) { +- return true ++ hasDots := false // contains . or .. path elements ++ for p := path; p != ""; { ++ var part string ++ part, p, _ = cutPath(p) ++ if part == "." || part == ".." { ++ hasDots = true } -- // Trim the extension and look for a reserved name. -- base, _, hasExt := strings.Cut(part, ".") -- if isReservedName(base) { -- if !hasExt { -- return false -- } -- // The path element is a reserved name with an extension. Some Windows -- // versions consider this a reserved name, while others do not. Use -- // FullPath to see if the name is reserved. -- // -- // FullPath will convert references to reserved device names to their -- // canonical form: \\.\${DEVICE_NAME} -- // -- // FullPath does not perform this conversion for paths which contain -- // a reserved device name anywhere other than in the last element, -- // so check the part rather than the full path. -- if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` { -- return false -- } + if safefilepath.IsReservedName(part) { + return false - } ++ } ++ } ++ if hasDots { ++ path = Clean(path) ++ } ++ if path == ".." || strings.HasPrefix(path, `..\`) { ++ return false } - if hasDots { -@@ -102,40 +78,110 @@ func IsAbs(path string) (b bool) { +- return false ++ return true + } + + // IsAbs reports whether the path is absolute. +@@ -58,40 +80,110 @@ func IsAbs(path string) (b bool) { // volumeNameLen returns length of the leading volume name on Windows. // It returns 0 elsewhere. @@ -613,7 +768,7 @@ index 2865dd2659..d074a87a92 100644 } // HasPrefix exists for historical compatibility and should not be used. -@@ -195,9 +241,44 @@ func abs(path string) (string, error) { +@@ -151,9 +243,44 @@ func abs(path string) (string, error) { } func join(elem []string) string { @@ -661,7 +816,7 @@ index 2865dd2659..d074a87a92 100644 } } return "" -@@ -246,3 +327,29 @@ func isUNC(path string) bool { +@@ -202,3 +329,29 @@ func isUNC(path string) bool { func sameWord(a, b string) bool { return strings.EqualFold(a, b) } @@ -692,5 +847,5 @@ index 2865dd2659..d074a87a92 100644 + } +} -- -2.42.0 +2.42.1 From 32a1a706fdbd72d8a462654533c28b8da8544fc6 Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Thu, 9 Nov 2023 16:44:40 -0800 Subject: [PATCH 11/12] just keep trying --- ...3-eks-path-filepath-fix-various-issu.patch | 118 +++++++++++++++--- 1 file changed, 101 insertions(+), 17 deletions(-) diff --git a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch index 102728efa..b71d8315b 100644 --- a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch +++ b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch @@ -1,4 +1,4 @@ -From cfa56c91c12c547eba21b516180d02350181132c Mon Sep 17 00:00:00 2001 +From c253019adf35b956a3a8975aec95f7c53987bd33 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 9 Nov 2022 17:49:44 -0800 Subject: [PATCH] path/filepath: fix various issues in parsing Windows paths @@ -6,10 +6,11 @@ Subject: [PATCH] path/filepath: fix various issues in parsing Windows paths # AWS EKS Backported To: go-1.19.13-eks -Backported On: Thu, 00 Nov 2023 +Backported On: Tue, 07 Nov 2023 Backported By: rcrozean@amazon.com Backported From: release-branch.go1.20 Source Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae \ + https://github.com/golang/go/commit/45b98bfb793923c539f9a959c3047d2e5fe2ebf0 \ https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 In addition to the CVE fix https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae, @@ -20,8 +21,6 @@ function calls exist as expected. # Original Information -Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae - 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 @@ -72,8 +71,37 @@ LUCI-TryBot-Result: Go LUCI +Reviewed-by: Bryan Mills +TryBot-Result: Gopher Robot +Reviewed-by: Quim Muntal +(cherry picked from commit 6e43407931ee4acc204620a9fae59c7903164901) +Reviewed-on: https://go-review.googlesource.com/c/go/+/519655 +Reviewed-by: Damien Neil +Reviewed-by: Dmitri Shuralyov +LUCI-TryBot-Result: Go LUCI +Run-TryBot: Dmitri Shuralyov + +----- + Commit: https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 + path/filepath: add IsLocal IsLocal reports whether a path lexically refers to a location @@ -96,13 +124,13 @@ Reviewed-by: Joedian Reid api/go1.19.txt | 1 + src/go/build/deps_test.go | 2 +- src/internal/safefilepath/path_windows.go | 98 ++++++--- - src/path/filepath/path.go | 41 ++++ + src/path/filepath/path.go | 59 ++++-- src/path/filepath/path_nonwindows.go | 9 + src/path/filepath/path_plan9.go | 4 + - src/path/filepath/path_test.go | 135 ++++++++++++- + src/path/filepath/path_test.go | 138 ++++++++++++- src/path/filepath/path_unix.go | 4 + src/path/filepath/path_windows.go | 229 ++++++++++++++++++---- - 9 files changed, 453 insertions(+), 70 deletions(-) + 9 files changed, 461 insertions(+), 83 deletions(-) create mode 100644 src/path/filepath/path_nonwindows.go diff --git a/api/go1.19.txt b/api/go1.19.txt @@ -270,10 +298,49 @@ index 909c150edc..7cfd6ce2ea 100644 if 'a' <= c && c <= 'z' { return c - ('a' - 'A') diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go -index 9b1f5ed7c0..1c0d18531e 100644 +index 9b1f5ed7c0..eb1628b9a0 100644 --- a/src/path/filepath/path.go +++ b/src/path/filepath/path.go -@@ -170,9 +170,50 @@ func Clean(path string) string { +@@ -15,7 +15,6 @@ import ( + "errors" + "io/fs" + "os" +- "runtime" + "sort" + "strings" + ) +@@ -52,6 +51,11 @@ func (b *lazybuf) append(c byte) { + b.w++ + } + ++func (b *lazybuf) prepend(prefix ...byte) { ++ b.buf = append(prefix, b.buf...) ++ b.w += len(prefix) ++} ++ + func (b *lazybuf) string() string { + if b.buf == nil { + return b.volAndPath[:b.volLen+b.w] +@@ -146,18 +150,6 @@ func Clean(path string) string { + if rooted && out.w != 1 || !rooted && out.w != 0 { + out.append(Separator) + } +- // If a ':' appears in the path element at the start of a Windows path, +- // insert a .\ at the beginning to avoid converting relative paths +- // like a/../c: into c:. +- if runtime.GOOS == "windows" && out.w == 0 && out.volLen == 0 && r != 0 { +- for i := r; i < n && !os.IsPathSeparator(path[i]); i++ { +- if path[i] == ':' { +- out.append('.') +- out.append(Separator) +- break +- } +- } +- } + // copy element + for ; r < n && !os.IsPathSeparator(path[r]); r++ { + out.append(path[r]) +@@ -170,9 +162,50 @@ func Clean(path string) string { out.append('.') } @@ -355,7 +422,7 @@ index ec792fc831..453206aee3 100644 func IsAbs(path string) bool { return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go -index 9a57920dd7..b472a228a0 100644 +index 9a57920dd7..204b3bb5c8 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -7,7 +7,6 @@ package filepath_test @@ -375,7 +442,23 @@ index 9a57920dd7..b472a228a0 100644 ) type PathTest struct { -@@ -103,6 +104,9 @@ var wincleantests = []PathTest{ +@@ -69,6 +70,7 @@ var cleantests = []PathTest{ + {"/abc/def/../../..", "/"}, + {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"}, + {"/../abc", "/abc"}, ++ {"a/../b:/../../c", `../c`}, + + // Combinations + {"abc/./../def", "def"}, +@@ -84,6 +86,7 @@ var wincleantests = []PathTest{ + {`c:\abc\def\..\..`, `c:\`}, + {`c:\..\abc`, `c:\abc`}, + {`c:..\abc`, `c:..\abc`}, ++ {`c:\b:\..\..\..\d`, `c:\d`}, + {`\`, `\`}, + {`/`, `\`}, + {`\\i\..\c$`, `\c$`}, +@@ -103,6 +106,9 @@ var wincleantests = []PathTest{ {`a/../c:/a`, `.\c:\a`}, {`a/../../c:`, `..\c:`}, {`foo:bar`, `foo:bar`}, @@ -385,7 +468,7 @@ index 9a57920dd7..b472a228a0 100644 } func TestClean(t *testing.T) { -@@ -138,6 +142,79 @@ func TestClean(t *testing.T) { +@@ -138,6 +144,80 @@ func TestClean(t *testing.T) { } } @@ -407,6 +490,7 @@ index 9a57920dd7..b472a228a0 100644 + {"a/", true}, + {"a/.", true}, + {"a/./b/./c", true}, ++ {`a/../b:/../../c`, false}, +} + +var winislocaltests = []IsLocalTest{ @@ -465,7 +549,7 @@ index 9a57920dd7..b472a228a0 100644 const sep = filepath.Separator var slashtests = []PathTest{ -@@ -299,8 +376,11 @@ var winjointests = []JoinTest{ +@@ -299,8 +379,11 @@ var winjointests = []JoinTest{ {[]string{`\`, `a`, `b`}, `\a\b`}, {[]string{`\\`, `a`, `b`}, `\a\b`}, {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`}, @@ -479,7 +563,7 @@ index 9a57920dd7..b472a228a0 100644 } func TestJoin(t *testing.T) { -@@ -805,6 +885,8 @@ var winisabstests = []IsAbsTest{ +@@ -805,6 +888,8 @@ var winisabstests = []IsAbsTest{ {`\\host\share\`, true}, {`\\host\share\foo`, true}, {`//host/share/foo/bar`, true}, @@ -488,7 +572,7 @@ index 9a57920dd7..b472a228a0 100644 } func TestIsAbs(t *testing.T) { -@@ -1279,7 +1361,8 @@ type VolumeNameTest struct { +@@ -1279,7 +1364,8 @@ type VolumeNameTest struct { var volumenametests = []VolumeNameTest{ {`c:/foo/bar`, `c:`}, {`c:`, `c:`}, @@ -498,7 +582,7 @@ index 9a57920dd7..b472a228a0 100644 {``, ``}, {`\\\host`, ``}, {`\\\host\`, ``}, -@@ -1298,7 +1381,24 @@ var volumenametests = []VolumeNameTest{ +@@ -1298,7 +1384,24 @@ var volumenametests = []VolumeNameTest{ {`\\host\share\\foo\\\bar\\\\baz`, `\\host\share`}, {`//host/share//foo///bar////baz`, `//host/share`}, {`\\host\share\foo\..\bar`, `\\host\share`}, @@ -524,7 +608,7 @@ index 9a57920dd7..b472a228a0 100644 } func TestVolumeName(t *testing.T) { -@@ -1571,3 +1671,28 @@ func TestIssue51617(t *testing.T) { +@@ -1571,3 +1674,28 @@ func TestIssue51617(t *testing.T) { t.Errorf("got directories %v, want %v", saw, want) } } From d948b1fe4f9e24b8a7956758c76e0449808f4983 Mon Sep 17 00:00:00 2001 From: Cameron Rozean Date: Thu, 9 Nov 2023 17:31:32 -0800 Subject: [PATCH 12/12] fix fix fix --- ...3-eks-path-filepath-fix-various-issu.patch | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch index b71d8315b..c90f8b348 100644 --- a/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch +++ b/projects/golang/go/1.19/patches/0005-go-1.19.13-eks-path-filepath-fix-various-issu.patch @@ -1,7 +1,8 @@ -From c253019adf35b956a3a8975aec95f7c53987bd33 Mon Sep 17 00:00:00 2001 +From f268c1ac845737c230189e44663213ffc8af0fef Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 9 Nov 2022 17:49:44 -0800 -Subject: [PATCH] path/filepath: fix various issues in parsing Windows paths +Subject: [PATCH] path/filepath: fix various issues in + parsing Windows paths # AWS EKS @@ -14,9 +15,11 @@ Source Commit: https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 In addition to the CVE fix https://github.com/golang/go/commit/46fb78168596f7ce8834f528bb0eb9555c08bcae, -https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 was cherry-picked to include expected functions and -tests expected in the CVE fix commit. Additionally, for the purpose of -tests I added the line to api/go1.19.txt which is used for checking the + +https://github.com/golang/go/commit/45b98bfb793923c539f9a959c3047d2e5fe2ebf0 & +https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 were +cherry-picked to include expected functions and tests expected in the CVE fix commit. +Additionally, for the purpose of tests I added the line to api/go1.19.txt which is used for checking the function calls exist as expected. # Original Information @@ -69,9 +72,7 @@ Reviewed-on: https://go-review.googlesource.com/c/go/+/539276 Auto-Submit: Heschi Kreinick LUCI-TryBot-Result: Go LUCI ------ - -Commit: https://github.com/golang/go/commit/45b98bfb793923c539f9a959c3047d2e5fe2ebf0 +commit: https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 [release-branch.go1.21] path/filepath: don't drop .. elements when cleaning invalid Windows paths @@ -97,10 +98,7 @@ Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Run-TryBot: Dmitri Shuralyov ------ - -Commit: https://github.com/golang/go/commit/6d0bf438e302afcb0db5422ea2da59d1995e08c1 - +commit: https://github.com/golang/go/commit/45b98bfb793923c539f9a959c3047d2e5fe2ebf0 path/filepath: add IsLocal @@ -129,8 +127,8 @@ Reviewed-by: Joedian Reid src/path/filepath/path_plan9.go | 4 + src/path/filepath/path_test.go | 138 ++++++++++++- src/path/filepath/path_unix.go | 4 + - src/path/filepath/path_windows.go | 229 ++++++++++++++++++---- - 9 files changed, 461 insertions(+), 83 deletions(-) + src/path/filepath/path_windows.go | 239 ++++++++++++++++++---- + 9 files changed, 468 insertions(+), 86 deletions(-) create mode 100644 src/path/filepath/path_nonwindows.go diff --git a/api/go1.19.txt b/api/go1.19.txt @@ -653,10 +651,10 @@ index 93fdfdd8a0..ab1d08d356 100644 func IsAbs(path string) bool { return strings.HasPrefix(path, "/") diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go -index b4d8ac3301..8c5513737d 100644 +index b4d8ac3301..134114a39d 100644 --- a/src/path/filepath/path_windows.go +++ b/src/path/filepath/path_windows.go -@@ -5,8 +5,11 @@ +@@ -5,14 +5,24 @@ package filepath import ( @@ -668,7 +666,20 @@ index b4d8ac3301..8c5513737d 100644 ) func isSlash(c uint8) bool { -@@ -22,18 +25,37 @@ var reservedNames = []string{ + return c == '\\' || c == '/' + } + ++func toUpper(c byte) byte { ++ if 'a' <= c && c <= 'z' { ++ return c - ('a' - 'A') ++ } ++ return c ++} ++ + // reservedNames lists reserved Windows names. Search for PRN in + // https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file + // for details. +@@ -22,25 +32,41 @@ var reservedNames = []string{ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", } @@ -682,39 +693,46 @@ index b4d8ac3301..8c5513737d 100644 + } + if isSlash(path[0]) { + // Path rooted in the current drive. -+ return false -+ } -+ if strings.IndexByte(path, ':') >= 0 { -+ // Colons are only valid when marking a drive letter ("C:foo"). -+ // Rejecting any path with a colon is conservative but safe. return false } - for _, reserved := range reservedNames { - if strings.EqualFold(path, reserved) { - return true ++ if strings.IndexByte(path, ':') >= 0 { ++ // Colons are only valid when marking a drive letter ("C:foo"). ++ // Rejecting any path with a colon is conservative but safe. ++ return false ++ } + hasDots := false // contains . or .. path elements + for p := path; p != ""; { + var part string + part, p, _ = cutPath(p) + if part == "." || part == ".." { + hasDots = true - } ++ } + if safefilepath.IsReservedName(part) { + return false -+ } -+ } + } + } +- return false + if hasDots { + path = Clean(path) + } + if path == ".." || strings.HasPrefix(path, `..\`) { + return false - } -- return false ++ } + return true } // IsAbs reports whether the path is absolute. -@@ -58,40 +80,110 @@ func IsAbs(path string) (b bool) { + func IsAbs(path string) (b bool) { +- if isReservedName(path) { +- return true +- } + l := volumeNameLen(path) + if l == 0 { + return false +@@ -58,40 +84,110 @@ func IsAbs(path string) (b bool) { // volumeNameLen returns length of the leading volume name on Windows. // It returns 0 elsewhere. @@ -852,7 +870,7 @@ index b4d8ac3301..8c5513737d 100644 } // HasPrefix exists for historical compatibility and should not be used. -@@ -151,9 +243,44 @@ func abs(path string) (string, error) { +@@ -151,9 +247,44 @@ func abs(path string) (string, error) { } func join(elem []string) string { @@ -900,7 +918,7 @@ index b4d8ac3301..8c5513737d 100644 } } return "" -@@ -202,3 +329,29 @@ func isUNC(path string) bool { +@@ -202,3 +333,29 @@ func isUNC(path string) bool { func sameWord(a, b string) bool { return strings.EqualFold(a, b) }