Message ID | 20230320200908.1233173-1-sakib.sajal@windriver.com |
---|---|
State | New, archived |
Headers | show |
Series | [kirkstone] go: fix CVE-2022-2879 and CVE-2022-41720 | expand |
On 2023-03-20 16:09, Sakib Sajal via lists.openembedded.org wrote: > Backport appropriate patches to fix CVE-2022-2879 and CVE-2022-41720. > > Modified the original fix for CVE-2022-2879 to remove a testdata tarball > and any references to it since git binary diffs are not supported in quilt. > > Signed-off-by: Sakib Sajal<sakib.sajal@windriver.com> > --- > meta/recipes-devtools/go/go-1.17.13.inc | 36 +- > ...01-archive-tar-limit-size-of-headers.patch | 177 ++++++ > ...d-escapes-from-os.DirFS-and-http.Dir.patch | 514 ++++++++++++++++++ > 3 files changed, 710 insertions(+), 17 deletions(-) > create mode 100644 meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch > create mode 100644 meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch > > diff --git a/meta/recipes-devtools/go/go-1.17.13.inc b/meta/recipes-devtools/go/go-1.17.13.inc > index 99662bd298..f5cf192361 100644 > --- a/meta/recipes-devtools/go/go-1.17.13.inc > +++ b/meta/recipes-devtools/go/go-1.17.13.inc > @@ -4,23 +4,25 @@ FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/go-1.18:" > > LIC_FILES_CHKSUM ="file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" > > -SRC_URI += "\ > -file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ > -file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ > -file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ > -file://0004-ld-add-soname-to-shareable-objects.patch \ > -file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ > -file://0006-cmd-dist-separate-host-and-target-builds.patch \ > -file://0007-cmd-go-make-GOROOT-precious-by-default.patch \ > -file://0008-use-GOBUILDMODE-to-set-buildmode.patch \ > -file://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ > -file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ > -file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ > -file://CVE-2022-27664.patch \ > -file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ > -file://CVE-2022-41715.patch \ > -file://CVE-2022-41717.patch \ > -" > +SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \ Nack. Sakib, You said this works for you but if you look at: ❯ cat meta/recipes-devtools/go/go-1.17.13.inc require go-common.inc FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/go-1.18:" LIC_FILES_CHKSUM = "file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" SRC_URI += "\ ... and then ❯ grep SRC_URI meta/recipes-devtools/go/go-common.inc SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main" You see that you should stick with the += operator. I think you said that devtool changed that , right? If so, and if we can learn why this change even built for you, then consider opening a bug against devtool. ../Randy > +file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ > +file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ > +file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ > +file://0004-ld-add-soname-to-shareable-objects.patch \ > +file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ > +file://0006-cmd-dist-separate-host-and-target-builds.patch \ > +file://0007-cmd-go-make-GOROOT-precious-by-default.patch \ > +file://0008-use-GOBUILDMODE-to-set-buildmode.patch \ > +file://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ > +file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ > +file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ > +file://CVE-2022-27664.patch \ > +file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ > +file://CVE-2022-41715.patch \ > +file://CVE-2022-41717.patch \ > +file://0001-archive-tar-limit-size-of-headers.patch \ > +file://0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch \ > + " > SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" > > # Upstream don't believe it is a signifiant real world issue and will only > diff --git a/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch b/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch > new file mode 100644 > index 0000000000..0315e1a3ee > --- /dev/null > +++ b/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch > @@ -0,0 +1,177 @@ > +From d064ed520a7cc6b480f9565e30751e695d394f4e Mon Sep 17 00:00:00 2001 > +From: Damien Neil<dneil@google.com> > +Date: Fri, 2 Sep 2022 20:45:18 -0700 > +Subject: [PATCH] archive/tar: limit size of headers > + > +Set a 1MiB limit on special file blocks (PAX headers, GNU long names, > +GNU link names), to avoid reading arbitrarily large amounts of data > +into memory. > + > +Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting > +this issue. > + > +Fixes CVE-2022-2879 > +Updates #54853 > +Fixes #55925 > + > +Change-Id: I85136d6ff1e0af101a112190e027987ab4335680 > +Reviewed-on:https://team-review.git.corp.google.com/c/golang/go-private/+/1565555 > +Reviewed-by: Tatiana Bradley<tatianabradley@google.com> > +Run-TryBot: Roland Shoemaker<bracewell@google.com> > +Reviewed-by: Roland Shoemaker<bracewell@google.com> > +(cherry picked from commit 6ee768cef6b82adf7a90dcf367a1699ef694f3b2) > +Reviewed-on:https://team-review.git.corp.google.com/c/golang/go-private/+/1590622 > +Reviewed-by: Damien Neil<dneil@google.com> > +Reviewed-by: Julie Qiu<julieqiu@google.com> > +Reviewed-on:https://go-review.googlesource.com/c/go/+/438500 > +Reviewed-by: Dmitri Shuralyov<dmitshur@golang.org> > +Reviewed-by: Carlos Amedee<carlos@golang.org> > +Reviewed-by: Dmitri Shuralyov<dmitshur@google.com> > +Run-TryBot: Carlos Amedee<carlos@golang.org> > +TryBot-Result: Gopher Robot<gobot@golang.org> > + > +CVE: CVE-2022-2879 > +Upstream-Status: Backport [0a723816cd205576945fa57fbdde7e6532d59d08] > +Signed-off-by: Sakib Sajal<sakib.sajal@windriver.com> > +--- > + src/archive/tar/format.go | 4 ++++ > + src/archive/tar/reader.go | 14 ++++++++++++-- > + src/archive/tar/reader_test.go | 8 +++++++- > + src/archive/tar/writer.go | 3 +++ > + src/archive/tar/writer_test.go | 27 +++++++++++++++++++++++++++ > + 5 files changed, 53 insertions(+), 3 deletions(-) > + > +diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go > +index cfe24a5..6642364 100644 > +--- a/src/archive/tar/format.go > ++++ b/src/archive/tar/format.go > +@@ -143,6 +143,10 @@ const ( > + blockSize = 512 // Size of each block in a tar stream > + nameSize = 100 // Max length of the name field in USTAR format > + prefixSize = 155 // Max length of the prefix field in USTAR format > ++ > ++ // Max length of a special file (PAX header, GNU long name or link). > ++ // This matches the limit used by libarchive. > ++ maxSpecialFileSize = 1 << 20 > + ) > + > + // blockPadding computes the number of bytes needed to pad offset up to the > +diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go > +index 1b1d5b4..f645af8 100644 > +--- a/src/archive/tar/reader.go > ++++ b/src/archive/tar/reader.go > +@@ -103,7 +103,7 @@ func (tr *Reader) next() (*Header, error) { > + continue // This is a meta header affecting the next header > + case TypeGNULongName, TypeGNULongLink: > + format.mayOnlyBe(FormatGNU) > +- realname, err := io.ReadAll(tr) > ++ realname, err := readSpecialFile(tr) > + if err != nil { > + return nil, err > + } > +@@ -293,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { > + // parsePAX parses PAX headers. > + // If an extended header (type 'x') is invalid, ErrHeader is returned > + func parsePAX(r io.Reader) (map[string]string, error) { > +- buf, err := io.ReadAll(r) > ++ buf, err := readSpecialFile(r) > + if err != nil { > + return nil, err > + } > +@@ -826,6 +826,16 @@ func tryReadFull(r io.Reader, b []byte) (n int, err error) { > + return n, err > + } > + > ++// readSpecialFile is like io.ReadAll except it returns > ++// ErrFieldTooLong if more than maxSpecialFileSize is read. > ++func readSpecialFile(r io.Reader) ([]byte, error) { > ++ buf, err := io.ReadAll(io.LimitReader(r, maxSpecialFileSize+1)) > ++ if len(buf) > maxSpecialFileSize { > ++ return nil, ErrFieldTooLong > ++ } > ++ return buf, err > ++} > ++ > + // discard skips n bytes in r, reporting an error if unable to do so. > + func discard(r io.Reader, n int64) error { > + // If possible, Seek to the last byte before the end of the data section. > +diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go > +index 789ddc1..926dc3d 100644 > +--- a/src/archive/tar/reader_test.go > ++++ b/src/archive/tar/reader_test.go > +@@ -6,6 +6,7 @@ package tar > + > + import ( > + "bytes" > ++ "compress/bzip2" > + "crypto/md5" > + "errors" > + "fmt" +@@ -625,9 +626,14 @@ func TestReader(t *testing.T) { + } + defer > f.Close() + ++ var fr io.Reader = f ++ if strings.HasSuffix(v.file, ".bz2") { > ++ fr = bzip2.NewReader(fr) > ++ } > ++ > + // Capture all headers and checksums. > + var ( > +- tr = NewReader(f) > ++ tr = NewReader(fr) > + hdrs []*Header > + chksums []string > + rdbuf = make([]byte, 8) > +diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go > +index e80498d..893eac0 100644 > +--- a/src/archive/tar/writer.go > ++++ b/src/archive/tar/writer.go > +@@ -199,6 +199,9 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error { > + flag = TypeXHeader > + } > + data := buf.String() > ++ if len(data) > maxSpecialFileSize { > ++ return ErrFieldTooLong > ++ } > + if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal { > + return err // Global headers return here > + } > +diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go > +index a00f02d..4e709e5 100644 > +--- a/src/archive/tar/writer_test.go > ++++ b/src/archive/tar/writer_test.go > +@@ -1006,6 +1006,33 @@ func TestIssue12594(t *testing.T) { > + } > + } > + > ++func TestWriteLongHeader(t *testing.T) { > ++ for _, test := range []struct { > ++ name string > ++ h *Header > ++ }{{ > ++ name: "name too long", > ++ h: &Header{Name: strings.Repeat("a", maxSpecialFileSize)}, > ++ }, { > ++ name: "linkname too long", > ++ h: &Header{Linkname: strings.Repeat("a", maxSpecialFileSize)}, > ++ }, { > ++ name: "uname too long", > ++ h: &Header{Uname: strings.Repeat("a", maxSpecialFileSize)}, > ++ }, { > ++ name: "gname too long", > ++ h: &Header{Gname: strings.Repeat("a", maxSpecialFileSize)}, > ++ }, { > ++ name: "PAX header too long", > ++ h: &Header{PAXRecords: map[string]string{"GOLANG.x": strings.Repeat("a", maxSpecialFileSize)}}, > ++ }} { > ++ w := NewWriter(io.Discard) > ++ if err := w.WriteHeader(test.h); err != ErrFieldTooLong { > ++ t.Errorf("%v: w.WriteHeader() = %v, want ErrFieldTooLong", test.name, err) > ++ } > ++ } > ++} > ++ > + // testNonEmptyWriter wraps an io.Writer and ensures that > + // Write is never called with an empty buffer. > + type testNonEmptyWriter struct{ io.Writer } > diff --git a/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch b/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch > new file mode 100644 > index 0000000000..6c2e8804b3 > --- /dev/null > +++ b/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch > @@ -0,0 +1,514 @@ > +From f8896a97a0630b0f2f8c488310147f7f20b3ec7d Mon Sep 17 00:00:00 2001 > +From: Damien Neil<dneil@google.com> > +Date: Thu, 10 Nov 2022 12:16:27 -0800 > +Subject: [PATCH] os, net/http: avoid escapes from os.DirFS and http.Dir on > + Windows > + > +Do not permit access to Windows reserved device names (NUL, COM1, etc.) > +via os.DirFS and http.Dir filesystems. > + > +Avoid escapes from os.DirFS(`\`) on Windows. DirFS would join the > +the root to the relative path with a path separator, making > +os.DirFS(`\`).Open(`/foo/bar`) open the path `\\foo\bar`, which is > +a UNC name. Not only does this not open the intended file, but permits > +reference to any file on the system rather than only files on the > +current drive. > + > +Make os.DirFS("") invalid, with all file access failing. Previously, > +a root of "" was interpreted as "/", which is surprising and probably > +unintentional. > + > +Fixes CVE-2022-41720. > +Fixes #56694. > + > +Change-Id: I275b5fa391e6ad7404309ea98ccc97405942e0f0 > +Reviewed-on:https://team-review.git.corp.google.com/c/golang/go-private/+/1663832 > +Reviewed-by: Julie Qiu<julieqiu@google.com> > +Reviewed-by: Tatiana Bradley<tatianabradley@google.com> > +Reviewed-on:https://go-review.googlesource.com/c/go/+/455360 > +Reviewed-by: Michael Pratt<mpratt@google.com> > +TryBot-Result: Gopher Robot<gobot@golang.org> > +Run-TryBot: Jenny Rakoczy<jenny@golang.org> > + > +CVE: CVE-2022-41720 > +Upstream-Status: Backport [7013a4f5f816af62033ad63dd06b77c30d7a62a7] > +Signed-off-by: Sakib Sajal<sakib.sajal@windriver.com> > +--- > + src/go/build/deps_test.go | 1 + > + src/internal/safefilepath/path.go | 21 +++++ > + src/internal/safefilepath/path_other.go | 23 ++++++ > + src/internal/safefilepath/path_test.go | 88 +++++++++++++++++++++ > + src/internal/safefilepath/path_windows.go | 95 +++++++++++++++++++++++ > + src/net/http/fs.go | 8 +- > + src/net/http/fs_test.go | 28 +++++++ > + src/os/file.go | 36 +++++++-- > + src/os/os_test.go | 38 +++++++++ > + 9 files changed, 328 insertions(+), 10 deletions(-) > + create mode 100644 src/internal/safefilepath/path.go > + create mode 100644 src/internal/safefilepath/path_other.go > + create mode 100644 src/internal/safefilepath/path_test.go > + create mode 100644 src/internal/safefilepath/path_windows.go > + > +diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go > +index 45e2f25..dc3bb8c 100644 > +--- a/src/go/build/deps_test.go > ++++ b/src/go/build/deps_test.go > +@@ -165,6 +165,7 @@ var depsRules = ` > + io/fs > + < internal/testlog > + < internal/poll > ++ < internal/safefilepath > + < os > + < os/signal; > + > +diff --git a/src/internal/safefilepath/path.go b/src/internal/safefilepath/path.go > +new file mode 100644 > +index 0000000..0f0a270 > +--- /dev/null > ++++ b/src/internal/safefilepath/path.go > +@@ -0,0 +1,21 @@ > ++// Copyright 2022 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. > ++ > ++// Package safefilepath manipulates operating-system file paths. > ++package safefilepath > ++ > ++import ( > ++ "errors" > ++) > ++ > ++var errInvalidPath = errors.New("invalid path") > ++ > ++// FromFS converts a slash-separated path into an operating-system path. > ++// > ++// FromFS returns an error if the path cannot be represented by the operating > ++// system. For example, paths containing '\' and ':' characters are rejected > ++// on Windows. > ++func FromFS(path string) (string, error) { > ++ return fromFS(path) > ++} > +diff --git a/src/internal/safefilepath/path_other.go b/src/internal/safefilepath/path_other.go > +new file mode 100644 > +index 0000000..f93da18 > +--- /dev/null > ++++ b/src/internal/safefilepath/path_other.go > +@@ -0,0 +1,23 @@ > ++// Copyright 2022 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 safefilepath > ++ > ++import "runtime" > ++ > ++func fromFS(path string) (string, error) { > ++ if runtime.GOOS == "plan9" { > ++ if len(path) > 0 && path[0] == '#' { > ++ return path, errInvalidPath > ++ } > ++ } > ++ for i := range path { > ++ if path[i] == 0 { > ++ return "", errInvalidPath > ++ } > ++ } > ++ return path, nil > ++} > +diff --git a/src/internal/safefilepath/path_test.go b/src/internal/safefilepath/path_test.go > +new file mode 100644 > +index 0000000..dc662c1 > +--- /dev/null > ++++ b/src/internal/safefilepath/path_test.go > +@@ -0,0 +1,88 @@ > ++// Copyright 2022 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. > ++ > ++package safefilepath_test > ++ > ++import ( > ++ "internal/safefilepath" > ++ "os" > ++ "path/filepath" > ++ "runtime" > ++ "testing" > ++) > ++ > ++type PathTest struct { > ++ path, result string > ++} > ++ > ++const invalid = "" > ++ > ++var fspathtests = []PathTest{ > ++ {".", "."}, > ++ {"/a/b/c", "/a/b/c"}, > ++ {"a\x00b", invalid}, > ++} > ++ > ++var winreservedpathtests = []PathTest{ > ++ {`a\b`, `a\b`}, > ++ {`a:b`, `a:b`}, > ++ {`a/b:c`, `a/b:c`}, > ++ {`NUL`, `NUL`}, > ++ {`./com1`, `./com1`}, > ++ {`a/nul/b`, `a/nul/b`}, > ++} > ++ > ++// Whether a reserved name with an extension is reserved or not varies by > ++// Windows version. > ++var winreservedextpathtests = []PathTest{ > ++ {"nul.txt", "nul.txt"}, > ++ {"a/nul.txt/b", "a/nul.txt/b"}, > ++} > ++ > ++var plan9reservedpathtests = []PathTest{ > ++ {`#c`, `#c`}, > ++} > ++ > ++func TestFromFS(t *testing.T) { > ++ switch runtime.GOOS { > ++ case "windows": > ++ if canWriteFile(t, "NUL") { > ++ t.Errorf("can unexpectedly write a file named NUL on Windows") > ++ } > ++ if canWriteFile(t, "nul.txt") { > ++ fspathtests = append(fspathtests, winreservedextpathtests...) > ++ } else { > ++ winreservedpathtests = append(winreservedpathtests, winreservedextpathtests...) > ++ } > ++ for i := range winreservedpathtests { > ++ winreservedpathtests[i].result = invalid > ++ } > ++ for i := range fspathtests { > ++ fspathtests[i].result = filepath.FromSlash(fspathtests[i].result) > ++ } > ++ case "plan9": > ++ for i := range plan9reservedpathtests { > ++ plan9reservedpathtests[i].result = invalid > ++ } > ++ } > ++ tests := fspathtests > ++ tests = append(tests, winreservedpathtests...) > ++ tests = append(tests, plan9reservedpathtests...) > ++ for _, test := range tests { > ++ got, err := safefilepath.FromFS(test.path) > ++ if (got == "") != (err != nil) { > ++ t.Errorf(`FromFS(%q) = %q, %v; want "" only if err != nil`, test.path, got, err) > ++ } > ++ if got != test.result { > ++ t.Errorf("FromFS(%q) = %q, %v; want %q", test.path, got, err, test.result) > ++ } > ++ } > ++} > ++ > ++func canWriteFile(t *testing.T, name string) bool { > ++ path := filepath.Join(t.TempDir(), name) > ++ os.WriteFile(path, []byte("ok"), 0666) > ++ b, _ := os.ReadFile(path) > ++ return string(b) == "ok" > ++} > +diff --git a/src/internal/safefilepath/path_windows.go b/src/internal/safefilepath/path_windows.go > +new file mode 100644 > +index 0000000..909c150 > +--- /dev/null > ++++ b/src/internal/safefilepath/path_windows.go > +@@ -0,0 +1,95 @@ > ++// Copyright 2022 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. > ++ > ++package safefilepath > ++ > ++import ( > ++ "syscall" > ++ "unicode/utf8" > ++) > ++ > ++func fromFS(path string) (string, error) { > ++ if !utf8.ValidString(path) { > ++ return "", errInvalidPath > ++ } > ++ for len(path) > 1 && path[0] == '/' && path[1] == '/' { > ++ path = path[1:] > ++ } > ++ containsSlash := false > ++ 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++ > ++ } > ++ part := p[:i] > ++ if i < len(p) { > ++ containsSlash = true > ++ p = p[i+1:] > ++ } 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 containsSlash { > ++ // We can't depend on strings, so substitute \ for / manually. > ++ buf := []byte(path) > ++ for i, b := range buf { > ++ if b == '/' { > ++ buf[i] = '\\' > ++ } > ++ } > ++ path = string(buf) > ++ } > ++ return path, nil > ++} > ++ > ++// 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 toUpper(c byte) byte { > ++ if 'a' <= c && c <= 'z' { > ++ return c - ('a' - 'A') > ++ } > ++ return c > ++} > +diff --git a/src/net/http/fs.go b/src/net/http/fs.go > +index 57e731e..43ee4b5 100644 > +--- a/src/net/http/fs.go > ++++ b/src/net/http/fs.go > +@@ -9,6 +9,7 @@ package http > + import ( > + "errors" > + "fmt" > ++ "internal/safefilepath" > + "io" > + "io/fs" > + "mime" +@@ -69,14 +70,15 @@ func mapDirOpenError(originalErr error, name > string) error { + // Open implements FileSystem using os.Open, opening > files for reading rooted + // and relative to the directory d. + func > (d Dir) Open(name string) (File, error) { +- if filepath.Separator != > '/' && strings.ContainsRune(name, filepath.Separator) { +- return nil, > errors.New("http: invalid character in file path") > ++ path, err := safefilepath.FromFS(path.Clean("/" + name)) > ++ if err != nil { > ++ return nil, errors.New("http: invalid or unsafe file path") > + } > + dir := string(d) > + if dir == "" { > + dir = "." > + } > +- fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))) > ++ fullName := filepath.Join(dir, path) > + f, err := os.Open(fullName) > + if err != nil { > + return nil, mapDirOpenError(err, fullName) > +diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go > +index b42ade1..941448a 100644 > +--- a/src/net/http/fs_test.go > ++++ b/src/net/http/fs_test.go > +@@ -648,6 +648,34 @@ func TestFileServerZeroByte(t *testing.T) { > + } > + } > + > ++func TestFileServerNamesEscape(t *testing.T) { > ++ t.Run("h1", func(t *testing.T) { > ++ testFileServerNamesEscape(t, h1Mode) > ++ }) > ++ t.Run("h2", func(t *testing.T) { > ++ testFileServerNamesEscape(t, h2Mode) > ++ }) > ++} > ++func testFileServerNamesEscape(t *testing.T, h2 bool) { > ++ defer afterTest(t) > ++ ts := newClientServerTest(t, h2, FileServer(Dir("testdata"))).ts > ++ defer ts.Close() > ++ for _, path := range []string{ > ++ "/../testdata/file", > ++ "/NUL", // don't read from device files on Windows > ++ } { > ++ res, err := ts.Client().Get(ts.URL + path) > ++ if err != nil { > ++ t.Fatal(err) > ++ } > ++ res.Body.Close() > ++ if res.StatusCode < 400 || res.StatusCode > 599 { > ++ t.Errorf("Get(%q): got status %v, want 4xx or 5xx", path, res.StatusCode) > ++ } > ++ > ++ } > ++} > ++ > + type fakeFileInfo struct { > + dir bool > + basename string > +diff --git a/src/os/file.go b/src/os/file.go > +index e717f17..cb87158 100644 > +--- a/src/os/file.go > ++++ b/src/os/file.go > +@@ -37,12 +37,12 @@ > + // Note: The maximum number of concurrent operations on a File may be limited by > + // the OS or the system. The number should be high, but exceeding it may degrade > + // performance or cause other issues. > +-// > + package os > + > + import ( > + "errors" > + "internal/poll" > ++ "internal/safefilepath" > + "internal/testlog" > + "internal/unsafeheader" > + "io" +@@ -623,6 +623,8 @@ func isWindowsNulName(name string) bool { + // > the /prefix tree, then using DirFS does not stop the access any more > than using + // os.Open does. DirFS is therefore not a general > substitute for a chroot-style security + // mechanism when the > directory tree contains arbitrary content. ++// ++// The directory dir > must not be "". > + func DirFS(dir string) fs.FS { > + return dirFS(dir) > + } > +@@ -641,10 +643,11 @@ func containsAny(s, chars string) bool { > + type dirFS string > + > + func (dir dirFS) Open(name string) (fs.File, error) { > +- if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { > +- return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid} > ++ fullname, err := dir.join(name) > ++ if err != nil { > ++ return nil, &PathError{Op: "stat", Path: name, Err: err} > + } > +- f, err := Open(string(dir) + "/" + name) > ++ f, err := Open(fullname) > + if err != nil { > + return nil, err // nil fs.File > + } > +@@ -652,16 +655,35 @@ func (dir dirFS) Open(name string) (fs.File, error) { > + } > + > + func (dir dirFS) Stat(name string) (fs.FileInfo, error) { > +- if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { > +- return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid} > ++ fullname, err := dir.join(name) > ++ if err != nil { > ++ return nil, &PathError{Op: "stat", Path: name, Err: err} > + } > +- f, err := Stat(string(dir) + "/" + name) > ++ f, err := Stat(fullname) > + if err != nil { > + return nil, err > + } > + return f, nil > + } > + > ++// join returns the path for name in dir. > ++func (dir dirFS) join(name string) (string, error) { > ++ if dir == "" { > ++ return "", errors.New("os: DirFS with empty root") > ++ } > ++ if !fs.ValidPath(name) { > ++ return "", ErrInvalid > ++ } > ++ name, err := safefilepath.FromFS(name) > ++ if err != nil { > ++ return "", ErrInvalid > ++ } > ++ if IsPathSeparator(dir[len(dir)-1]) { > ++ return string(dir) + name, nil > ++ } > ++ return string(dir) + string(PathSeparator) + name, nil > ++} > ++ > + // ReadFile reads the named file and returns the contents. > + // A successful call returns err == nil, not err == EOF. > + // Because ReadFile reads the whole file, it does not treat an EOF from Read > +diff --git a/src/os/os_test.go b/src/os/os_test.go > +index 506f1fb..be269bb 100644 > +--- a/src/os/os_test.go > ++++ b/src/os/os_test.go > +@@ -2702,6 +2702,44 @@ func TestDirFS(t *testing.T) { > + if err == nil { > + t.Fatalf(`Open testdata\dirfs succeeded`) > + } > ++ > ++ // Test that Open does not open Windows device files. > ++ _, err = d.Open(`NUL`) > ++ if err == nil { > ++ t.Errorf(`Open NUL succeeded`) > ++ } > ++} > ++ > ++func TestDirFSRootDir(t *testing.T) { > ++ cwd, err := os.Getwd() > ++ if err != nil { > ++ t.Fatal(err) > ++ } > ++ cwd = cwd[len(filepath.VolumeName(cwd)):] // trim volume prefix (C:) on Windows > ++ cwd = filepath.ToSlash(cwd) // convert \ to / > ++ cwd = strings.TrimPrefix(cwd, "/") // trim leading / > ++ > ++ // Test that Open can open a path starting at /. > ++ d := DirFS("/") > ++ f, err := d.Open(cwd + "/testdata/dirfs/a") > ++ if err != nil { > ++ t.Fatal(err) > ++ } > ++ f.Close() > ++} > ++ > ++func TestDirFSEmptyDir(t *testing.T) { > ++ d := DirFS("") > ++ cwd, _ := os.Getwd() > ++ for _, path := range []string{ > ++ "testdata/dirfs/a", // not DirFS(".") > ++ filepath.ToSlash(cwd) + "/testdata/dirfs/a", // not DirFS("/") > ++ } { > ++ _, err := d.Open(path) > ++ if err == nil { > ++ t.Fatalf(`DirFS("").Open(%q) succeeded`, path) > ++ } > ++ } > + } > + > + func TestDirFSPathsValid(t *testing.T) { > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#178840):https://lists.openembedded.org/g/openembedded-core/message/178840 > Mute This Topic:https://lists.openembedded.org/mt/97740601/3616765 > Group Owner:openembedded-core+owner@lists.openembedded.org > Unsubscribe:https://lists.openembedded.org/g/openembedded-core/unsub [randy.macleod@windriver.com] > -=-=-=-=-=-=-=-=-=-=-=- >
On 2023-03-20 17:05, Randy MacLeod wrote: > On 2023-03-20 16:09, Sakib Sajal via lists.openembedded.org wrote: >> Backport appropriate patches to fix CVE-2022-2879 and CVE-2022-41720. >> >> Modified the original fix for CVE-2022-2879 to remove a testdata tarball >> and any references to it since git binary diffs are not supported in quilt. >> >> Signed-off-by: Sakib Sajal<sakib.sajal@windriver.com> >> --- >> meta/recipes-devtools/go/go-1.17.13.inc | 36 +- >> ...01-archive-tar-limit-size-of-headers.patch | 177 ++++++ >> ...d-escapes-from-os.DirFS-and-http.Dir.patch | 514 ++++++++++++++++++ >> 3 files changed, 710 insertions(+), 17 deletions(-) >> create mode 100644 meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch >> create mode 100644 meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch >> >> diff --git a/meta/recipes-devtools/go/go-1.17.13.inc b/meta/recipes-devtools/go/go-1.17.13.inc >> index 99662bd298..f5cf192361 100644 >> --- a/meta/recipes-devtools/go/go-1.17.13.inc >> +++ b/meta/recipes-devtools/go/go-1.17.13.inc >> @@ -4,23 +4,25 @@ FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/go-1.18:" >> >> LIC_FILES_CHKSUM ="file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" >> >> -SRC_URI += "\ >> -file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ >> -file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ >> -file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ >> -file://0004-ld-add-soname-to-shareable-objects.patch \ >> -file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ >> -file://0006-cmd-dist-separate-host-and-target-builds.patch \ >> -file://0007-cmd-go-make-GOROOT-precious-by-default.patch \ >> -file://0008-use-GOBUILDMODE-to-set-buildmode.patch \ >> -file://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ >> -file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ >> -file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ >> -file://CVE-2022-27664.patch \ >> -file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ >> -file://CVE-2022-41715.patch \ >> -file://CVE-2022-41717.patch \ >> -" >> +SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \ > > > Nack. > > > Sakib, > > You said this works for you but if you look at: > > ❯ cat meta/recipes-devtools/go/go-1.17.13.inc > require go-common.inc > > FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/go-1.18:" > > LIC_FILES_CHKSUM = "file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" > > SRC_URI += "\ > ... > > and then > > ❯ grep SRC_URI meta/recipes-devtools/go/go-common.inc > SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main" > > You see that you should stick with the += operator. > > I think you said that devtool changed that , right? > > If so, and if we can learn why this change even built for you, > then consider opening a bug against devtool. > > ../Randy > > Yes, this change was done by "devtool update-recipe go" I do not think what devtool did is wrong. go-common.inc is included only by go-1.17.13.inc and the SRC_URI from go-common.inc is included in the SRC_URI for go-1.17.13.inc, in the correct order too, so technically you do not need the += in go-1.17.13.inc file. Regardless SRC_URI change should not be part of CVE fix, sending a v2 by updating the recipe manually. Sakib >> +file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ >> +file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ >> +file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ >> +file://0004-ld-add-soname-to-shareable-objects.patch \ >> +file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ >> +file://0006-cmd-dist-separate-host-and-target-builds.patch \ >> +file://0007-cmd-go-make-GOROOT-precious-by-default.patch \ >> +file://0008-use-GOBUILDMODE-to-set-buildmode.patch \ >> +file://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ >> +file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ >> +file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ >> +file://CVE-2022-27664.patch \ >> +file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ >> +file://CVE-2022-41715.patch \ >> +file://CVE-2022-41717.patch \ >> +file://0001-archive-tar-limit-size-of-headers.patch \ >> +file://0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch \ >> + " >> SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" >> >> # Upstream don't believe it is a signifiant real world issue and will only >> diff --git a/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch b/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch >> new file mode 100644 >> index 0000000000..0315e1a3ee >> --- /dev/null >> +++ b/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch >> @@ -0,0 +1,177 @@ >> +From d064ed520a7cc6b480f9565e30751e695d394f4e Mon Sep 17 00:00:00 2001 >> +From: Damien Neil<dneil@google.com> >> +Date: Fri, 2 Sep 2022 20:45:18 -0700 >> +Subject: [PATCH] archive/tar: limit size of headers >> + >> +Set a 1MiB limit on special file blocks (PAX headers, GNU long names, >> +GNU link names), to avoid reading arbitrarily large amounts of data >> +into memory. >> + >> +Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting >> +this issue. >> + >> +Fixes CVE-2022-2879 >> +Updates #54853 >> +Fixes #55925 >> + >> +Change-Id: I85136d6ff1e0af101a112190e027987ab4335680 >> +Reviewed-on:https://team-review.git.corp.google.com/c/golang/go-private/+/1565555 >> +Reviewed-by: Tatiana Bradley<tatianabradley@google.com> >> +Run-TryBot: Roland Shoemaker<bracewell@google.com> >> +Reviewed-by: Roland Shoemaker<bracewell@google.com> >> +(cherry picked from commit 6ee768cef6b82adf7a90dcf367a1699ef694f3b2) >> +Reviewed-on:https://team-review.git.corp.google.com/c/golang/go-private/+/1590622 >> +Reviewed-by: Damien Neil<dneil@google.com> >> +Reviewed-by: Julie Qiu<julieqiu@google.com> >> +Reviewed-on:https://go-review.googlesource.com/c/go/+/438500 >> +Reviewed-by: Dmitri Shuralyov<dmitshur@golang.org> >> +Reviewed-by: Carlos Amedee<carlos@golang.org> >> +Reviewed-by: Dmitri Shuralyov<dmitshur@google.com> >> +Run-TryBot: Carlos Amedee<carlos@golang.org> >> +TryBot-Result: Gopher Robot<gobot@golang.org> >> + >> +CVE: CVE-2022-2879 >> +Upstream-Status: Backport [0a723816cd205576945fa57fbdde7e6532d59d08] >> +Signed-off-by: Sakib Sajal<sakib.sajal@windriver.com> >> +--- >> + src/archive/tar/format.go | 4 ++++ >> + src/archive/tar/reader.go | 14 ++++++++++++-- >> + src/archive/tar/reader_test.go | 8 +++++++- >> + src/archive/tar/writer.go | 3 +++ >> + src/archive/tar/writer_test.go | 27 +++++++++++++++++++++++++++ >> + 5 files changed, 53 insertions(+), 3 deletions(-) >> + >> +diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go >> +index cfe24a5..6642364 100644 >> +--- a/src/archive/tar/format.go >> ++++ b/src/archive/tar/format.go >> +@@ -143,6 +143,10 @@ const ( >> + blockSize = 512 // Size of each block in a tar stream >> + nameSize = 100 // Max length of the name field in USTAR format >> + prefixSize = 155 // Max length of the prefix field in USTAR format >> ++ >> ++ // Max length of a special file (PAX header, GNU long name or link). >> ++ // This matches the limit used by libarchive. >> ++ maxSpecialFileSize = 1 << 20 >> + ) >> + >> + // blockPadding computes the number of bytes needed to pad offset up to the >> +diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go >> +index 1b1d5b4..f645af8 100644 >> +--- a/src/archive/tar/reader.go >> ++++ b/src/archive/tar/reader.go >> +@@ -103,7 +103,7 @@ func (tr *Reader) next() (*Header, error) { >> + continue // This is a meta header affecting the next header >> + case TypeGNULongName, TypeGNULongLink: >> + format.mayOnlyBe(FormatGNU) >> +- realname, err := io.ReadAll(tr) >> ++ realname, err := readSpecialFile(tr) >> + if err != nil { >> + return nil, err >> + } >> +@@ -293,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { >> + // parsePAX parses PAX headers. >> + // If an extended header (type 'x') is invalid, ErrHeader is returned >> + func parsePAX(r io.Reader) (map[string]string, error) { >> +- buf, err := io.ReadAll(r) >> ++ buf, err := readSpecialFile(r) >> + if err != nil { >> + return nil, err >> + } >> +@@ -826,6 +826,16 @@ func tryReadFull(r io.Reader, b []byte) (n int, err error) { >> + return n, err >> + } >> + >> ++// readSpecialFile is like io.ReadAll except it returns >> ++// ErrFieldTooLong if more than maxSpecialFileSize is read. >> ++func readSpecialFile(r io.Reader) ([]byte, error) { >> ++ buf, err := io.ReadAll(io.LimitReader(r, maxSpecialFileSize+1)) >> ++ if len(buf) > maxSpecialFileSize { >> ++ return nil, ErrFieldTooLong >> ++ } >> ++ return buf, err >> ++} >> ++ >> + // discard skips n bytes in r, reporting an error if unable to do so. >> + func discard(r io.Reader, n int64) error { >> + // If possible, Seek to the last byte before the end of the data section. >> +diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go >> +index 789ddc1..926dc3d 100644 >> +--- a/src/archive/tar/reader_test.go >> ++++ b/src/archive/tar/reader_test.go >> +@@ -6,6 +6,7 @@ package tar >> + >> + import ( >> + "bytes" >> ++ "compress/bzip2" >> + "crypto/md5" >> + "errors" >> + "fmt" +@@ -625,9 +626,14 @@ func TestReader(t *testing.T) { + } + defer >> f.Close() + ++ var fr io.Reader = f ++ if strings.HasSuffix(v.file, ".bz2") { >> ++ fr = bzip2.NewReader(fr) >> ++ } >> ++ >> + // Capture all headers and checksums. >> + var ( >> +- tr = NewReader(f) >> ++ tr = NewReader(fr) >> + hdrs []*Header >> + chksums []string >> + rdbuf = make([]byte, 8) >> +diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go >> +index e80498d..893eac0 100644 >> +--- a/src/archive/tar/writer.go >> ++++ b/src/archive/tar/writer.go >> +@@ -199,6 +199,9 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error { >> + flag = TypeXHeader >> + } >> + data := buf.String() >> ++ if len(data) > maxSpecialFileSize { >> ++ return ErrFieldTooLong >> ++ } >> + if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal { >> + return err // Global headers return here >> + } >> +diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go >> +index a00f02d..4e709e5 100644 >> +--- a/src/archive/tar/writer_test.go >> ++++ b/src/archive/tar/writer_test.go >> +@@ -1006,6 +1006,33 @@ func TestIssue12594(t *testing.T) { >> + } >> + } >> + >> ++func TestWriteLongHeader(t *testing.T) { >> ++ for _, test := range []struct { >> ++ name string >> ++ h *Header >> ++ }{{ >> ++ name: "name too long", >> ++ h: &Header{Name: strings.Repeat("a", maxSpecialFileSize)}, >> ++ }, { >> ++ name: "linkname too long", >> ++ h: &Header{Linkname: strings.Repeat("a", maxSpecialFileSize)}, >> ++ }, { >> ++ name: "uname too long", >> ++ h: &Header{Uname: strings.Repeat("a", maxSpecialFileSize)}, >> ++ }, { >> ++ name: "gname too long", >> ++ h: &Header{Gname: strings.Repeat("a", maxSpecialFileSize)}, >> ++ }, { >> ++ name: "PAX header too long", >> ++ h: &Header{PAXRecords: map[string]string{"GOLANG.x": strings.Repeat("a", maxSpecialFileSize)}}, >> ++ }} { >> ++ w := NewWriter(io.Discard) >> ++ if err := w.WriteHeader(test.h); err != ErrFieldTooLong { >> ++ t.Errorf("%v: w.WriteHeader() = %v, want ErrFieldTooLong", test.name, err) >> ++ } >> ++ } >> ++} >> ++ >> + // testNonEmptyWriter wraps an io.Writer and ensures that >> + // Write is never called with an empty buffer. >> + type testNonEmptyWriter struct{ io.Writer } >> diff --git a/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch b/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch >> new file mode 100644 >> index 0000000000..6c2e8804b3 >> --- /dev/null >> +++ b/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch >> @@ -0,0 +1,514 @@ >> +From f8896a97a0630b0f2f8c488310147f7f20b3ec7d Mon Sep 17 00:00:00 2001 >> +From: Damien Neil<dneil@google.com> >> +Date: Thu, 10 Nov 2022 12:16:27 -0800 >> +Subject: [PATCH] os, net/http: avoid escapes from os.DirFS and http.Dir on >> + Windows >> + >> +Do not permit access to Windows reserved device names (NUL, COM1, etc.) >> +via os.DirFS and http.Dir filesystems. >> + >> +Avoid escapes from os.DirFS(`\`) on Windows. DirFS would join the >> +the root to the relative path with a path separator, making >> +os.DirFS(`\`).Open(`/foo/bar`) open the path `\\foo\bar`, which is >> +a UNC name. Not only does this not open the intended file, but permits >> +reference to any file on the system rather than only files on the >> +current drive. >> + >> +Make os.DirFS("") invalid, with all file access failing. Previously, >> +a root of "" was interpreted as "/", which is surprising and probably >> +unintentional. >> + >> +Fixes CVE-2022-41720. >> +Fixes #56694. >> + >> +Change-Id: I275b5fa391e6ad7404309ea98ccc97405942e0f0 >> +Reviewed-on:https://team-review.git.corp.google.com/c/golang/go-private/+/1663832 >> +Reviewed-by: Julie Qiu<julieqiu@google.com> >> +Reviewed-by: Tatiana Bradley<tatianabradley@google.com> >> +Reviewed-on:https://go-review.googlesource.com/c/go/+/455360 >> +Reviewed-by: Michael Pratt<mpratt@google.com> >> +TryBot-Result: Gopher Robot<gobot@golang.org> >> +Run-TryBot: Jenny Rakoczy<jenny@golang.org> >> + >> +CVE: CVE-2022-41720 >> +Upstream-Status: Backport [7013a4f5f816af62033ad63dd06b77c30d7a62a7] >> +Signed-off-by: Sakib Sajal<sakib.sajal@windriver.com> >> +--- >> + src/go/build/deps_test.go | 1 + >> + src/internal/safefilepath/path.go | 21 +++++ >> + src/internal/safefilepath/path_other.go | 23 ++++++ >> + src/internal/safefilepath/path_test.go | 88 +++++++++++++++++++++ >> + src/internal/safefilepath/path_windows.go | 95 +++++++++++++++++++++++ >> + src/net/http/fs.go | 8 +- >> + src/net/http/fs_test.go | 28 +++++++ >> + src/os/file.go | 36 +++++++-- >> + src/os/os_test.go | 38 +++++++++ >> + 9 files changed, 328 insertions(+), 10 deletions(-) >> + create mode 100644 src/internal/safefilepath/path.go >> + create mode 100644 src/internal/safefilepath/path_other.go >> + create mode 100644 src/internal/safefilepath/path_test.go >> + create mode 100644 src/internal/safefilepath/path_windows.go >> + >> +diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go >> +index 45e2f25..dc3bb8c 100644 >> +--- a/src/go/build/deps_test.go >> ++++ b/src/go/build/deps_test.go >> +@@ -165,6 +165,7 @@ var depsRules = ` >> + io/fs >> + < internal/testlog >> + < internal/poll >> ++ < internal/safefilepath >> + < os >> + < os/signal; >> + >> +diff --git a/src/internal/safefilepath/path.go b/src/internal/safefilepath/path.go >> +new file mode 100644 >> +index 0000000..0f0a270 >> +--- /dev/null >> ++++ b/src/internal/safefilepath/path.go >> +@@ -0,0 +1,21 @@ >> ++// Copyright 2022 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. >> ++ >> ++// Package safefilepath manipulates operating-system file paths. >> ++package safefilepath >> ++ >> ++import ( >> ++ "errors" >> ++) >> ++ >> ++var errInvalidPath = errors.New("invalid path") >> ++ >> ++// FromFS converts a slash-separated path into an operating-system path. >> ++// >> ++// FromFS returns an error if the path cannot be represented by the operating >> ++// system. For example, paths containing '\' and ':' characters are rejected >> ++// on Windows. >> ++func FromFS(path string) (string, error) { >> ++ return fromFS(path) >> ++} >> +diff --git a/src/internal/safefilepath/path_other.go b/src/internal/safefilepath/path_other.go >> +new file mode 100644 >> +index 0000000..f93da18 >> +--- /dev/null >> ++++ b/src/internal/safefilepath/path_other.go >> +@@ -0,0 +1,23 @@ >> ++// Copyright 2022 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 safefilepath >> ++ >> ++import "runtime" >> ++ >> ++func fromFS(path string) (string, error) { >> ++ if runtime.GOOS == "plan9" { >> ++ if len(path) > 0 && path[0] == '#' { >> ++ return path, errInvalidPath >> ++ } >> ++ } >> ++ for i := range path { >> ++ if path[i] == 0 { >> ++ return "", errInvalidPath >> ++ } >> ++ } >> ++ return path, nil >> ++} >> +diff --git a/src/internal/safefilepath/path_test.go b/src/internal/safefilepath/path_test.go >> +new file mode 100644 >> +index 0000000..dc662c1 >> +--- /dev/null >> ++++ b/src/internal/safefilepath/path_test.go >> +@@ -0,0 +1,88 @@ >> ++// Copyright 2022 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. >> ++ >> ++package safefilepath_test >> ++ >> ++import ( >> ++ "internal/safefilepath" >> ++ "os" >> ++ "path/filepath" >> ++ "runtime" >> ++ "testing" >> ++) >> ++ >> ++type PathTest struct { >> ++ path, result string >> ++} >> ++ >> ++const invalid = "" >> ++ >> ++var fspathtests = []PathTest{ >> ++ {".", "."}, >> ++ {"/a/b/c", "/a/b/c"}, >> ++ {"a\x00b", invalid}, >> ++} >> ++ >> ++var winreservedpathtests = []PathTest{ >> ++ {`a\b`, `a\b`}, >> ++ {`a:b`, `a:b`}, >> ++ {`a/b:c`, `a/b:c`}, >> ++ {`NUL`, `NUL`}, >> ++ {`./com1`, `./com1`}, >> ++ {`a/nul/b`, `a/nul/b`}, >> ++} >> ++ >> ++// Whether a reserved name with an extension is reserved or not varies by >> ++// Windows version. >> ++var winreservedextpathtests = []PathTest{ >> ++ {"nul.txt", "nul.txt"}, >> ++ {"a/nul.txt/b", "a/nul.txt/b"}, >> ++} >> ++ >> ++var plan9reservedpathtests = []PathTest{ >> ++ {`#c`, `#c`}, >> ++} >> ++ >> ++func TestFromFS(t *testing.T) { >> ++ switch runtime.GOOS { >> ++ case "windows": >> ++ if canWriteFile(t, "NUL") { >> ++ t.Errorf("can unexpectedly write a file named NUL on Windows") >> ++ } >> ++ if canWriteFile(t, "nul.txt") { >> ++ fspathtests = append(fspathtests, winreservedextpathtests...) >> ++ } else { >> ++ winreservedpathtests = append(winreservedpathtests, winreservedextpathtests...) >> ++ } >> ++ for i := range winreservedpathtests { >> ++ winreservedpathtests[i].result = invalid >> ++ } >> ++ for i := range fspathtests { >> ++ fspathtests[i].result = filepath.FromSlash(fspathtests[i].result) >> ++ } >> ++ case "plan9": >> ++ for i := range plan9reservedpathtests { >> ++ plan9reservedpathtests[i].result = invalid >> ++ } >> ++ } >> ++ tests := fspathtests >> ++ tests = append(tests, winreservedpathtests...) >> ++ tests = append(tests, plan9reservedpathtests...) >> ++ for _, test := range tests { >> ++ got, err := safefilepath.FromFS(test.path) >> ++ if (got == "") != (err != nil) { >> ++ t.Errorf(`FromFS(%q) = %q, %v; want "" only if err != nil`, test.path, got, err) >> ++ } >> ++ if got != test.result { >> ++ t.Errorf("FromFS(%q) = %q, %v; want %q", test.path, got, err, test.result) >> ++ } >> ++ } >> ++} >> ++ >> ++func canWriteFile(t *testing.T, name string) bool { >> ++ path := filepath.Join(t.TempDir(), name) >> ++ os.WriteFile(path, []byte("ok"), 0666) >> ++ b, _ := os.ReadFile(path) >> ++ return string(b) == "ok" >> ++} >> +diff --git a/src/internal/safefilepath/path_windows.go b/src/internal/safefilepath/path_windows.go >> +new file mode 100644 >> +index 0000000..909c150 >> +--- /dev/null >> ++++ b/src/internal/safefilepath/path_windows.go >> +@@ -0,0 +1,95 @@ >> ++// Copyright 2022 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. >> ++ >> ++package safefilepath >> ++ >> ++import ( >> ++ "syscall" >> ++ "unicode/utf8" >> ++) >> ++ >> ++func fromFS(path string) (string, error) { >> ++ if !utf8.ValidString(path) { >> ++ return "", errInvalidPath >> ++ } >> ++ for len(path) > 1 && path[0] == '/' && path[1] == '/' { >> ++ path = path[1:] >> ++ } >> ++ containsSlash := false >> ++ 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++ >> ++ } >> ++ part := p[:i] >> ++ if i < len(p) { >> ++ containsSlash = true >> ++ p = p[i+1:] >> ++ } 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 containsSlash { >> ++ // We can't depend on strings, so substitute \ for / manually. >> ++ buf := []byte(path) >> ++ for i, b := range buf { >> ++ if b == '/' { >> ++ buf[i] = '\\' >> ++ } >> ++ } >> ++ path = string(buf) >> ++ } >> ++ return path, nil >> ++} >> ++ >> ++// 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 toUpper(c byte) byte { >> ++ if 'a' <= c && c <= 'z' { >> ++ return c - ('a' - 'A') >> ++ } >> ++ return c >> ++} >> +diff --git a/src/net/http/fs.go b/src/net/http/fs.go >> +index 57e731e..43ee4b5 100644 >> +--- a/src/net/http/fs.go >> ++++ b/src/net/http/fs.go >> +@@ -9,6 +9,7 @@ package http >> + import ( >> + "errors" >> + "fmt" >> ++ "internal/safefilepath" >> + "io" >> + "io/fs" >> + "mime" +@@ -69,14 +70,15 @@ func mapDirOpenError(originalErr error, name >> string) error { + // Open implements FileSystem using os.Open, >> opening files for reading rooted + // and relative to the directory >> d. + func (d Dir) Open(name string) (File, error) { +- if >> filepath.Separator != '/' && strings.ContainsRune(name, >> filepath.Separator) { +- return nil, errors.New("http: invalid character in file path") >> ++ path, err := safefilepath.FromFS(path.Clean("/" + name)) >> ++ if err != nil { >> ++ return nil, errors.New("http: invalid or unsafe file path") >> + } >> + dir := string(d) >> + if dir == "" { >> + dir = "." >> + } >> +- fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))) >> ++ fullName := filepath.Join(dir, path) >> + f, err := os.Open(fullName) >> + if err != nil { >> + return nil, mapDirOpenError(err, fullName) >> +diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go >> +index b42ade1..941448a 100644 >> +--- a/src/net/http/fs_test.go >> ++++ b/src/net/http/fs_test.go >> +@@ -648,6 +648,34 @@ func TestFileServerZeroByte(t *testing.T) { >> + } >> + } >> + >> ++func TestFileServerNamesEscape(t *testing.T) { >> ++ t.Run("h1", func(t *testing.T) { >> ++ testFileServerNamesEscape(t, h1Mode) >> ++ }) >> ++ t.Run("h2", func(t *testing.T) { >> ++ testFileServerNamesEscape(t, h2Mode) >> ++ }) >> ++} >> ++func testFileServerNamesEscape(t *testing.T, h2 bool) { >> ++ defer afterTest(t) >> ++ ts := newClientServerTest(t, h2, FileServer(Dir("testdata"))).ts >> ++ defer ts.Close() >> ++ for _, path := range []string{ >> ++ "/../testdata/file", >> ++ "/NUL", // don't read from device files on Windows >> ++ } { >> ++ res, err := ts.Client().Get(ts.URL + path) >> ++ if err != nil { >> ++ t.Fatal(err) >> ++ } >> ++ res.Body.Close() >> ++ if res.StatusCode < 400 || res.StatusCode > 599 { >> ++ t.Errorf("Get(%q): got status %v, want 4xx or 5xx", path, res.StatusCode) >> ++ } >> ++ >> ++ } >> ++} >> ++ >> + type fakeFileInfo struct { >> + dir bool >> + basename string >> +diff --git a/src/os/file.go b/src/os/file.go >> +index e717f17..cb87158 100644 >> +--- a/src/os/file.go >> ++++ b/src/os/file.go >> +@@ -37,12 +37,12 @@ >> + // Note: The maximum number of concurrent operations on a File may be limited by >> + // the OS or the system. The number should be high, but exceeding it may degrade >> + // performance or cause other issues. >> +-// >> + package os >> + >> + import ( >> + "errors" >> + "internal/poll" >> ++ "internal/safefilepath" >> + "internal/testlog" >> + "internal/unsafeheader" >> + "io" +@@ -623,6 +623,8 @@ func isWindowsNulName(name string) bool { + // >> the /prefix tree, then using DirFS does not stop the access any more >> than using + // os.Open does. DirFS is therefore not a general >> substitute for a chroot-style security + // mechanism when the >> directory tree contains arbitrary content. ++// ++// The directory >> dir must not be "". >> + func DirFS(dir string) fs.FS { >> + return dirFS(dir) >> + } >> +@@ -641,10 +643,11 @@ func containsAny(s, chars string) bool { >> + type dirFS string >> + >> + func (dir dirFS) Open(name string) (fs.File, error) { >> +- if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { >> +- return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid} >> ++ fullname, err := dir.join(name) >> ++ if err != nil { >> ++ return nil, &PathError{Op: "stat", Path: name, Err: err} >> + } >> +- f, err := Open(string(dir) + "/" + name) >> ++ f, err := Open(fullname) >> + if err != nil { >> + return nil, err // nil fs.File >> + } >> +@@ -652,16 +655,35 @@ func (dir dirFS) Open(name string) (fs.File, error) { >> + } >> + >> + func (dir dirFS) Stat(name string) (fs.FileInfo, error) { >> +- if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { >> +- return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid} >> ++ fullname, err := dir.join(name) >> ++ if err != nil { >> ++ return nil, &PathError{Op: "stat", Path: name, Err: err} >> + } >> +- f, err := Stat(string(dir) + "/" + name) >> ++ f, err := Stat(fullname) >> + if err != nil { >> + return nil, err >> + } >> + return f, nil >> + } >> + >> ++// join returns the path for name in dir. >> ++func (dir dirFS) join(name string) (string, error) { >> ++ if dir == "" { >> ++ return "", errors.New("os: DirFS with empty root") >> ++ } >> ++ if !fs.ValidPath(name) { >> ++ return "", ErrInvalid >> ++ } >> ++ name, err := safefilepath.FromFS(name) >> ++ if err != nil { >> ++ return "", ErrInvalid >> ++ } >> ++ if IsPathSeparator(dir[len(dir)-1]) { >> ++ return string(dir) + name, nil >> ++ } >> ++ return string(dir) + string(PathSeparator) + name, nil >> ++} >> ++ >> + // ReadFile reads the named file and returns the contents. >> + // A successful call returns err == nil, not err == EOF. >> + // Because ReadFile reads the whole file, it does not treat an EOF from Read >> +diff --git a/src/os/os_test.go b/src/os/os_test.go >> +index 506f1fb..be269bb 100644 >> +--- a/src/os/os_test.go >> ++++ b/src/os/os_test.go >> +@@ -2702,6 +2702,44 @@ func TestDirFS(t *testing.T) { >> + if err == nil { >> + t.Fatalf(`Open testdata\dirfs succeeded`) >> + } >> ++ >> ++ // Test that Open does not open Windows device files. >> ++ _, err = d.Open(`NUL`) >> ++ if err == nil { >> ++ t.Errorf(`Open NUL succeeded`) >> ++ } >> ++} >> ++ >> ++func TestDirFSRootDir(t *testing.T) { >> ++ cwd, err := os.Getwd() >> ++ if err != nil { >> ++ t.Fatal(err) >> ++ } >> ++ cwd = cwd[len(filepath.VolumeName(cwd)):] // trim volume prefix (C:) on Windows >> ++ cwd = filepath.ToSlash(cwd) // convert \ to / >> ++ cwd = strings.TrimPrefix(cwd, "/") // trim leading / >> ++ >> ++ // Test that Open can open a path starting at /. >> ++ d := DirFS("/") >> ++ f, err := d.Open(cwd + "/testdata/dirfs/a") >> ++ if err != nil { >> ++ t.Fatal(err) >> ++ } >> ++ f.Close() >> ++} >> ++ >> ++func TestDirFSEmptyDir(t *testing.T) { >> ++ d := DirFS("") >> ++ cwd, _ := os.Getwd() >> ++ for _, path := range []string{ >> ++ "testdata/dirfs/a", // not DirFS(".") >> ++ filepath.ToSlash(cwd) + "/testdata/dirfs/a", // not DirFS("/") >> ++ } { >> ++ _, err := d.Open(path) >> ++ if err == nil { >> ++ t.Fatalf(`DirFS("").Open(%q) succeeded`, path) >> ++ } >> ++ } >> + } >> + >> + func TestDirFSPathsValid(t *testing.T) { >> >> -=-=-=-=-=-=-=-=-=-=-=- >> Links: You receive all messages sent to this group. >> View/Reply Online (#178840):https://lists.openembedded.org/g/openembedded-core/message/178840 >> Mute This Topic:https://lists.openembedded.org/mt/97740601/3616765 >> Group Owner:openembedded-core+owner@lists.openembedded.org >> Unsubscribe:https://lists.openembedded.org/g/openembedded-core/unsub [randy.macleod@windriver.com] >> -=-=-=-=-=-=-=-=-=-=-=- >> > > -- > # Randy MacLeod > # Wind River Linux
diff --git a/meta/recipes-devtools/go/go-1.17.13.inc b/meta/recipes-devtools/go/go-1.17.13.inc index 99662bd298..f5cf192361 100644 --- a/meta/recipes-devtools/go/go-1.17.13.inc +++ b/meta/recipes-devtools/go/go-1.17.13.inc @@ -4,23 +4,25 @@ FILESEXTRAPATHS:prepend := "${FILE_DIRNAME}/go-1.18:" LIC_FILES_CHKSUM = "file://LICENSE;md5=5d4950ecb7b26d2c5e4e7b4e0dd74707" -SRC_URI += "\ - file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ - file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ - file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ - file://0004-ld-add-soname-to-shareable-objects.patch \ - file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ - file://0006-cmd-dist-separate-host-and-target-builds.patch \ - file://0007-cmd-go-make-GOROOT-precious-by-default.patch \ - file://0008-use-GOBUILDMODE-to-set-buildmode.patch \ - file://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ - file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ - file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ - file://CVE-2022-27664.patch \ - file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ - file://CVE-2022-41715.patch \ - file://CVE-2022-41717.patch \ -" +SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \ + file://0001-allow-CC-and-CXX-to-have-multiple-words.patch \ + file://0002-cmd-go-make-content-based-hash-generation-less-pedan.patch \ + file://0003-allow-GOTOOLDIR-to-be-overridden-in-the-environment.patch \ + file://0004-ld-add-soname-to-shareable-objects.patch \ + file://0005-make.bash-override-CC-when-building-dist-and-go_boot.patch \ + file://0006-cmd-dist-separate-host-and-target-builds.patch \ + file://0007-cmd-go-make-GOROOT-precious-by-default.patch \ + file://0008-use-GOBUILDMODE-to-set-buildmode.patch \ + file://0009-Revert-cmd-go-make-sure-CC-and-CXX-are-absolute.patch \ + file://0001-exec.go-do-not-write-linker-flags-into-buildids.patch \ + file://0001-src-cmd-dist-buildgo.go-do-not-hardcode-host-compile.patch \ + file://CVE-2022-27664.patch \ + file://0001-net-http-httputil-avoid-query-parameter-smuggling.patch \ + file://CVE-2022-41715.patch \ + file://CVE-2022-41717.patch \ + file://0001-archive-tar-limit-size-of-headers.patch \ + file://0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch \ + " SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" # Upstream don't believe it is a signifiant real world issue and will only diff --git a/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch b/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch new file mode 100644 index 0000000000..0315e1a3ee --- /dev/null +++ b/meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch @@ -0,0 +1,177 @@ +From d064ed520a7cc6b480f9565e30751e695d394f4e Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Fri, 2 Sep 2022 20:45:18 -0700 +Subject: [PATCH] archive/tar: limit size of headers + +Set a 1MiB limit on special file blocks (PAX headers, GNU long names, +GNU link names), to avoid reading arbitrarily large amounts of data +into memory. + +Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting +this issue. + +Fixes CVE-2022-2879 +Updates #54853 +Fixes #55925 + +Change-Id: I85136d6ff1e0af101a112190e027987ab4335680 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1565555 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +(cherry picked from commit 6ee768cef6b82adf7a90dcf367a1699ef694f3b2) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1590622 +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/438500 +Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org> +Reviewed-by: Carlos Amedee <carlos@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Run-TryBot: Carlos Amedee <carlos@golang.org> +TryBot-Result: Gopher Robot <gobot@golang.org> + +CVE: CVE-2022-2879 +Upstream-Status: Backport [0a723816cd205576945fa57fbdde7e6532d59d08] +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + src/archive/tar/format.go | 4 ++++ + src/archive/tar/reader.go | 14 ++++++++++++-- + src/archive/tar/reader_test.go | 8 +++++++- + src/archive/tar/writer.go | 3 +++ + src/archive/tar/writer_test.go | 27 +++++++++++++++++++++++++++ + 5 files changed, 53 insertions(+), 3 deletions(-) + +diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go +index cfe24a5..6642364 100644 +--- a/src/archive/tar/format.go ++++ b/src/archive/tar/format.go +@@ -143,6 +143,10 @@ const ( + blockSize = 512 // Size of each block in a tar stream + nameSize = 100 // Max length of the name field in USTAR format + prefixSize = 155 // Max length of the prefix field in USTAR format ++ ++ // Max length of a special file (PAX header, GNU long name or link). ++ // This matches the limit used by libarchive. ++ maxSpecialFileSize = 1 << 20 + ) + + // blockPadding computes the number of bytes needed to pad offset up to the +diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go +index 1b1d5b4..f645af8 100644 +--- a/src/archive/tar/reader.go ++++ b/src/archive/tar/reader.go +@@ -103,7 +103,7 @@ func (tr *Reader) next() (*Header, error) { + continue // This is a meta header affecting the next header + case TypeGNULongName, TypeGNULongLink: + format.mayOnlyBe(FormatGNU) +- realname, err := io.ReadAll(tr) ++ realname, err := readSpecialFile(tr) + if err != nil { + return nil, err + } +@@ -293,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { + // parsePAX parses PAX headers. + // If an extended header (type 'x') is invalid, ErrHeader is returned + func parsePAX(r io.Reader) (map[string]string, error) { +- buf, err := io.ReadAll(r) ++ buf, err := readSpecialFile(r) + if err != nil { + return nil, err + } +@@ -826,6 +826,16 @@ func tryReadFull(r io.Reader, b []byte) (n int, err error) { + return n, err + } + ++// readSpecialFile is like io.ReadAll except it returns ++// ErrFieldTooLong if more than maxSpecialFileSize is read. ++func readSpecialFile(r io.Reader) ([]byte, error) { ++ buf, err := io.ReadAll(io.LimitReader(r, maxSpecialFileSize+1)) ++ if len(buf) > maxSpecialFileSize { ++ return nil, ErrFieldTooLong ++ } ++ return buf, err ++} ++ + // discard skips n bytes in r, reporting an error if unable to do so. + func discard(r io.Reader, n int64) error { + // If possible, Seek to the last byte before the end of the data section. +diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go +index 789ddc1..926dc3d 100644 +--- a/src/archive/tar/reader_test.go ++++ b/src/archive/tar/reader_test.go +@@ -6,6 +6,7 @@ package tar + + import ( + "bytes" ++ "compress/bzip2" + "crypto/md5" + "errors" + "fmt" +@@ -625,9 +626,14 @@ func TestReader(t *testing.T) { + } + defer f.Close() + ++ var fr io.Reader = f ++ if strings.HasSuffix(v.file, ".bz2") { ++ fr = bzip2.NewReader(fr) ++ } ++ + // Capture all headers and checksums. + var ( +- tr = NewReader(f) ++ tr = NewReader(fr) + hdrs []*Header + chksums []string + rdbuf = make([]byte, 8) +diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go +index e80498d..893eac0 100644 +--- a/src/archive/tar/writer.go ++++ b/src/archive/tar/writer.go +@@ -199,6 +199,9 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error { + flag = TypeXHeader + } + data := buf.String() ++ if len(data) > maxSpecialFileSize { ++ return ErrFieldTooLong ++ } + if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal { + return err // Global headers return here + } +diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go +index a00f02d..4e709e5 100644 +--- a/src/archive/tar/writer_test.go ++++ b/src/archive/tar/writer_test.go +@@ -1006,6 +1006,33 @@ func TestIssue12594(t *testing.T) { + } + } + ++func TestWriteLongHeader(t *testing.T) { ++ for _, test := range []struct { ++ name string ++ h *Header ++ }{{ ++ name: "name too long", ++ h: &Header{Name: strings.Repeat("a", maxSpecialFileSize)}, ++ }, { ++ name: "linkname too long", ++ h: &Header{Linkname: strings.Repeat("a", maxSpecialFileSize)}, ++ }, { ++ name: "uname too long", ++ h: &Header{Uname: strings.Repeat("a", maxSpecialFileSize)}, ++ }, { ++ name: "gname too long", ++ h: &Header{Gname: strings.Repeat("a", maxSpecialFileSize)}, ++ }, { ++ name: "PAX header too long", ++ h: &Header{PAXRecords: map[string]string{"GOLANG.x": strings.Repeat("a", maxSpecialFileSize)}}, ++ }} { ++ w := NewWriter(io.Discard) ++ if err := w.WriteHeader(test.h); err != ErrFieldTooLong { ++ t.Errorf("%v: w.WriteHeader() = %v, want ErrFieldTooLong", test.name, err) ++ } ++ } ++} ++ + // testNonEmptyWriter wraps an io.Writer and ensures that + // Write is never called with an empty buffer. + type testNonEmptyWriter struct{ io.Writer } diff --git a/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch b/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch new file mode 100644 index 0000000000..6c2e8804b3 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch @@ -0,0 +1,514 @@ +From f8896a97a0630b0f2f8c488310147f7f20b3ec7d Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Thu, 10 Nov 2022 12:16:27 -0800 +Subject: [PATCH] os, net/http: avoid escapes from os.DirFS and http.Dir on + Windows + +Do not permit access to Windows reserved device names (NUL, COM1, etc.) +via os.DirFS and http.Dir filesystems. + +Avoid escapes from os.DirFS(`\`) on Windows. DirFS would join the +the root to the relative path with a path separator, making +os.DirFS(`\`).Open(`/foo/bar`) open the path `\\foo\bar`, which is +a UNC name. Not only does this not open the intended file, but permits +reference to any file on the system rather than only files on the +current drive. + +Make os.DirFS("") invalid, with all file access failing. Previously, +a root of "" was interpreted as "/", which is surprising and probably +unintentional. + +Fixes CVE-2022-41720. +Fixes #56694. + +Change-Id: I275b5fa391e6ad7404309ea98ccc97405942e0f0 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1663832 +Reviewed-by: Julie Qiu <julieqiu@google.com> +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/455360 +Reviewed-by: Michael Pratt <mpratt@google.com> +TryBot-Result: Gopher Robot <gobot@golang.org> +Run-TryBot: Jenny Rakoczy <jenny@golang.org> + +CVE: CVE-2022-41720 +Upstream-Status: Backport [7013a4f5f816af62033ad63dd06b77c30d7a62a7] +Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> +--- + src/go/build/deps_test.go | 1 + + src/internal/safefilepath/path.go | 21 +++++ + src/internal/safefilepath/path_other.go | 23 ++++++ + src/internal/safefilepath/path_test.go | 88 +++++++++++++++++++++ + src/internal/safefilepath/path_windows.go | 95 +++++++++++++++++++++++ + src/net/http/fs.go | 8 +- + src/net/http/fs_test.go | 28 +++++++ + src/os/file.go | 36 +++++++-- + src/os/os_test.go | 38 +++++++++ + 9 files changed, 328 insertions(+), 10 deletions(-) + create mode 100644 src/internal/safefilepath/path.go + create mode 100644 src/internal/safefilepath/path_other.go + create mode 100644 src/internal/safefilepath/path_test.go + create mode 100644 src/internal/safefilepath/path_windows.go + +diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go +index 45e2f25..dc3bb8c 100644 +--- a/src/go/build/deps_test.go ++++ b/src/go/build/deps_test.go +@@ -165,6 +165,7 @@ var depsRules = ` + io/fs + < internal/testlog + < internal/poll ++ < internal/safefilepath + < os + < os/signal; + +diff --git a/src/internal/safefilepath/path.go b/src/internal/safefilepath/path.go +new file mode 100644 +index 0000000..0f0a270 +--- /dev/null ++++ b/src/internal/safefilepath/path.go +@@ -0,0 +1,21 @@ ++// Copyright 2022 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. ++ ++// Package safefilepath manipulates operating-system file paths. ++package safefilepath ++ ++import ( ++ "errors" ++) ++ ++var errInvalidPath = errors.New("invalid path") ++ ++// FromFS converts a slash-separated path into an operating-system path. ++// ++// FromFS returns an error if the path cannot be represented by the operating ++// system. For example, paths containing '\' and ':' characters are rejected ++// on Windows. ++func FromFS(path string) (string, error) { ++ return fromFS(path) ++} +diff --git a/src/internal/safefilepath/path_other.go b/src/internal/safefilepath/path_other.go +new file mode 100644 +index 0000000..f93da18 +--- /dev/null ++++ b/src/internal/safefilepath/path_other.go +@@ -0,0 +1,23 @@ ++// Copyright 2022 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 safefilepath ++ ++import "runtime" ++ ++func fromFS(path string) (string, error) { ++ if runtime.GOOS == "plan9" { ++ if len(path) > 0 && path[0] == '#' { ++ return path, errInvalidPath ++ } ++ } ++ for i := range path { ++ if path[i] == 0 { ++ return "", errInvalidPath ++ } ++ } ++ return path, nil ++} +diff --git a/src/internal/safefilepath/path_test.go b/src/internal/safefilepath/path_test.go +new file mode 100644 +index 0000000..dc662c1 +--- /dev/null ++++ b/src/internal/safefilepath/path_test.go +@@ -0,0 +1,88 @@ ++// Copyright 2022 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. ++ ++package safefilepath_test ++ ++import ( ++ "internal/safefilepath" ++ "os" ++ "path/filepath" ++ "runtime" ++ "testing" ++) ++ ++type PathTest struct { ++ path, result string ++} ++ ++const invalid = "" ++ ++var fspathtests = []PathTest{ ++ {".", "."}, ++ {"/a/b/c", "/a/b/c"}, ++ {"a\x00b", invalid}, ++} ++ ++var winreservedpathtests = []PathTest{ ++ {`a\b`, `a\b`}, ++ {`a:b`, `a:b`}, ++ {`a/b:c`, `a/b:c`}, ++ {`NUL`, `NUL`}, ++ {`./com1`, `./com1`}, ++ {`a/nul/b`, `a/nul/b`}, ++} ++ ++// Whether a reserved name with an extension is reserved or not varies by ++// Windows version. ++var winreservedextpathtests = []PathTest{ ++ {"nul.txt", "nul.txt"}, ++ {"a/nul.txt/b", "a/nul.txt/b"}, ++} ++ ++var plan9reservedpathtests = []PathTest{ ++ {`#c`, `#c`}, ++} ++ ++func TestFromFS(t *testing.T) { ++ switch runtime.GOOS { ++ case "windows": ++ if canWriteFile(t, "NUL") { ++ t.Errorf("can unexpectedly write a file named NUL on Windows") ++ } ++ if canWriteFile(t, "nul.txt") { ++ fspathtests = append(fspathtests, winreservedextpathtests...) ++ } else { ++ winreservedpathtests = append(winreservedpathtests, winreservedextpathtests...) ++ } ++ for i := range winreservedpathtests { ++ winreservedpathtests[i].result = invalid ++ } ++ for i := range fspathtests { ++ fspathtests[i].result = filepath.FromSlash(fspathtests[i].result) ++ } ++ case "plan9": ++ for i := range plan9reservedpathtests { ++ plan9reservedpathtests[i].result = invalid ++ } ++ } ++ tests := fspathtests ++ tests = append(tests, winreservedpathtests...) ++ tests = append(tests, plan9reservedpathtests...) ++ for _, test := range tests { ++ got, err := safefilepath.FromFS(test.path) ++ if (got == "") != (err != nil) { ++ t.Errorf(`FromFS(%q) = %q, %v; want "" only if err != nil`, test.path, got, err) ++ } ++ if got != test.result { ++ t.Errorf("FromFS(%q) = %q, %v; want %q", test.path, got, err, test.result) ++ } ++ } ++} ++ ++func canWriteFile(t *testing.T, name string) bool { ++ path := filepath.Join(t.TempDir(), name) ++ os.WriteFile(path, []byte("ok"), 0666) ++ b, _ := os.ReadFile(path) ++ return string(b) == "ok" ++} +diff --git a/src/internal/safefilepath/path_windows.go b/src/internal/safefilepath/path_windows.go +new file mode 100644 +index 0000000..909c150 +--- /dev/null ++++ b/src/internal/safefilepath/path_windows.go +@@ -0,0 +1,95 @@ ++// Copyright 2022 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. ++ ++package safefilepath ++ ++import ( ++ "syscall" ++ "unicode/utf8" ++) ++ ++func fromFS(path string) (string, error) { ++ if !utf8.ValidString(path) { ++ return "", errInvalidPath ++ } ++ for len(path) > 1 && path[0] == '/' && path[1] == '/' { ++ path = path[1:] ++ } ++ containsSlash := false ++ 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++ ++ } ++ part := p[:i] ++ if i < len(p) { ++ containsSlash = true ++ p = p[i+1:] ++ } 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 containsSlash { ++ // We can't depend on strings, so substitute \ for / manually. ++ buf := []byte(path) ++ for i, b := range buf { ++ if b == '/' { ++ buf[i] = '\\' ++ } ++ } ++ path = string(buf) ++ } ++ return path, nil ++} ++ ++// 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 toUpper(c byte) byte { ++ if 'a' <= c && c <= 'z' { ++ return c - ('a' - 'A') ++ } ++ return c ++} +diff --git a/src/net/http/fs.go b/src/net/http/fs.go +index 57e731e..43ee4b5 100644 +--- a/src/net/http/fs.go ++++ b/src/net/http/fs.go +@@ -9,6 +9,7 @@ package http + import ( + "errors" + "fmt" ++ "internal/safefilepath" + "io" + "io/fs" + "mime" +@@ -69,14 +70,15 @@ func mapDirOpenError(originalErr error, name string) error { + // Open implements FileSystem using os.Open, opening files for reading rooted + // and relative to the directory d. + func (d Dir) Open(name string) (File, error) { +- if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) { +- return nil, errors.New("http: invalid character in file path") ++ path, err := safefilepath.FromFS(path.Clean("/" + name)) ++ if err != nil { ++ return nil, errors.New("http: invalid or unsafe file path") + } + dir := string(d) + if dir == "" { + dir = "." + } +- fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))) ++ fullName := filepath.Join(dir, path) + f, err := os.Open(fullName) + if err != nil { + return nil, mapDirOpenError(err, fullName) +diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go +index b42ade1..941448a 100644 +--- a/src/net/http/fs_test.go ++++ b/src/net/http/fs_test.go +@@ -648,6 +648,34 @@ func TestFileServerZeroByte(t *testing.T) { + } + } + ++func TestFileServerNamesEscape(t *testing.T) { ++ t.Run("h1", func(t *testing.T) { ++ testFileServerNamesEscape(t, h1Mode) ++ }) ++ t.Run("h2", func(t *testing.T) { ++ testFileServerNamesEscape(t, h2Mode) ++ }) ++} ++func testFileServerNamesEscape(t *testing.T, h2 bool) { ++ defer afterTest(t) ++ ts := newClientServerTest(t, h2, FileServer(Dir("testdata"))).ts ++ defer ts.Close() ++ for _, path := range []string{ ++ "/../testdata/file", ++ "/NUL", // don't read from device files on Windows ++ } { ++ res, err := ts.Client().Get(ts.URL + path) ++ if err != nil { ++ t.Fatal(err) ++ } ++ res.Body.Close() ++ if res.StatusCode < 400 || res.StatusCode > 599 { ++ t.Errorf("Get(%q): got status %v, want 4xx or 5xx", path, res.StatusCode) ++ } ++ ++ } ++} ++ + type fakeFileInfo struct { + dir bool + basename string +diff --git a/src/os/file.go b/src/os/file.go +index e717f17..cb87158 100644 +--- a/src/os/file.go ++++ b/src/os/file.go +@@ -37,12 +37,12 @@ + // Note: The maximum number of concurrent operations on a File may be limited by + // the OS or the system. The number should be high, but exceeding it may degrade + // performance or cause other issues. +-// + package os + + import ( + "errors" + "internal/poll" ++ "internal/safefilepath" + "internal/testlog" + "internal/unsafeheader" + "io" +@@ -623,6 +623,8 @@ func isWindowsNulName(name string) bool { + // the /prefix tree, then using DirFS does not stop the access any more than using + // os.Open does. DirFS is therefore not a general substitute for a chroot-style security + // mechanism when the directory tree contains arbitrary content. ++// ++// The directory dir must not be "". + func DirFS(dir string) fs.FS { + return dirFS(dir) + } +@@ -641,10 +643,11 @@ func containsAny(s, chars string) bool { + type dirFS string + + func (dir dirFS) Open(name string) (fs.File, error) { +- if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { +- return nil, &PathError{Op: "open", Path: name, Err: ErrInvalid} ++ fullname, err := dir.join(name) ++ if err != nil { ++ return nil, &PathError{Op: "stat", Path: name, Err: err} + } +- f, err := Open(string(dir) + "/" + name) ++ f, err := Open(fullname) + if err != nil { + return nil, err // nil fs.File + } +@@ -652,16 +655,35 @@ func (dir dirFS) Open(name string) (fs.File, error) { + } + + func (dir dirFS) Stat(name string) (fs.FileInfo, error) { +- if !fs.ValidPath(name) || runtime.GOOS == "windows" && containsAny(name, `\:`) { +- return nil, &PathError{Op: "stat", Path: name, Err: ErrInvalid} ++ fullname, err := dir.join(name) ++ if err != nil { ++ return nil, &PathError{Op: "stat", Path: name, Err: err} + } +- f, err := Stat(string(dir) + "/" + name) ++ f, err := Stat(fullname) + if err != nil { + return nil, err + } + return f, nil + } + ++// join returns the path for name in dir. ++func (dir dirFS) join(name string) (string, error) { ++ if dir == "" { ++ return "", errors.New("os: DirFS with empty root") ++ } ++ if !fs.ValidPath(name) { ++ return "", ErrInvalid ++ } ++ name, err := safefilepath.FromFS(name) ++ if err != nil { ++ return "", ErrInvalid ++ } ++ if IsPathSeparator(dir[len(dir)-1]) { ++ return string(dir) + name, nil ++ } ++ return string(dir) + string(PathSeparator) + name, nil ++} ++ + // ReadFile reads the named file and returns the contents. + // A successful call returns err == nil, not err == EOF. + // Because ReadFile reads the whole file, it does not treat an EOF from Read +diff --git a/src/os/os_test.go b/src/os/os_test.go +index 506f1fb..be269bb 100644 +--- a/src/os/os_test.go ++++ b/src/os/os_test.go +@@ -2702,6 +2702,44 @@ func TestDirFS(t *testing.T) { + if err == nil { + t.Fatalf(`Open testdata\dirfs succeeded`) + } ++ ++ // Test that Open does not open Windows device files. ++ _, err = d.Open(`NUL`) ++ if err == nil { ++ t.Errorf(`Open NUL succeeded`) ++ } ++} ++ ++func TestDirFSRootDir(t *testing.T) { ++ cwd, err := os.Getwd() ++ if err != nil { ++ t.Fatal(err) ++ } ++ cwd = cwd[len(filepath.VolumeName(cwd)):] // trim volume prefix (C:) on Windows ++ cwd = filepath.ToSlash(cwd) // convert \ to / ++ cwd = strings.TrimPrefix(cwd, "/") // trim leading / ++ ++ // Test that Open can open a path starting at /. ++ d := DirFS("/") ++ f, err := d.Open(cwd + "/testdata/dirfs/a") ++ if err != nil { ++ t.Fatal(err) ++ } ++ f.Close() ++} ++ ++func TestDirFSEmptyDir(t *testing.T) { ++ d := DirFS("") ++ cwd, _ := os.Getwd() ++ for _, path := range []string{ ++ "testdata/dirfs/a", // not DirFS(".") ++ filepath.ToSlash(cwd) + "/testdata/dirfs/a", // not DirFS("/") ++ } { ++ _, err := d.Open(path) ++ if err == nil { ++ t.Fatalf(`DirFS("").Open(%q) succeeded`, path) ++ } ++ } + } + + func TestDirFSPathsValid(t *testing.T) {
Backport appropriate patches to fix CVE-2022-2879 and CVE-2022-41720. Modified the original fix for CVE-2022-2879 to remove a testdata tarball and any references to it since git binary diffs are not supported in quilt. Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> --- meta/recipes-devtools/go/go-1.17.13.inc | 36 +- ...01-archive-tar-limit-size-of-headers.patch | 177 ++++++ ...d-escapes-from-os.DirFS-and-http.Dir.patch | 514 ++++++++++++++++++ 3 files changed, 710 insertions(+), 17 deletions(-) create mode 100644 meta/recipes-devtools/go/go-1.18/0001-archive-tar-limit-size-of-headers.patch create mode 100644 meta/recipes-devtools/go/go-1.18/0002-os-net-http-avoid-escapes-from-os.DirFS-and-http.Dir.patch