diff --git a/0001-release-branch.go1.17-crypto-elliptic-tolerate-zero-.patch b/0001-release-branch.go1.17-crypto-elliptic-tolerate-zero-.patch deleted file mode 100644 index 6f993e03193c56d30da7f26fdb8cbdc9c9e95ebd..0000000000000000000000000000000000000000 --- a/0001-release-branch.go1.17-crypto-elliptic-tolerate-zero-.patch +++ /dev/null @@ -1,60 +0,0 @@ -From ad33fdc8f4bce612842d922ca701c3062fe4d4c6 Mon Sep 17 00:00:00 2001 -From: Filippo Valsorda -Date: Thu, 31 Mar 2022 12:31:58 -0400 -Subject: [Backport 1/2] [release-branch.go1.17] crypto/elliptic: tolerate - zero-padded scalars in generic P-256 - -Updates #52075 -Fixes #52076 -Fixes CVE-2022-28327 - -Change-Id: I595a7514c9a0aa1b9c76aedfc2307e1124271f27 -Reviewed-on: https://go-review.googlesource.com/c/go/+/397136 -Trust: Filippo Valsorda -Reviewed-by: Julie Qiu - -Conflict:NA -Reference:https://go-review.googlesource.com/c/go/+/399816,https://go-review.googlesource.com/c/go/+/397136 ---- - src/crypto/elliptic/p256.go | 2 +- - src/crypto/elliptic/p256_test.go | 14 ++++++++++++++ - 2 files changed, 15 insertions(+), 1 deletion(-) - -diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go -index b2b12c8f13..da5283735c 100644 ---- a/src/crypto/elliptic/p256.go -+++ b/src/crypto/elliptic/p256.go -@@ -52,7 +52,7 @@ func p256GetScalar(out *[32]byte, in []byte) { - n := new(big.Int).SetBytes(in) - var scalarBytes []byte - -- if n.Cmp(p256Params.N) >= 0 { -+ if n.Cmp(p256Params.N) >= 0 || len(in) > len(out) { - n.Mod(n, p256Params.N) - scalarBytes = n.Bytes() - } else { -diff --git a/src/crypto/elliptic/p256_test.go b/src/crypto/elliptic/p256_test.go -index 1435f5e1a5..694186df81 100644 ---- a/src/crypto/elliptic/p256_test.go -+++ b/src/crypto/elliptic/p256_test.go -@@ -153,3 +153,17 @@ func TestP256CombinedMult(t *testing.T) { - t.Errorf("1×G + (-1)×G = (%d, %d), should be ∞", x, y) - } - } -+ -+func TestIssue52075(t *testing.T) { -+ Gx, Gy := P256().Params().Gx, P256().Params().Gy -+ scalar := make([]byte, 33) -+ scalar[32] = 1 -+ x, y := P256().ScalarBaseMult(scalar) -+ if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 { -+ t.Errorf("unexpected output (%v,%v)", x, y) -+ } -+ x, y = P256().ScalarMult(Gx, Gy, scalar) -+ if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 { -+ t.Errorf("unexpected output (%v,%v)", x, y) -+ } -+} --- -2.30.0 - diff --git a/0002-release-branch.go1.17-encoding-pem-fix-stack-overflo.patch b/0002-release-branch.go1.17-encoding-pem-fix-stack-overflo.patch deleted file mode 100644 index 243596c90ead364fc953a1fd4144479adb812e12..0000000000000000000000000000000000000000 --- a/0002-release-branch.go1.17-encoding-pem-fix-stack-overflo.patch +++ /dev/null @@ -1,291 +0,0 @@ -From baaaf3ce29bf98efc00c2f06c531f2b0186b027b Mon Sep 17 00:00:00 2001 -From: Julie Qiu -Date: Tue, 1 Mar 2022 10:19:38 -0600 -Subject: [Backport 2/2] [release-branch.go1.17] encoding/pem: fix stack - overflow in Decode - -Previously, Decode called decodeError, a recursive function that was -prone to stack overflows when given a large PEM file containing errors. - -Credit to Juho Nurminen of Mattermost who reported the error. - -Fixes CVE-2022-24675 -Updates #51853 -Fixes #52036 - -Change-Id: Iffe768be53c8ddc0036fea0671d290f8f797692c -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1391157 -Reviewed-by: Damien Neil -Reviewed-by: Filippo Valsorda -(cherry picked from commit 794ea5e828010e8b68493b2fc6d2963263195a02) -Reviewed-on: https://go-review.googlesource.com/c/go/+/399816 -Run-TryBot: Dmitri Shuralyov -Reviewed-by: Dmitri Shuralyov -Reviewed-by: Cherry Mui -TryBot-Result: Gopher Robot - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/399816 ---- - src/encoding/pem/pem.go | 174 +++++++++++++++-------------------- - src/encoding/pem/pem_test.go | 28 +++++- - 2 files changed, 101 insertions(+), 101 deletions(-) - -diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go -index a7272da5ad..1bee1c12d2 100644 ---- a/src/encoding/pem/pem.go -+++ b/src/encoding/pem/pem.go -@@ -87,123 +87,97 @@ func Decode(data []byte) (p *Block, rest []byte) { - // pemStart begins with a newline. However, at the very beginning of - // the byte array, we'll accept the start string without it. - rest = data -- if bytes.HasPrefix(data, pemStart[1:]) { -- rest = rest[len(pemStart)-1 : len(data)] -- } else if i := bytes.Index(data, pemStart); i >= 0 { -- rest = rest[i+len(pemStart) : len(data)] -- } else { -- return nil, data -- } -- -- typeLine, rest := getLine(rest) -- if !bytes.HasSuffix(typeLine, pemEndOfLine) { -- return decodeError(data, rest) -- } -- typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)] -- -- p = &Block{ -- Headers: make(map[string]string), -- Type: string(typeLine), -- } -- - for { -- // This loop terminates because getLine's second result is -- // always smaller than its argument. -- if len(rest) == 0 { -+ if bytes.HasPrefix(rest, pemStart[1:]) { -+ rest = rest[len(pemStart)-1:] -+ } else if i := bytes.Index(rest, pemStart); i >= 0 { -+ rest = rest[i+len(pemStart) : len(rest)] -+ } else { - return nil, data - } -- line, next := getLine(rest) - -- i := bytes.IndexByte(line, ':') -- if i == -1 { -- break -+ var typeLine []byte -+ typeLine, rest = getLine(rest) -+ if !bytes.HasSuffix(typeLine, pemEndOfLine) { -+ continue - } -+ typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)] - -- // TODO(agl): need to cope with values that spread across lines. -- key, val := line[:i], line[i+1:] -- key = bytes.TrimSpace(key) -- val = bytes.TrimSpace(val) -- p.Headers[string(key)] = string(val) -- rest = next -- } -+ p = &Block{ -+ Headers: make(map[string]string), -+ Type: string(typeLine), -+ } - -- var endIndex, endTrailerIndex int -+ for { -+ // This loop terminates because getLine's second result is -+ // always smaller than its argument. -+ if len(rest) == 0 { -+ return nil, data -+ } -+ line, next := getLine(rest) - -- // If there were no headers, the END line might occur -- // immediately, without a leading newline. -- if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) { -- endIndex = 0 -- endTrailerIndex = len(pemEnd) - 1 -- } else { -- endIndex = bytes.Index(rest, pemEnd) -- endTrailerIndex = endIndex + len(pemEnd) -- } -+ i := bytes.IndexByte(line, ':') -+ if i == -1 { -+ break -+ } - -- if endIndex < 0 { -- return decodeError(data, rest) -- } -+ // TODO(agl): need to cope with values that spread across lines. -+ key, val := line[:i], line[i+1:] -+ key = bytes.TrimSpace(key) -+ val = bytes.TrimSpace(val) -+ p.Headers[string(key)] = string(val) -+ rest = next -+ } - -- // After the "-----" of the ending line, there should be the same type -- // and then a final five dashes. -- endTrailer := rest[endTrailerIndex:] -- endTrailerLen := len(typeLine) + len(pemEndOfLine) -- if len(endTrailer) < endTrailerLen { -- return decodeError(data, rest) -- } -+ var endIndex, endTrailerIndex int - -- restOfEndLine := endTrailer[endTrailerLen:] -- endTrailer = endTrailer[:endTrailerLen] -- if !bytes.HasPrefix(endTrailer, typeLine) || -- !bytes.HasSuffix(endTrailer, pemEndOfLine) { -- return decodeError(data, rest) -- } -+ // If there were no headers, the END line might occur -+ // immediately, without a leading newline. -+ if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) { -+ endIndex = 0 -+ endTrailerIndex = len(pemEnd) - 1 -+ } else { -+ endIndex = bytes.Index(rest, pemEnd) -+ endTrailerIndex = endIndex + len(pemEnd) -+ } - -- // The line must end with only whitespace. -- if s, _ := getLine(restOfEndLine); len(s) != 0 { -- return decodeError(data, rest) -- } -+ if endIndex < 0 { -+ continue -+ } - -- base64Data := removeSpacesAndTabs(rest[:endIndex]) -- p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) -- n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) -- if err != nil { -- return decodeError(data, rest) -- } -- p.Bytes = p.Bytes[:n] -+ // After the "-----" of the ending line, there should be the same type -+ // and then a final five dashes. -+ endTrailer := rest[endTrailerIndex:] -+ endTrailerLen := len(typeLine) + len(pemEndOfLine) -+ if len(endTrailer) < endTrailerLen { -+ continue -+ } -+ -+ restOfEndLine := endTrailer[endTrailerLen:] -+ endTrailer = endTrailer[:endTrailerLen] -+ if !bytes.HasPrefix(endTrailer, typeLine) || -+ !bytes.HasSuffix(endTrailer, pemEndOfLine) { -+ continue -+ } - -- // the -1 is because we might have only matched pemEnd without the -- // leading newline if the PEM block was empty. -- _, rest = getLine(rest[endIndex+len(pemEnd)-1:]) -+ // The line must end with only whitespace. -+ if s, _ := getLine(restOfEndLine); len(s) != 0 { -+ continue -+ } - -- return --} -+ base64Data := removeSpacesAndTabs(rest[:endIndex]) -+ p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) -+ n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) -+ if err != nil { -+ continue -+ } -+ p.Bytes = p.Bytes[:n] - --func decodeError(data, rest []byte) (*Block, []byte) { -- // If we get here then we have rejected a likely looking, but -- // ultimately invalid PEM block. We need to start over from a new -- // position. We have consumed the preamble line and will have consumed -- // any lines which could be header lines. However, a valid preamble -- // line is not a valid header line, therefore we cannot have consumed -- // the preamble line for the any subsequent block. Thus, we will always -- // find any valid block, no matter what bytes precede it. -- // -- // For example, if the input is -- // -- // -----BEGIN MALFORMED BLOCK----- -- // junk that may look like header lines -- // or data lines, but no END line -- // -- // -----BEGIN ACTUAL BLOCK----- -- // realdata -- // -----END ACTUAL BLOCK----- -- // -- // we've failed to parse using the first BEGIN line -- // and now will try again, using the second BEGIN line. -- p, rest := Decode(rest) -- if p == nil { -- rest = data -+ // the -1 is because we might have only matched pemEnd without the -+ // leading newline if the PEM block was empty. -+ _, rest = getLine(rest[endIndex+len(pemEnd)-1:]) -+ return p, rest - } -- return p, rest - } - - const pemLineLength = 64 -diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go -index b2b6b15e73..c94b5ca53b 100644 ---- a/src/encoding/pem/pem_test.go -+++ b/src/encoding/pem/pem_test.go -@@ -107,6 +107,12 @@ const pemMissingEndingSpace = ` - dGVzdA== - -----ENDBAR-----` - -+const pemMissingEndLine = ` -+-----BEGIN FOO----- -+Header: 1` -+ -+var pemRepeatingBegin = strings.Repeat("-----BEGIN \n", 10) -+ - var badPEMTests = []struct { - name string - input string -@@ -131,14 +137,34 @@ var badPEMTests = []struct { - "missing ending space", - pemMissingEndingSpace, - }, -+ { -+ "repeating begin", -+ pemRepeatingBegin, -+ }, -+ { -+ "missing end line", -+ pemMissingEndLine, -+ }, - } - - func TestBadDecode(t *testing.T) { - for _, test := range badPEMTests { -- result, _ := Decode([]byte(test.input)) -+ result, rest := Decode([]byte(test.input)) - if result != nil { - t.Errorf("unexpected success while parsing %q", test.name) - } -+ if string(rest) != test.input { -+ t.Errorf("unexpected rest: %q; want = %q", rest, test.input) -+ } -+ } -+} -+ -+func TestCVE202224675(t *testing.T) { -+ // Prior to CVE-2022-24675, this input would cause a stack overflow. -+ input := []byte(strings.Repeat("-----BEGIN \n", 10000000)) -+ result, rest := Decode(input) -+ if result != nil || !reflect.DeepEqual(rest, input) { -+ t.Errorf("Encode of %#v decoded as %#v", input, rest) - } - } - --- -2.30.0 - diff --git a/0003-release-branch.go1.17-syscall-fix-ForkLock-spurious-.patch b/0003-release-branch.go1.17-syscall-fix-ForkLock-spurious-.patch deleted file mode 100644 index 64aee693f6998b6f9dd75f404673a048b9e74a24..0000000000000000000000000000000000000000 --- a/0003-release-branch.go1.17-syscall-fix-ForkLock-spurious-.patch +++ /dev/null @@ -1,79 +0,0 @@ -From e7aab832069d06d77e04a585803dfdb04453253a Mon Sep 17 00:00:00 2001 -From: Russ Cox -Date: Wed, 8 Dec 2021 18:05:11 -0500 -Subject: [PATCH] [release-branch.go1.17] syscall: fix ForkLock spurious - close(0) on pipe failure - -Pipe (and therefore forkLockPipe) does not make any guarantees -about the state of p after a failed Pipe(p). Avoid that assumption -and the too-clever goto, so that we don't accidentally Close a real fd -if the failed pipe leaves p[0] or p[1] set >= 0. - -Updates #50057 -Fixes CVE-2021-44717 - -Change-Id: Iff8e19a6efbba0c73cc8b13ecfae381c87600bb4 -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1291270 -Reviewed-by: Ian Lance Taylor -Reviewed-on: https://go-review.googlesource.com/c/go/+/370534 -Trust: Filippo Valsorda -Run-TryBot: Filippo Valsorda -TryBot-Result: Gopher Robot -Reviewed-by: Alex Rakoczy ---- - src/syscall/exec_unix.go | 20 ++++++-------------- - 1 file changed, 6 insertions(+), 14 deletions(-) - -diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go -index 54b18dccd7..c9c9d1abf3 100644 ---- a/src/syscall/exec_unix.go -+++ b/src/syscall/exec_unix.go -@@ -153,9 +153,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) - sys = &zeroSysProcAttr - } - -- p[0] = -1 -- p[1] = -1 -- - // Convert args to C form. - argv0p, err := BytePtrFromString(argv0) - if err != nil { -@@ -205,14 +202,17 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) - - // Allocate child status pipe close on exec. - if err = forkExecPipe(p[:]); err != nil { -- goto error -+ ForkLock.Unlock() -+ return 0, err - } - - // Kick off child. - pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) - if err1 != 0 { -- err = Errno(err1) -- goto error -+ Close(p[0]) -+ Close(p[1]) -+ ForkLock.Unlock() -+ return 0, Errno(err1) - } - ForkLock.Unlock() - -@@ -244,14 +244,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) - - // Read got EOF, so pipe closed on exec, so exec succeeded. - return pid, nil -- --error: -- if p[0] >= 0 { -- Close(p[0]) -- Close(p[1]) -- } -- ForkLock.Unlock() -- return 0, err - } - - // Combination of fork and exec, careful to be thread safe. --- -2.30.0 - diff --git a/0004-backport-cmd-link-mark-unexported-methods-for-plugins.patch b/0004-backport-cmd-link-mark-unexported-methods-for-plugins.patch deleted file mode 100644 index 6b9dd4b07c525c5e2263c1abb1c7c8fa199f8c92..0000000000000000000000000000000000000000 --- a/0004-backport-cmd-link-mark-unexported-methods-for-plugins.patch +++ /dev/null @@ -1,39 +0,0 @@ -From c872b0594f716a2a0799b07d7226a45f02c005f1 Mon Sep 17 00:00:00 2001 -From: Cherry Mui -Date: Wed, 16 Mar 2022 13:07:57 -0400 -Subject: [PATCH] cmd/link: mark unexported methods for plugins - -When plugin is used, we already mark all exported methods -reachable. However, when the plugin and the host program share -a common package, an unexported method could also be reachable -from both the plugin and the host via interfaces. We need to mark -them as well. - -Fixes #51621. - -Change-Id: I1a70d3f96b66b803f2d0ab14d00ed0df276ea500 -Reviewed-on: https://go-review.googlesource.com/c/go/+/393365 -Trust: Cherry Mui -Run-TryBot: Cherry Mui -TryBot-Result: Gopher Robot -Reviewed-by: Than McIntosh ---- - src/cmd/link/internal/ld/deadcode.go | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go -index e4fa75f..21a9703 100644 ---- a/src/cmd/link/internal/ld/deadcode.go -+++ b/src/cmd/link/internal/ld/deadcode.go -@@ -350,7 +350,7 @@ func deadcode(ctxt *Link) { - // in the last pass. - rem := d.markableMethods[:0] - for _, m := range d.markableMethods { -- if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] { -+ if (d.reflectSeen && (m.isExported() || d.dynlink)) || d.ifaceMethod[m.m] { - d.markMethod(m) - } else { - rem = append(rem, m) --- -1.8.3.1 - diff --git a/0005-release-branch.go1.17-net-http-preserve-nil-values-i.patch b/0005-release-branch.go1.17-net-http-preserve-nil-values-i.patch deleted file mode 100644 index 98972340a918d866c0322d17b1c10068f2f57910..0000000000000000000000000000000000000000 --- a/0005-release-branch.go1.17-net-http-preserve-nil-values-i.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 67bff2eb995a098f838fa4b799c0b8261292e6e7 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Fri, 17 Jun 2022 10:09:45 -0700 -Subject: [PATCH 01/11] [release-branch.go1.17] net/http: preserve nil values - in Header.Clone - -ReverseProxy makes a distinction between nil and zero-length header values. -Avoid losing nil-ness when cloning a request. - -Thanks to Christian Mehlmauer for discovering this. - -For #53423 -For CVE-2022-32148 -Fixes #53620 - -Change-Id: Ice369cdb4712e2d62e25bb881b080847aa4801f5 -Reviewed-on: https://go-review.googlesource.com/c/go/+/412857 -Reviewed-by: Ian Lance Taylor -Reviewed-by: Brad Fitzpatrick -(cherry picked from commit b2cc0fecc2ccd80e6d5d16542cc684f97b3a9c8a) -Reviewed-on: https://go-review.googlesource.com/c/go/+/415221 -Reviewed-by: Heschi Kreinick -TryBot-Result: Gopher Robot -Run-TryBot: Michael Knyszek -Run-TryBot: Heschi Kreinick -Reviewed-by: Michael Knyszek - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/415221 ---- - src/net/http/header.go | 6 ++++++ - src/net/http/header_test.go | 5 +++++ - 2 files changed, 11 insertions(+) - -diff --git a/src/net/http/header.go b/src/net/http/header.go -index 4c72dcb2c88..ef4ee7ffa81 100644 ---- a/src/net/http/header.go -+++ b/src/net/http/header.go -@@ -101,6 +101,12 @@ func (h Header) Clone() Header { - sv := make([]string, nv) // shared backing array for headers' values - h2 := make(Header, len(h)) - for k, vv := range h { -+ if vv == nil { -+ // Preserve nil values. ReverseProxy distinguishes -+ // between nil and zero-length header values. -+ h2[k] = nil -+ continue -+ } - n := copy(sv, vv) - h2[k] = sv[:n:n] - sv = sv[n:] -diff --git a/src/net/http/header_test.go b/src/net/http/header_test.go -index 47893629194..80c003551db 100644 ---- a/src/net/http/header_test.go -+++ b/src/net/http/header_test.go -@@ -235,6 +235,11 @@ func TestCloneOrMakeHeader(t *testing.T) { - in: Header{"foo": {"bar"}}, - want: Header{"foo": {"bar"}}, - }, -+ { -+ name: "nil value", -+ in: Header{"foo": nil}, -+ want: Header{"foo": nil}, -+ }, - } - - for _, tt := range tests { --- -2.30.2 - diff --git a/0006-release-branch.go1.17-go-parser-limit-recursion-dept.patch b/0006-release-branch.go1.17-go-parser-limit-recursion-dept.patch deleted file mode 100644 index 23a903a9e5c421b420127404315fbf9983f6fde8..0000000000000000000000000000000000000000 --- a/0006-release-branch.go1.17-go-parser-limit-recursion-dept.patch +++ /dev/null @@ -1,421 +0,0 @@ -From b78e521644334294019da243a5ff57436f70cd72 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Wed, 15 Jun 2022 10:43:05 -0700 -Subject: [PATCH 02/11] [release-branch.go1.17] go/parser: limit recursion - depth - -Limit nested parsing to 100,000, which prevents stack exhaustion when -parsing deeply nested statements, types, and expressions. Also limit -the scope depth to 1,000 during object resolution. - -Thanks to Juho Nurminen of Mattermost for reporting this issue. - -Fixes #53707 -Updates #53616 -Fixes CVE-2022-1962 - -Change-Id: I4d7b86c1d75d0bf3c7af1fdea91582aa74272c64 -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1491025 -Reviewed-by: Russ Cox -Reviewed-by: Damien Neil -(cherry picked from commit 6a856f08d58e4b6705c0c337d461c540c1235c83) -Reviewed-on: https://go-review.googlesource.com/c/go/+/417070 -Reviewed-by: Heschi Kreinick -TryBot-Result: Gopher Robot -Run-TryBot: Michael Knyszek - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/417070 ---- - src/go/parser/interface.go | 10 ++- - src/go/parser/parser.go | 54 ++++++++++- - src/go/parser/parser_test.go | 169 +++++++++++++++++++++++++++++++++++ - src/go/parser/resolver.go | 9 ++ - 4 files changed, 236 insertions(+), 6 deletions(-) - -diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go -index 85486d2f4b4..eae429e6ef3 100644 ---- a/src/go/parser/interface.go -+++ b/src/go/parser/interface.go -@@ -97,8 +97,11 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) - defer func() { - if e := recover(); e != nil { - // resume same panic if it's not a bailout -- if _, ok := e.(bailout); !ok { -+ bail, ok := e.(bailout) -+ if !ok { - panic(e) -+ } else if bail.msg != "" { -+ p.errors.Add(p.file.Position(bail.pos), bail.msg) - } - } - -@@ -203,8 +206,11 @@ func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode M - defer func() { - if e := recover(); e != nil { - // resume same panic if it's not a bailout -- if _, ok := e.(bailout); !ok { -+ bail, ok := e.(bailout) -+ if !ok { - panic(e) -+ } else if bail.msg != "" { -+ p.errors.Add(p.file.Position(bail.pos), bail.msg) - } - } - p.errors.Sort() -diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go -index f10c8650afd..2c42b9f8cc2 100644 ---- a/src/go/parser/parser.go -+++ b/src/go/parser/parser.go -@@ -60,6 +60,10 @@ type parser struct { - inRhs bool // if set, the parser is parsing a rhs expression - - imports []*ast.ImportSpec // list of imports -+ -+ // nestLev is used to track and limit the recursion depth -+ // during parsing. -+ nestLev int - } - - func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode Mode) { -@@ -110,6 +114,24 @@ func un(p *parser) { - p.printTrace(")") - } - -+// maxNestLev is the deepest we're willing to recurse during parsing -+const maxNestLev int = 1e5 -+ -+func incNestLev(p *parser) *parser { -+ p.nestLev++ -+ if p.nestLev > maxNestLev { -+ p.error(p.pos, "exceeded max nesting depth") -+ panic(bailout{}) -+ } -+ return p -+} -+ -+// decNestLev is used to track nesting depth during parsing to prevent stack exhaustion. -+// It is used along with incNestLev in a similar fashion to how un and trace are used. -+func decNestLev(p *parser) { -+ p.nestLev-- -+} -+ - // Advance to the next token. - func (p *parser) next0() { - // Because of one-token look-ahead, print the previous token -@@ -222,8 +244,12 @@ func (p *parser) next() { - } - } - --// A bailout panic is raised to indicate early termination. --type bailout struct{} -+// A bailout panic is raised to indicate early termination. pos and msg are -+// only populated when bailing out of object resolution. -+type bailout struct { -+ pos token.Pos -+ msg string -+} - - func (p *parser) error(pos token.Pos, msg string) { - if p.trace { -@@ -1119,6 +1145,8 @@ func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr { - } - - func (p *parser) tryIdentOrType() ast.Expr { -+ defer decNestLev(incNestLev(p)) -+ - switch p.tok { - case token.IDENT: - typ := p.parseTypeName(nil) -@@ -1531,7 +1559,13 @@ func (p *parser) parsePrimaryExpr() (x ast.Expr) { - } - - x = p.parseOperand() -- for { -+ // We track the nesting here rather than at the entry for the function, -+ // since it can iteratively produce a nested output, and we want to -+ // limit how deep a structure we generate. -+ var n int -+ defer func() { p.nestLev -= n }() -+ for n = 1; ; n++ { -+ incNestLev(p) - switch p.tok { - case token.PERIOD: - p.next() -@@ -1591,6 +1625,8 @@ func (p *parser) parsePrimaryExpr() (x ast.Expr) { - } - - func (p *parser) parseUnaryExpr() ast.Expr { -+ defer decNestLev(incNestLev(p)) -+ - if p.trace { - defer un(trace(p, "UnaryExpr")) - } -@@ -1673,7 +1709,13 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { - } - - x := p.parseUnaryExpr() -- for { -+ // We track the nesting here rather than at the entry for the function, -+ // since it can iteratively produce a nested output, and we want to -+ // limit how deep a structure we generate. -+ var n int -+ defer func() { p.nestLev -= n }() -+ for n = 1; ; n++ { -+ incNestLev(p) - op, oprec := p.tokPrec() - if oprec < prec1 { - return x -@@ -1962,6 +2004,8 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) { - } - - func (p *parser) parseIfStmt() *ast.IfStmt { -+ defer decNestLev(incNestLev(p)) -+ - if p.trace { - defer un(trace(p, "IfStmt")) - } -@@ -2265,6 +2309,8 @@ func (p *parser) parseForStmt() ast.Stmt { - } - - func (p *parser) parseStmt() (s ast.Stmt) { -+ defer decNestLev(incNestLev(p)) -+ - if p.trace { - defer un(trace(p, "Statement")) - } -diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go -index a4f882d3688..1a46c878663 100644 ---- a/src/go/parser/parser_test.go -+++ b/src/go/parser/parser_test.go -@@ -10,6 +10,7 @@ import ( - "go/ast" - "go/token" - "io/fs" -+ "runtime" - "strings" - "testing" - ) -@@ -577,3 +578,171 @@ type x int // comment - t.Errorf("got %q, want %q", comment, "// comment") - } - } -+ -+var parseDepthTests = []struct { -+ name string -+ format string -+ // multipler is used when a single statement may result in more than one -+ // change in the depth level, for instance "1+(..." produces a BinaryExpr -+ // followed by a UnaryExpr, which increments the depth twice. The test -+ // case comment explains which nodes are triggering the multiple depth -+ // changes. -+ parseMultiplier int -+ // scope is true if we should also test the statement for the resolver scope -+ // depth limit. -+ scope bool -+ // scopeMultiplier does the same as parseMultiplier, but for the scope -+ // depths. -+ scopeMultiplier int -+}{ -+ // The format expands the part inside « » many times. -+ // A second set of brackets nested inside the first stops the repetition, -+ // so that for example «(«1»)» expands to (((...((((1))))...))). -+ {name: "array", format: "package main; var x «[1]»int"}, -+ {name: "slice", format: "package main; var x «[]»int"}, -+ {name: "struct", format: "package main; var x «struct { X «int» }»", scope: true}, -+ {name: "pointer", format: "package main; var x «*»int"}, -+ {name: "func", format: "package main; var x «func()»int", scope: true}, -+ {name: "chan", format: "package main; var x «chan »int"}, -+ {name: "chan2", format: "package main; var x «<-chan »int"}, -+ {name: "interface", format: "package main; var x «interface { M() «int» }»", scope: true, scopeMultiplier: 2}, // Scopes: InterfaceType, FuncType -+ {name: "map", format: "package main; var x «map[int]»int"}, -+ {name: "slicelit", format: "package main; var x = «[]any{«»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit -+ {name: "arraylit", format: "package main; var x = «[1]any{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit -+ {name: "structlit", format: "package main; var x = «struct{x any}{«nil»}»", parseMultiplier: 2}, // Parser nodes: UnaryExpr, CompositeLit -+ {name: "maplit", format: "package main; var x = «map[int]any{1:«nil»}»", parseMultiplier: 2}, // Parser nodes: CompositeLit, KeyValueExpr -+ {name: "dot", format: "package main; var x = «x.»x"}, -+ {name: "index", format: "package main; var x = x«[1]»"}, -+ {name: "slice", format: "package main; var x = x«[1:2]»"}, -+ {name: "slice3", format: "package main; var x = x«[1:2:3]»"}, -+ {name: "dottype", format: "package main; var x = x«.(any)»"}, -+ {name: "callseq", format: "package main; var x = x«()»"}, -+ {name: "methseq", format: "package main; var x = x«.m()»", parseMultiplier: 2}, // Parser nodes: SelectorExpr, CallExpr -+ {name: "binary", format: "package main; var x = «1+»1"}, -+ {name: "binaryparen", format: "package main; var x = «1+(«1»)»", parseMultiplier: 2}, // Parser nodes: BinaryExpr, ParenExpr -+ {name: "unary", format: "package main; var x = «^»1"}, -+ {name: "addr", format: "package main; var x = «& »x"}, -+ {name: "star", format: "package main; var x = «*»x"}, -+ {name: "recv", format: "package main; var x = «<-»x"}, -+ {name: "call", format: "package main; var x = «f(«1»)»", parseMultiplier: 2}, // Parser nodes: Ident, CallExpr -+ {name: "conv", format: "package main; var x = «(*T)(«1»)»", parseMultiplier: 2}, // Parser nodes: ParenExpr, CallExpr -+ {name: "label", format: "package main; func main() { «Label:» }"}, -+ {name: "if", format: "package main; func main() { «if true { «» }»}", parseMultiplier: 2, scope: true, scopeMultiplier: 2}, // Parser nodes: IfStmt, BlockStmt. Scopes: IfStmt, BlockStmt -+ {name: "ifelse", format: "package main; func main() { «if true {} else » {} }", scope: true}, -+ {name: "switch", format: "package main; func main() { «switch { default: «» }»}", scope: true, scopeMultiplier: 2}, // Scopes: TypeSwitchStmt, CaseClause -+ {name: "typeswitch", format: "package main; func main() { «switch x.(type) { default: «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: TypeSwitchStmt, CaseClause -+ {name: "for0", format: "package main; func main() { «for { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt -+ {name: "for1", format: "package main; func main() { «for x { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt -+ {name: "for3", format: "package main; func main() { «for f(); g(); h() { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: ForStmt, BlockStmt -+ {name: "forrange0", format: "package main; func main() { «for range x { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt -+ {name: "forrange1", format: "package main; func main() { «for x = range z { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt -+ {name: "forrange2", format: "package main; func main() { «for x, y = range z { «» }» }", scope: true, scopeMultiplier: 2}, // Scopes: RangeStmt, BlockStmt -+ {name: "go", format: "package main; func main() { «go func() { «» }()» }", parseMultiplier: 2, scope: true}, // Parser nodes: GoStmt, FuncLit -+ {name: "defer", format: "package main; func main() { «defer func() { «» }()» }", parseMultiplier: 2, scope: true}, // Parser nodes: DeferStmt, FuncLit -+ {name: "select", format: "package main; func main() { «select { default: «» }» }", scope: true}, -+} -+ -+// split splits pre«mid»post into pre, mid, post. -+// If the string does not have that form, split returns x, "", "". -+func split(x string) (pre, mid, post string) { -+ start, end := strings.Index(x, "«"), strings.LastIndex(x, "»") -+ if start < 0 || end < 0 { -+ return x, "", "" -+ } -+ return x[:start], x[start+len("«") : end], x[end+len("»"):] -+} -+ -+func TestParseDepthLimit(t *testing.T) { -+ if runtime.GOARCH == "wasm" { -+ t.Skip("causes call stack exhaustion on js/wasm") -+ } -+ for _, tt := range parseDepthTests { -+ for _, size := range []string{"small", "big"} { -+ t.Run(tt.name+"/"+size, func(t *testing.T) { -+ n := maxNestLev + 1 -+ if tt.parseMultiplier > 0 { -+ n /= tt.parseMultiplier -+ } -+ if size == "small" { -+ // Decrease the number of statements by 10, in order to check -+ // that we do not fail when under the limit. 10 is used to -+ // provide some wiggle room for cases where the surrounding -+ // scaffolding syntax adds some noise to the depth that changes -+ // on a per testcase basis. -+ n -= 10 -+ } -+ -+ pre, mid, post := split(tt.format) -+ if strings.Contains(mid, "«") { -+ left, base, right := split(mid) -+ mid = strings.Repeat(left, n) + base + strings.Repeat(right, n) -+ } else { -+ mid = strings.Repeat(mid, n) -+ } -+ input := pre + mid + post -+ -+ fset := token.NewFileSet() -+ _, err := ParseFile(fset, "", input, ParseComments|SkipObjectResolution) -+ if size == "small" { -+ if err != nil { -+ t.Errorf("ParseFile(...): %v (want success)", err) -+ } -+ } else { -+ expected := "exceeded max nesting depth" -+ if err == nil || !strings.HasSuffix(err.Error(), expected) { -+ t.Errorf("ParseFile(...) = _, %v, want %q", err, expected) -+ } -+ } -+ }) -+ } -+ } -+} -+ -+func TestScopeDepthLimit(t *testing.T) { -+ if runtime.GOARCH == "wasm" { -+ t.Skip("causes call stack exhaustion on js/wasm") -+ } -+ for _, tt := range parseDepthTests { -+ if !tt.scope { -+ continue -+ } -+ for _, size := range []string{"small", "big"} { -+ t.Run(tt.name+"/"+size, func(t *testing.T) { -+ n := maxScopeDepth + 1 -+ if tt.scopeMultiplier > 0 { -+ n /= tt.scopeMultiplier -+ } -+ if size == "small" { -+ // Decrease the number of statements by 10, in order to check -+ // that we do not fail when under the limit. 10 is used to -+ // provide some wiggle room for cases where the surrounding -+ // scaffolding syntax adds some noise to the depth that changes -+ // on a per testcase basis. -+ n -= 10 -+ } -+ -+ pre, mid, post := split(tt.format) -+ if strings.Contains(mid, "«") { -+ left, base, right := split(mid) -+ mid = strings.Repeat(left, n) + base + strings.Repeat(right, n) -+ } else { -+ mid = strings.Repeat(mid, n) -+ } -+ input := pre + mid + post -+ -+ fset := token.NewFileSet() -+ _, err := ParseFile(fset, "", input, DeclarationErrors) -+ if size == "small" { -+ if err != nil { -+ t.Errorf("ParseFile(...): %v (want success)", err) -+ } -+ } else { -+ expected := "exceeded max scope depth during object resolution" -+ if err == nil || !strings.HasSuffix(err.Error(), expected) { -+ t.Errorf("ParseFile(...) = _, %v, want %q", err, expected) -+ } -+ } -+ }) -+ } -+ } -+} -diff --git a/src/go/parser/resolver.go b/src/go/parser/resolver.go -index cf92c7e4f57..f55bdb7f177 100644 ---- a/src/go/parser/resolver.go -+++ b/src/go/parser/resolver.go -@@ -25,6 +25,7 @@ func resolveFile(file *ast.File, handle *token.File, declErr func(token.Pos, str - declErr: declErr, - topScope: pkgScope, - pkgScope: pkgScope, -+ depth: 1, - } - - for _, decl := range file.Decls { -@@ -53,6 +54,8 @@ func resolveFile(file *ast.File, handle *token.File, declErr func(token.Pos, str - file.Unresolved = r.unresolved[0:i] - } - -+const maxScopeDepth int = 1e3 -+ - type resolver struct { - handle *token.File - declErr func(token.Pos, string) -@@ -61,6 +64,7 @@ type resolver struct { - pkgScope *ast.Scope // pkgScope.Outer == nil - topScope *ast.Scope // top-most scope; may be pkgScope - unresolved []*ast.Ident // unresolved identifiers -+ depth int // scope depth - - // Label scopes - // (maintained by open/close LabelScope) -@@ -83,6 +87,10 @@ func (r *resolver) sprintf(format string, args ...interface{}) string { - } - - func (r *resolver) openScope(pos token.Pos) { -+ r.depth++ -+ if r.depth > maxScopeDepth { -+ panic(bailout{pos: pos, msg: "exceeded max scope depth during object resolution"}) -+ } - if debugResolve { - r.dump("opening scope @%v", pos) - } -@@ -90,6 +98,7 @@ func (r *resolver) openScope(pos token.Pos) { - } - - func (r *resolver) closeScope() { -+ r.depth-- - if debugResolve { - r.dump("closing scope") - } --- -2.30.2 - diff --git a/0007-release-branch.go1.17-net-http-don-t-strip-whitespac.patch b/0007-release-branch.go1.17-net-http-don-t-strip-whitespac.patch deleted file mode 100644 index 7fdcd6f86e68031ece6523d3aed9973202e91630..0000000000000000000000000000000000000000 --- a/0007-release-branch.go1.17-net-http-don-t-strip-whitespac.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 4ad62aecaf57ca3adc11a04bd2113bdbee6249c3 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Wed, 1 Jun 2022 11:17:07 -0700 -Subject: [PATCH 03/11] [release-branch.go1.17] net/http: don't strip - whitespace from Transfer-Encoding headers - -Do not accept "Transfer-Encoding: \rchunked" as a valid TE header -setting chunked encoding. - -Thanks to Zeyu Zhang (https://www.zeyu2001.com/) for identifying -the issue. - -For #53188 -For CVE-2022-1705 -Fixes #53432 - -Change-Id: I1a16631425159267f2eca68056b057192a7edf6c -Reviewed-on: https://go-review.googlesource.com/c/go/+/409874 -Reviewed-by: Roland Shoemaker -Reviewed-by: Brad Fitzpatrick -(cherry picked from commit e5017a93fcde94f09836200bca55324af037ee5f) -Reviewed-on: https://go-review.googlesource.com/c/go/+/415217 -Reviewed-by: Dmitri Shuralyov -Run-TryBot: Dmitri Shuralyov -Reviewed-by: Dmitri Shuralyov -TryBot-Result: Gopher Robot - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/415217 ---- - src/net/http/serve_test.go | 1 + - src/net/http/transfer.go | 2 +- - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go -index 6394da3bb7c..bfac783e3a9 100644 ---- a/src/net/http/serve_test.go -+++ b/src/net/http/serve_test.go -@@ -6189,6 +6189,7 @@ func TestUnsupportedTransferEncodingsReturn501(t *testing.T) { - "fugazi", - "foo-bar", - "unknown", -+ "\rchunked", - } - - for _, badTE := range unsupportedTEs { -diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go -index 85c2e5a360d..3894007d306 100644 ---- a/src/net/http/transfer.go -+++ b/src/net/http/transfer.go -@@ -639,7 +639,7 @@ func (t *transferReader) parseTransferEncoding() error { - if len(raw) != 1 { - return &unsupportedTEError{fmt.Sprintf("too many transfer encodings: %q", raw)} - } -- if !ascii.EqualFold(textproto.TrimString(raw[0]), "chunked") { -+ if !ascii.EqualFold(raw[0], "chunked") { - return &unsupportedTEError{fmt.Sprintf("unsupported transfer encoding: %q", raw[0])} - } - --- -2.30.2 - diff --git a/0008-release-branch.go1.17-encoding-xml-limit-depth-of-ne.patch b/0008-release-branch.go1.17-encoding-xml-limit-depth-of-ne.patch deleted file mode 100644 index 077af1523521e89770af7211afd05a3cf1422ca7..0000000000000000000000000000000000000000 --- a/0008-release-branch.go1.17-encoding-xml-limit-depth-of-ne.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 106c859f68c3137cfa05c433a9b90494db386fda Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Tue, 29 Mar 2022 15:52:09 -0700 -Subject: [PATCH 04/11] [release-branch.go1.17] encoding/xml: limit depth of - nesting in unmarshal - -Prevent exhausting the stack limit when unmarshalling extremely deeply -nested structures into nested types. - -Fixes #53715 -Updates #53611 -Fixes CVE-2022-30633 - -Change-Id: Ic6c5d41674c93cfc9a316135a408db9156d39c59 -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1421319 -Reviewed-by: Damien Neil -Reviewed-by: Julie Qiu -(cherry picked from commit ebee00a55e28931b2cad0e76207a73712b000432) -Reviewed-on: https://go-review.googlesource.com/c/go/+/417069 -Reviewed-by: Heschi Kreinick -Run-TryBot: Michael Knyszek -TryBot-Result: Gopher Robot - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/417069 ---- - src/encoding/xml/read.go | 27 +++++++++++++++++++-------- - src/encoding/xml/read_test.go | 32 ++++++++++++++++++++++++++++++++ - 2 files changed, 51 insertions(+), 8 deletions(-) - -diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go -index ef5df3f7f6a..e0ed8b527ce 100644 ---- a/src/encoding/xml/read.go -+++ b/src/encoding/xml/read.go -@@ -148,7 +148,7 @@ func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error { - if val.Kind() != reflect.Ptr { - return errors.New("non-pointer passed to Unmarshal") - } -- return d.unmarshal(val.Elem(), start) -+ return d.unmarshal(val.Elem(), start, 0) - } - - // An UnmarshalError represents an error in the unmarshaling process. -@@ -304,8 +304,15 @@ var ( - textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() - ) - -+const maxUnmarshalDepth = 10000 -+ -+var errExeceededMaxUnmarshalDepth = errors.New("exceeded max depth") -+ - // Unmarshal a single XML element into val. --func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { -+func (d *Decoder) unmarshal(val reflect.Value, start *StartElement, depth int) error { -+ if depth >= maxUnmarshalDepth { -+ return errExeceededMaxUnmarshalDepth -+ } - // Find start element if we need it. - if start == nil { - for { -@@ -398,7 +405,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error { - v.Set(reflect.Append(val, reflect.Zero(v.Type().Elem()))) - - // Recur to read element into slice. -- if err := d.unmarshal(v.Index(n), start); err != nil { -+ if err := d.unmarshal(v.Index(n), start, depth+1); err != nil { - v.SetLen(n) - return err - } -@@ -521,13 +528,15 @@ Loop: - case StartElement: - consumed := false - if sv.IsValid() { -- consumed, err = d.unmarshalPath(tinfo, sv, nil, &t) -+ // unmarshalPath can call unmarshal, so we need to pass the depth through so that -+ // we can continue to enforce the maximum recusion limit. -+ consumed, err = d.unmarshalPath(tinfo, sv, nil, &t, depth) - if err != nil { - return err - } - if !consumed && saveAny.IsValid() { - consumed = true -- if err := d.unmarshal(saveAny, &t); err != nil { -+ if err := d.unmarshal(saveAny, &t, depth+1); err != nil { - return err - } - } -@@ -672,7 +681,7 @@ func copyValue(dst reflect.Value, src []byte) (err error) { - // The consumed result tells whether XML elements have been consumed - // from the Decoder until start's matching end element, or if it's - // still untouched because start is uninteresting for sv's fields. --func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { -+func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement, depth int) (consumed bool, err error) { - recurse := false - Loop: - for i := range tinfo.fields { -@@ -687,7 +696,7 @@ Loop: - } - if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local { - // It's a perfect match, unmarshal the field. -- return true, d.unmarshal(finfo.value(sv, initNilPointers), start) -+ return true, d.unmarshal(finfo.value(sv, initNilPointers), start, depth+1) - } - if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local { - // It's a prefix for the field. Break and recurse -@@ -716,7 +725,9 @@ Loop: - } - switch t := tok.(type) { - case StartElement: -- consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t) -+ // the recursion depth of unmarshalPath is limited to the path length specified -+ // by the struct field tag, so we don't increment the depth here. -+ consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t, depth) - if err != nil { - return true, err - } -diff --git a/src/encoding/xml/read_test.go b/src/encoding/xml/read_test.go -index 8c2e70fa22e..8c940aefb81 100644 ---- a/src/encoding/xml/read_test.go -+++ b/src/encoding/xml/read_test.go -@@ -5,8 +5,11 @@ - package xml - - import ( -+ "bytes" -+ "errors" - "io" - "reflect" -+ "runtime" - "strings" - "testing" - "time" -@@ -1079,3 +1082,32 @@ func TestUnmarshalWhitespaceAttrs(t *testing.T) { - t.Fatalf("whitespace attrs: Unmarshal:\nhave: %#+v\nwant: %#+v", v, want) - } - } -+ -+func TestCVE202230633(t *testing.T) { -+ if runtime.GOARCH == "wasm" { -+ t.Skip("causes memory exhaustion on js/wasm") -+ } -+ defer func() { -+ p := recover() -+ if p != nil { -+ t.Fatal("Unmarshal panicked") -+ } -+ }() -+ var example struct { -+ Things []string -+ } -+ Unmarshal(bytes.Repeat([]byte(""), 17_000_000), &example) -+} -+ -+func TestCVE202228131(t *testing.T) { -+ type nested struct { -+ Parent *nested `xml:",any"` -+ } -+ var n nested -+ err := Unmarshal(bytes.Repeat([]byte(""), maxUnmarshalDepth+1), &n) -+ if err == nil { -+ t.Fatal("Unmarshal did not fail") -+ } else if !errors.Is(err, errExeceededMaxUnmarshalDepth) { -+ t.Fatalf("Unmarshal unexpected error: got %q, want %q", err, errExeceededMaxUnmarshalDepth) -+ } -+} --- -2.30.2 - diff --git a/0009-release-branch.go1.17-encoding-gob-add-a-depth-limit.patch b/0009-release-branch.go1.17-encoding-gob-add-a-depth-limit.patch deleted file mode 100644 index 13f56a5ce339c494603c9e8c1a7c47bcf8a318f4..0000000000000000000000000000000000000000 --- a/0009-release-branch.go1.17-encoding-gob-add-a-depth-limit.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 8747af9a1098e8fa497441be4c4a79a23de31a98 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Tue, 7 Jun 2022 13:00:43 -0700 -Subject: [PATCH 05/11] [release-branch.go1.17] encoding/gob: add a depth limit - for ignored fields - -Enforce a nesting limit of 10,000 for ignored fields during decoding -of messages. This prevents the possibility of triggering stack -exhaustion. - -Fixes #53709 -Updates #53615 -Fixes CVE-2022-30635 - -Change-Id: I05103d06dd5ca3945fcba3c1f5d3b5a645e8fb0f -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1484771 -Reviewed-by: Damien Neil -Reviewed-by: Tatiana Bradley -(cherry picked from commit 55e8f938d22bfec29cc9dc9671044c5a41d1ea9c) -Reviewed-on: https://go-review.googlesource.com/c/go/+/417074 -Run-TryBot: Heschi Kreinick -TryBot-Result: Gopher Robot -Reviewed-by: Heschi Kreinick - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/417074 ---- - src/encoding/gob/decode.go | 19 ++++++++++++------- - src/encoding/gob/gobencdec_test.go | 24 ++++++++++++++++++++++++ - 2 files changed, 36 insertions(+), 7 deletions(-) - -diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go -index d2f6c749b1b..0e0ec75cccc 100644 ---- a/src/encoding/gob/decode.go -+++ b/src/encoding/gob/decode.go -@@ -871,8 +871,13 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg - return &op - } - -+var maxIgnoreNestingDepth = 10000 -+ - // decIgnoreOpFor returns the decoding op for a field that has no destination. --func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp { -+func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp, depth int) *decOp { -+ if depth > maxIgnoreNestingDepth { -+ error_(errors.New("invalid nesting depth")) -+ } - // If this type is already in progress, it's a recursive type (e.g. map[string]*T). - // Return the pointer to the op we're already building. - if opPtr := inProgress[wireId]; opPtr != nil { -@@ -896,7 +901,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) - errorf("bad data: undefined type %s", wireId.string()) - case wire.ArrayT != nil: - elemId := wire.ArrayT.Elem -- elemOp := dec.decIgnoreOpFor(elemId, inProgress) -+ elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) - op = func(i *decInstr, state *decoderState, value reflect.Value) { - state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len) - } -@@ -904,15 +909,15 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) - case wire.MapT != nil: - keyId := dec.wireType[wireId].MapT.Key - elemId := dec.wireType[wireId].MapT.Elem -- keyOp := dec.decIgnoreOpFor(keyId, inProgress) -- elemOp := dec.decIgnoreOpFor(elemId, inProgress) -+ keyOp := dec.decIgnoreOpFor(keyId, inProgress, depth+1) -+ elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) - op = func(i *decInstr, state *decoderState, value reflect.Value) { - state.dec.ignoreMap(state, *keyOp, *elemOp) - } - - case wire.SliceT != nil: - elemId := wire.SliceT.Elem -- elemOp := dec.decIgnoreOpFor(elemId, inProgress) -+ elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) - op = func(i *decInstr, state *decoderState, value reflect.Value) { - state.dec.ignoreSlice(state, *elemOp) - } -@@ -1073,7 +1078,7 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de - func (dec *Decoder) compileIgnoreSingle(remoteId typeId) *decEngine { - engine := new(decEngine) - engine.instr = make([]decInstr, 1) // one item -- op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp)) -+ op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp), 0) - ovfl := overflow(dec.typeString(remoteId)) - engine.instr[0] = decInstr{*op, 0, nil, ovfl} - engine.numInstr = 1 -@@ -1118,7 +1123,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn - localField, present := srt.FieldByName(wireField.Name) - // TODO(r): anonymous names - if !present || !isExported(wireField.Name) { -- op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp)) -+ op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp), 0) - engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl} - continue - } -diff --git a/src/encoding/gob/gobencdec_test.go b/src/encoding/gob/gobencdec_test.go -index 6d2c8db42d0..1b52ecc6c84 100644 ---- a/src/encoding/gob/gobencdec_test.go -+++ b/src/encoding/gob/gobencdec_test.go -@@ -12,6 +12,7 @@ import ( - "fmt" - "io" - "net" -+ "reflect" - "strings" - "testing" - "time" -@@ -796,3 +797,26 @@ func TestNetIP(t *testing.T) { - t.Errorf("decoded to %v, want 1.2.3.4", ip.String()) - } - } -+ -+func TestIngoreDepthLimit(t *testing.T) { -+ // We don't test the actual depth limit because it requires building an -+ // extremely large message, which takes quite a while. -+ oldNestingDepth := maxIgnoreNestingDepth -+ maxIgnoreNestingDepth = 100 -+ defer func() { maxIgnoreNestingDepth = oldNestingDepth }() -+ b := new(bytes.Buffer) -+ enc := NewEncoder(b) -+ typ := reflect.TypeOf(int(0)) -+ nested := reflect.ArrayOf(1, typ) -+ for i := 0; i < 100; i++ { -+ nested = reflect.ArrayOf(1, nested) -+ } -+ badStruct := reflect.New(reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}})) -+ enc.Encode(badStruct.Interface()) -+ dec := NewDecoder(b) -+ var output struct{ Hello int } -+ expectedErr := "invalid nesting depth" -+ if err := dec.Decode(&output); err == nil || err.Error() != expectedErr { -+ t.Errorf("Decode didn't fail with depth limit of 100: want %q, got %q", expectedErr, err) -+ } -+} --- -2.30.2 - diff --git a/0010-release-branch.go1.17-io-fs-fix-stack-exhaustion-in-.patch b/0010-release-branch.go1.17-io-fs-fix-stack-exhaustion-in-.patch deleted file mode 100644 index c1943787ed4deeb3a6687cd4fd560c68b9dbac4c..0000000000000000000000000000000000000000 --- a/0010-release-branch.go1.17-io-fs-fix-stack-exhaustion-in-.patch +++ /dev/null @@ -1,96 +0,0 @@ -From a8d44d0477f2182563e279da115cbc164d639f33 Mon Sep 17 00:00:00 2001 -From: Julie Qiu -Date: Thu, 23 Jun 2022 23:17:53 +0000 -Subject: [PATCH 06/11] [release-branch.go1.17] io/fs: fix stack exhaustion in - Glob - -A limit is added to the number of path separators allowed by an input to -Glob, to prevent stack exhaustion issues. - -Thanks to Juho Nurminen of Mattermost who reported a similar issue in -path/filepath. - -Fixes #53719 -Updates #53415 -Fixes CVE-2022-30630 - -Change-Id: I5a9d02591fed90cd3d52627f5945f1301e53465d -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1497588 -Reviewed-by: Roland Shoemaker -(cherry picked from commit fdccc5d7bd0f276d0a8de3a818ca844f0bed5d97) -Reviewed-on: https://go-review.googlesource.com/c/go/+/417072 -Reviewed-by: Heschi Kreinick -TryBot-Result: Gopher Robot -Run-TryBot: Michael Knyszek - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/417072 ---- - src/io/fs/glob.go | 14 ++++++++++++-- - src/io/fs/glob_test.go | 10 ++++++++++ - 2 files changed, 22 insertions(+), 2 deletions(-) - -diff --git a/src/io/fs/glob.go b/src/io/fs/glob.go -index 45d9cb61b96..0e529cd05d1 100644 ---- a/src/io/fs/glob.go -+++ b/src/io/fs/glob.go -@@ -31,6 +31,16 @@ type GlobFS interface { - // Otherwise, Glob uses ReadDir to traverse the directory tree - // and look for matches for the pattern. - func Glob(fsys FS, pattern string) (matches []string, err error) { -+ return globWithLimit(fsys, pattern, 0) -+} -+ -+func globWithLimit(fsys FS, pattern string, depth int) (matches []string, err error) { -+ // This limit is added to prevent stack exhaustion issues. See -+ // CVE-2022-30630. -+ const pathSeparatorsLimit = 10000 -+ if depth > pathSeparatorsLimit { -+ return nil, path.ErrBadPattern -+ } - if fsys, ok := fsys.(GlobFS); ok { - return fsys.Glob(pattern) - } -@@ -59,9 +69,9 @@ func Glob(fsys FS, pattern string) (matches []string, err error) { - } - - var m []string -- m, err = Glob(fsys, dir) -+ m, err = globWithLimit(fsys, dir, depth+1) - if err != nil { -- return -+ return nil, err - } - for _, d := range m { - matches, err = glob(fsys, d, file, matches) -diff --git a/src/io/fs/glob_test.go b/src/io/fs/glob_test.go -index f19bebed77f..d052eab3713 100644 ---- a/src/io/fs/glob_test.go -+++ b/src/io/fs/glob_test.go -@@ -8,6 +8,7 @@ import ( - . "io/fs" - "os" - "path" -+ "strings" - "testing" - ) - -@@ -55,6 +56,15 @@ func TestGlobError(t *testing.T) { - } - } - -+func TestCVE202230630(t *testing.T) { -+ // Prior to CVE-2022-30630, a stack exhaustion would occur given a large -+ // number of separators. There is now a limit of 10,000. -+ _, err := Glob(os.DirFS("."), "/*"+strings.Repeat("/", 10001)) -+ if err != path.ErrBadPattern { -+ t.Fatalf("Glob returned err=%v, want %v", err, path.ErrBadPattern) -+ } -+} -+ - // contains reports whether vector contains the string s. - func contains(vector []string, s string) bool { - for _, elem := range vector { --- -2.30.2 - diff --git a/0011-release-branch.go1.17-path-filepath-fix-stack-exhaus.patch b/0011-release-branch.go1.17-path-filepath-fix-stack-exhaus.patch deleted file mode 100644 index 661634ac3dabe484b61c160c12218f3fb5a04700..0000000000000000000000000000000000000000 --- a/0011-release-branch.go1.17-path-filepath-fix-stack-exhaus.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 7b98bf3a8711126c532033ca89647f3b743b58ec Mon Sep 17 00:00:00 2001 -From: Julie Qiu -Date: Thu, 23 Jun 2022 23:18:56 +0000 -Subject: [PATCH 07/11] [release-branch.go1.17] path/filepath: fix stack - exhaustion in Glob - -A limit is added to the number of path separators allowed by an input to -Glob, to prevent stack exhaustion issues. - -Thanks to Juho Nurminen of Mattermost who reported the issue. - -Fixes #53713 -Updates #53416 -Fixes CVE-2022-30632 - -Change-Id: I1b9fd4faa85411a05dbc91dceae1c0c8eb021f07 -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1498176 -Reviewed-by: Roland Shoemaker -(cherry picked from commit d182a6d1217fd0d04c9babfa9a7ccd3515435c39) -Reviewed-on: https://go-review.googlesource.com/c/go/+/417073 -Reviewed-by: Heschi Kreinick -TryBot-Result: Gopher Robot -Run-TryBot: Michael Knyszek - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/417073 ---- - src/path/filepath/match.go | 12 +++++++++++- - src/path/filepath/match_test.go | 10 ++++++++++ - 2 files changed, 21 insertions(+), 1 deletion(-) - -diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go -index c77a26952a6..55ed1d75ae1 100644 ---- a/src/path/filepath/match.go -+++ b/src/path/filepath/match.go -@@ -241,6 +241,16 @@ func getEsc(chunk string) (r rune, nchunk string, err error) { - // The only possible returned error is ErrBadPattern, when pattern - // is malformed. - func Glob(pattern string) (matches []string, err error) { -+ return globWithLimit(pattern, 0) -+} -+ -+func globWithLimit(pattern string, depth int) (matches []string, err error) { -+ // This limit is used prevent stack exhaustion issues. See CVE-2022-30632. -+ const pathSeparatorsLimit = 10000 -+ if depth == pathSeparatorsLimit { -+ return nil, ErrBadPattern -+ } -+ - // Check pattern is well-formed. - if _, err := Match(pattern, ""); err != nil { - return nil, err -@@ -270,7 +280,7 @@ func Glob(pattern string) (matches []string, err error) { - } - - var m []string -- m, err = Glob(dir) -+ m, err = globWithLimit(dir, depth+1) - if err != nil { - return - } -diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go -index 375c41a7e9d..d6282596fed 100644 ---- a/src/path/filepath/match_test.go -+++ b/src/path/filepath/match_test.go -@@ -155,6 +155,16 @@ func TestGlob(t *testing.T) { - } - } - -+func TestCVE202230632(t *testing.T) { -+ // Prior to CVE-2022-30632, this would cause a stack exhaustion given a -+ // large number of separators (more than 4,000,000). There is now a limit -+ // of 10,000. -+ _, err := Glob("/*" + strings.Repeat("/", 10001)) -+ if err != ErrBadPattern { -+ t.Fatalf("Glob returned err=%v, want ErrBadPattern", err) -+ } -+} -+ - func TestGlobError(t *testing.T) { - bad := []string{`[]`, `nonexist/[]`} - for _, pattern := range bad { --- -2.30.2 - diff --git a/0012-release-branch.go1.17-encoding-xml-use-iterative-Ski.patch b/0012-release-branch.go1.17-encoding-xml-use-iterative-Ski.patch deleted file mode 100644 index 9be1eea8260baee823f1d033a0493f36a0efb8e1..0000000000000000000000000000000000000000 --- a/0012-release-branch.go1.17-encoding-xml-use-iterative-Ski.patch +++ /dev/null @@ -1,69 +0,0 @@ -From cedbe8f7a1f0d174636e70de68d85499d8025000 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Mon, 28 Mar 2022 18:41:26 -0700 -Subject: [PATCH 08/11] [release-branch.go1.17] encoding/xml: use iterative - Skip, rather than recursive - -Prevents exhausting the stack limit in _incredibly_ deeply nested -structures. - -Fixes #53711 -Updates #53614 -Fixes CVE-2022-28131 - -Change-Id: I47db4595ce10cecc29fbd06afce7b299868599e6 -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1419912 -Reviewed-by: Julie Qiu -Reviewed-by: Damien Neil -(cherry picked from commit 9278cb78443d2b4deb24cbb5b61c9ba5ac688d49) -Reviewed-on: https://go-review.googlesource.com/c/go/+/417068 -TryBot-Result: Gopher Robot -Reviewed-by: Heschi Kreinick -Run-TryBot: Michael Knyszek - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/417068 ---- - src/encoding/xml/read.go | 15 ++++++++------- - 1 file changed, 8 insertions(+), 7 deletions(-) - -diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go -index e0ed8b527ce..c77579880cb 100644 ---- a/src/encoding/xml/read.go -+++ b/src/encoding/xml/read.go -@@ -743,12 +743,12 @@ Loop: - } - - // Skip reads tokens until it has consumed the end element --// matching the most recent start element already consumed. --// It recurs if it encounters a start element, so it can be used to --// skip nested structures. -+// matching the most recent start element already consumed, -+// skipping nested structures. - // It returns nil if it finds an end element matching the start - // element; otherwise it returns an error describing the problem. - func (d *Decoder) Skip() error { -+ var depth int64 - for { - tok, err := d.Token() - if err != nil { -@@ -756,11 +756,12 @@ func (d *Decoder) Skip() error { - } - switch tok.(type) { - case StartElement: -- if err := d.Skip(); err != nil { -- return err -- } -+ depth++ - case EndElement: -- return nil -+ if depth == 0 { -+ return nil -+ } -+ depth-- - } - } - } --- -2.30.2 - diff --git a/0013-release-branch.go1.17-compress-gzip-fix-stack-exhaus.patch b/0013-release-branch.go1.17-compress-gzip-fix-stack-exhaus.patch deleted file mode 100644 index 7a54a71ea1789a38b6e07405b4c2d47766b75f08..0000000000000000000000000000000000000000 --- a/0013-release-branch.go1.17-compress-gzip-fix-stack-exhaus.patch +++ /dev/null @@ -1,133 +0,0 @@ -From 8a445abc7f7e2ed41112f176a169b97859c8d425 Mon Sep 17 00:00:00 2001 -From: Tatiana Bradley -Date: Fri, 6 May 2022 11:25:06 -0400 -Subject: [PATCH 09/11] [release-branch.go1.17] compress/gzip: fix stack - exhaustion bug in Reader.Read - -Replace recursion with iteration in Reader.Read to avoid stack -exhaustion when there are a large number of files. - -Fixes CVE-2022-30631 -Fixes #53717 -Updates #53168 - -Change-Id: I47d8afe3f2d40b0213ab61431df9b221794dbfe0 -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1455673 -Reviewed-by: Roland Shoemaker -Reviewed-by: Julie Qiu -(cherry picked from commit cf498969c8a0bae9d7a24b98fc1f66c824a4775d) -Reviewed-on: https://go-review.googlesource.com/c/go/+/417071 -Reviewed-by: Heschi Kreinick -Run-TryBot: Michael Knyszek -TryBot-Result: Gopher Robot - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/417071 ---- - src/compress/gzip/gunzip.go | 60 +++++++++++++++----------------- - src/compress/gzip/gunzip_test.go | 16 +++++++++ - 2 files changed, 45 insertions(+), 31 deletions(-) - -diff --git a/src/compress/gzip/gunzip.go b/src/compress/gzip/gunzip.go -index 924bce10b7c..237b2b928bf 100644 ---- a/src/compress/gzip/gunzip.go -+++ b/src/compress/gzip/gunzip.go -@@ -248,42 +248,40 @@ func (z *Reader) Read(p []byte) (n int, err error) { - return 0, z.err - } - -- n, z.err = z.decompressor.Read(p) -- z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n]) -- z.size += uint32(n) -- if z.err != io.EOF { -- // In the normal case we return here. -- return n, z.err -- } -+ for n == 0 { -+ n, z.err = z.decompressor.Read(p) -+ z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n]) -+ z.size += uint32(n) -+ if z.err != io.EOF { -+ // In the normal case we return here. -+ return n, z.err -+ } - -- // Finished file; check checksum and size. -- if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil { -- z.err = noEOF(err) -- return n, z.err -- } -- digest := le.Uint32(z.buf[:4]) -- size := le.Uint32(z.buf[4:8]) -- if digest != z.digest || size != z.size { -- z.err = ErrChecksum -- return n, z.err -- } -- z.digest, z.size = 0, 0 -+ // Finished file; check checksum and size. -+ if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil { -+ z.err = noEOF(err) -+ return n, z.err -+ } -+ digest := le.Uint32(z.buf[:4]) -+ size := le.Uint32(z.buf[4:8]) -+ if digest != z.digest || size != z.size { -+ z.err = ErrChecksum -+ return n, z.err -+ } -+ z.digest, z.size = 0, 0 - -- // File is ok; check if there is another. -- if !z.multistream { -- return n, io.EOF -- } -- z.err = nil // Remove io.EOF -+ // File is ok; check if there is another. -+ if !z.multistream { -+ return n, io.EOF -+ } -+ z.err = nil // Remove io.EOF - -- if _, z.err = z.readHeader(); z.err != nil { -- return n, z.err -+ if _, z.err = z.readHeader(); z.err != nil { -+ return n, z.err -+ } - } - -- // Read from next file, if necessary. -- if n > 0 { -- return n, nil -- } -- return z.Read(p) -+ return n, nil - } - - // Close closes the Reader. It does not close the underlying io.Reader. -diff --git a/src/compress/gzip/gunzip_test.go b/src/compress/gzip/gunzip_test.go -index 17c23e8a9be..6fe8ddcf558 100644 ---- a/src/compress/gzip/gunzip_test.go -+++ b/src/compress/gzip/gunzip_test.go -@@ -515,3 +515,19 @@ func TestTruncatedStreams(t *testing.T) { - } - } - } -+ -+func TestCVE202230631(t *testing.T) { -+ var empty = []byte{0x1f, 0x8b, 0x08, 0x00, 0xa7, 0x8f, 0x43, 0x62, 0x00, -+ 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -+ r := bytes.NewReader(bytes.Repeat(empty, 4e6)) -+ z, err := NewReader(r) -+ if err != nil { -+ t.Fatalf("NewReader: got %v, want nil", err) -+ } -+ // Prior to CVE-2022-30631 fix, this would cause an unrecoverable panic due -+ // to stack exhaustion. -+ _, err = z.Read(make([]byte, 10)) -+ if err != io.EOF { -+ t.Errorf("Reader.Read: got %v, want %v", err, io.EOF) -+ } -+} --- -2.30.2 - diff --git a/0014-release-branch.go1.17-crypto-tls-randomly-generate-t.patch b/0014-release-branch.go1.17-crypto-tls-randomly-generate-t.patch deleted file mode 100644 index f8f418a62b7f0a81fcd8bd8ae61ed498bf433228..0000000000000000000000000000000000000000 --- a/0014-release-branch.go1.17-crypto-tls-randomly-generate-t.patch +++ /dev/null @@ -1,69 +0,0 @@ -From b2815a72bef3f829c5ac7735feddb034f5501cc0 Mon Sep 17 00:00:00 2001 -From: Tatiana Bradley -Date: Thu, 12 May 2022 14:58:29 -0400 -Subject: [PATCH 10/11] [release-branch.go1.17] crypto/tls: randomly generate - ticket_age_add - -As required by RFC 8446, section 4.6.1, ticket_age_add now holds a -random 32-bit value. Before this change, this value was always set -to 0. - -This change also documents the reasoning for always setting -ticket_nonce to 0. The value ticket_nonce must be unique per -connection, but we only ever send one ticket per connection. - -Updates #52814 -Fixes #52832 -Fixes CVE-2022-30629 - -Change-Id: I6c2fc6ca0376b7b968abd59d6d3d3854c1ab68bb -Reviewed-on: https://go-review.googlesource.com/c/go/+/405994 -Reviewed-by: Tatiana Bradley -Reviewed-by: Roland Shoemaker -Run-TryBot: Tatiana Bradley -TryBot-Result: Gopher Robot -(cherry picked from commit fe4de36198794c447fbd9d7cc2d7199a506c76a5) -Reviewed-on: https://go-review.googlesource.com/c/go/+/408574 -Run-TryBot: Roland Shoemaker - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/408574 ---- - src/crypto/tls/handshake_server_tls13.go | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go -index 08251b84def..6aa52698a3a 100644 ---- a/src/crypto/tls/handshake_server_tls13.go -+++ b/src/crypto/tls/handshake_server_tls13.go -@@ -10,6 +10,7 @@ import ( - "crypto" - "crypto/hmac" - "crypto/rsa" -+ "encoding/binary" - "errors" - "hash" - "io" -@@ -741,6 +742,19 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { - } - m.lifetime = uint32(maxSessionTicketLifetime / time.Second) - -+ // ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1 -+ // The value is not stored anywhere; we never need to check the ticket age -+ // because 0-RTT is not supported. -+ ageAdd := make([]byte, 4) -+ _, err = hs.c.config.rand().Read(ageAdd) -+ if err != nil { -+ return err -+ } -+ m.ageAdd = binary.LittleEndian.Uint32(ageAdd) -+ -+ // ticket_nonce, which must be unique per connection, is always left at -+ // zero because we only ever send one ticket per connection. -+ - if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil { - return err - } --- -2.30.2 - diff --git a/0015-release-branch.go1.17-crypto-rand-properly-handle-la.patch b/0015-release-branch.go1.17-crypto-rand-properly-handle-la.patch deleted file mode 100644 index 092814022de625d9ed3205ff3821ec33ae0f0350..0000000000000000000000000000000000000000 --- a/0015-release-branch.go1.17-crypto-rand-properly-handle-la.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 07a30769186210c1b1e25943824743355c4e50f5 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Mon, 25 Apr 2022 19:02:35 -0700 -Subject: [PATCH 11/11] [release-branch.go1.17] crypto/rand: properly handle - large Read on windows - -Use the batched reader to chunk large Read calls on windows to a max of -1 << 31 - 1 bytes. This prevents an infinite loop when trying to read -more than 1 << 32 -1 bytes, due to how RtlGenRandom works. - -This change moves the batched function from rand_unix.go to rand.go, -since it is now needed for both windows and unix implementations. - -Updates #52561 -Fixes #52932 -Fixes CVE-2022-30634 - -Change-Id: Id98fc4b1427e5cb2132762a445b2aed646a37473 -Reviewed-on: https://go-review.googlesource.com/c/go/+/402257 -Run-TryBot: Roland Shoemaker -Reviewed-by: Filippo Valsorda -Reviewed-by: Filippo Valsorda -TryBot-Result: Gopher Robot -(cherry picked from commit bb1f4416180511231de6d17a1f2f55c82aafc863) -Reviewed-on: https://go-review.googlesource.com/c/go/+/406635 -Reviewed-by: Damien Neil - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/406635 ---- - src/crypto/rand/rand.go | 18 ++++++++++++++++++ - src/crypto/rand/rand_batched.go | 22 ++++++---------------- - src/crypto/rand/rand_batched_test.go | 21 +++++++++++---------- - src/crypto/rand/rand_getentropy.go | 6 +++--- - src/crypto/rand/rand_unix.go | 4 ++-- - src/crypto/rand/rand_windows.go | 18 ++++++------------ - 6 files changed, 46 insertions(+), 43 deletions(-) - -diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go -index fddd1147e6e..f2c276008d7 100644 ---- a/src/crypto/rand/rand.go -+++ b/src/crypto/rand/rand.go -@@ -23,3 +23,21 @@ var Reader io.Reader - func Read(b []byte) (n int, err error) { - return io.ReadFull(Reader, b) - } -+ -+// batched returns a function that calls f to populate a []byte by chunking it -+// into subslices of, at most, readMax bytes. -+func batched(f func([]byte) error, readMax int) func([]byte) error { -+ return func(out []byte) error { -+ for len(out) > 0 { -+ read := len(out) -+ if read > readMax { -+ read = readMax -+ } -+ if err := f(out[:read]); err != nil { -+ return err -+ } -+ out = out[read:] -+ } -+ return nil -+ } -+} -diff --git a/src/crypto/rand/rand_batched.go b/src/crypto/rand/rand_batched.go -index d7c5bf3562d..8df715fdd14 100644 ---- a/src/crypto/rand/rand_batched.go -+++ b/src/crypto/rand/rand_batched.go -@@ -8,6 +8,7 @@ - package rand - - import ( -+ "errors" - "internal/syscall/unix" - ) - -@@ -16,20 +17,6 @@ func init() { - altGetRandom = batched(getRandomBatch, maxGetRandomRead) - } - --// batched returns a function that calls f to populate a []byte by chunking it --// into subslices of, at most, readMax bytes. --func batched(f func([]byte) bool, readMax int) func([]byte) bool { -- return func(buf []byte) bool { -- for len(buf) > readMax { -- if !f(buf[:readMax]) { -- return false -- } -- buf = buf[readMax:] -- } -- return len(buf) == 0 || f(buf) -- } --} -- - // If the kernel is too old to support the getrandom syscall(), - // unix.GetRandom will immediately return ENOSYS and we will then fall back to - // reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS -@@ -37,7 +24,10 @@ func batched(f func([]byte) bool, readMax int) func([]byte) bool { - // If the kernel supports the getrandom() syscall, unix.GetRandom will block - // until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK). - // In this case, unix.GetRandom will not return an error. --func getRandomBatch(p []byte) (ok bool) { -+func getRandomBatch(p []byte) error { - n, err := unix.GetRandom(p, 0) -- return n == len(p) && err == nil -+ if n != len(p) { -+ return errors.New("short read") -+ } -+ return err - } -diff --git a/src/crypto/rand/rand_batched_test.go b/src/crypto/rand/rand_batched_test.go -index 2d20922c825..b56345e50f1 100644 ---- a/src/crypto/rand/rand_batched_test.go -+++ b/src/crypto/rand/rand_batched_test.go -@@ -9,20 +9,21 @@ package rand - - import ( - "bytes" -+ "errors" - "testing" - ) - - func TestBatched(t *testing.T) { -- fillBatched := batched(func(p []byte) bool { -+ fillBatched := batched(func(p []byte) error { - for i := range p { - p[i] = byte(i) - } -- return true -+ return nil - }, 5) - - p := make([]byte, 13) -- if !fillBatched(p) { -- t.Fatal("batched function returned false") -+ if err := fillBatched(p); err != nil { -+ t.Fatalf("batched function returned error: %s", err) - } - expected := []byte{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2} - if !bytes.Equal(expected, p) { -@@ -31,15 +32,15 @@ func TestBatched(t *testing.T) { - } - - func TestBatchedError(t *testing.T) { -- b := batched(func(p []byte) bool { return false }, 5) -- if b(make([]byte, 13)) { -- t.Fatal("batched function should have returned false") -+ b := batched(func(p []byte) error { return errors.New("") }, 5) -+ if b(make([]byte, 13)) == nil { -+ t.Fatal("batched function should have returned an error") - } - } - - func TestBatchedEmpty(t *testing.T) { -- b := batched(func(p []byte) bool { return false }, 5) -- if !b(make([]byte, 0)) { -- t.Fatal("empty slice should always return true") -+ b := batched(func(p []byte) error { return errors.New("") }, 5) -+ if err := b(make([]byte, 0)); err != nil { -+ t.Fatalf("empty slice should always return nil: %s", err) - } - } -diff --git a/src/crypto/rand/rand_getentropy.go b/src/crypto/rand/rand_getentropy.go -index dd725372ad9..b1c19f3d0da 100644 ---- a/src/crypto/rand/rand_getentropy.go -+++ b/src/crypto/rand/rand_getentropy.go -@@ -15,7 +15,7 @@ func init() { - altGetRandom = getEntropy - } - --func getEntropy(p []byte) (ok bool) { -+func getEntropy(p []byte) error { - // getentropy(2) returns a maximum of 256 bytes per call - for i := 0; i < len(p); i += 256 { - end := i + 256 -@@ -24,8 +24,8 @@ func getEntropy(p []byte) (ok bool) { - } - err := unix.GetEntropy(p[i:end]) - if err != nil { -- return false -+ return err - } - } -- return true -+ return nil - } -diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go -index 81277eb6a5d..3d11159a340 100644 ---- a/src/crypto/rand/rand_unix.go -+++ b/src/crypto/rand/rand_unix.go -@@ -46,7 +46,7 @@ type devReader struct { - - // altGetRandom if non-nil specifies an OS-specific function to get - // urandom-style randomness. --var altGetRandom func([]byte) (ok bool) -+var altGetRandom func([]byte) (err error) - - func warnBlocked() { - println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel") -@@ -59,7 +59,7 @@ func (r *devReader) Read(b []byte) (n int, err error) { - t := time.AfterFunc(60*time.Second, warnBlocked) - defer t.Stop() - } -- if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) { -+ if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) == nil { - return len(b), nil - } - r.mu.Lock() -diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go -index 7379f1489ad..6c0655c72b6 100644 ---- a/src/crypto/rand/rand_windows.go -+++ b/src/crypto/rand/rand_windows.go -@@ -9,7 +9,6 @@ package rand - - import ( - "internal/syscall/windows" -- "os" - ) - - func init() { Reader = &rngReader{} } -@@ -17,16 +16,11 @@ func init() { Reader = &rngReader{} } - type rngReader struct{} - - func (r *rngReader) Read(b []byte) (n int, err error) { -- // RtlGenRandom only accepts 2**32-1 bytes at a time, so truncate. -- inputLen := uint32(len(b)) -- -- if inputLen == 0 { -- return 0, nil -- } -- -- err = windows.RtlGenRandom(b) -- if err != nil { -- return 0, os.NewSyscallError("RtlGenRandom", err) -+ // RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at -+ // most 1<<31-1 bytes at a time so that this works the same on 32-bit -+ // and 64-bit systems. -+ if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil { -+ return 0, err - } -- return int(inputLen), nil -+ return len(b), nil - } --- -2.30.2 - diff --git a/0016-release-branch.go1.17-math-big-check-buffer-lengths-.patch b/0016-release-branch.go1.17-math-big-check-buffer-lengths-.patch deleted file mode 100644 index 78f8090c522ff73f635f567a3ce02cd46d419180..0000000000000000000000000000000000000000 --- a/0016-release-branch.go1.17-math-big-check-buffer-lengths-.patch +++ /dev/null @@ -1,125 +0,0 @@ -From dc903a8196a831d23e9b6504239e09a9e6bcd98a Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Fri, 15 Jul 2022 10:43:44 -0700 -Subject: [PATCH] [release-branch.go1.17] math/big: check buffer lengths in - GobDecode - -In Float.GobDecode and Rat.GobDecode, check buffer sizes before -indexing slices. - -Updates #53871 -Fixes #54094 - -Change-Id: I1b652c32c2bc7a0e8aa7620f7be9b2740c568b0a -Reviewed-on: https://go-review.googlesource.com/c/go/+/417774 -TryBot-Result: Gopher Robot -Reviewed-by: Tatiana Bradley -Run-TryBot: Roland Shoemaker -(cherry picked from commit 055113ef364337607e3e72ed7d48df67fde6fc66) -Reviewed-on: https://go-review.googlesource.com/c/go/+/419814 -Reviewed-by: Julie Qiu ---- - src/math/big/floatmarsh.go | 7 +++++++ - src/math/big/floatmarsh_test.go | 12 ++++++++++++ - src/math/big/ratmarsh.go | 6 ++++++ - src/math/big/ratmarsh_test.go | 12 ++++++++++++ - 4 files changed, 37 insertions(+) - -diff --git a/src/math/big/floatmarsh.go b/src/math/big/floatmarsh.go -index d1c1dab069..990e085abe 100644 ---- a/src/math/big/floatmarsh.go -+++ b/src/math/big/floatmarsh.go -@@ -8,6 +8,7 @@ package big - - import ( - "encoding/binary" -+ "errors" - "fmt" - ) - -@@ -67,6 +68,9 @@ func (z *Float) GobDecode(buf []byte) error { - *z = Float{} - return nil - } -+ if len(buf) < 6 { -+ return errors.New("Float.GobDecode: buffer too small") -+ } - - if buf[0] != floatGobVersion { - return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0]) -@@ -83,6 +87,9 @@ func (z *Float) GobDecode(buf []byte) error { - z.prec = binary.BigEndian.Uint32(buf[2:]) - - if z.form == finite { -+ if len(buf) < 10 { -+ return errors.New("Float.GobDecode: buffer too small for finite form float") -+ } - z.exp = int32(binary.BigEndian.Uint32(buf[6:])) - z.mant = z.mant.setBytes(buf[10:]) - } -diff --git a/src/math/big/floatmarsh_test.go b/src/math/big/floatmarsh_test.go -index c056d78b80..401f45a51f 100644 ---- a/src/math/big/floatmarsh_test.go -+++ b/src/math/big/floatmarsh_test.go -@@ -137,3 +137,15 @@ func TestFloatJSONEncoding(t *testing.T) { - } - } - } -+ -+func TestFloatGobDecodeShortBuffer(t *testing.T) { -+ for _, tc := range [][]byte{ -+ []byte{0x1, 0x0, 0x0, 0x0}, -+ []byte{0x1, 0xfa, 0x0, 0x0, 0x0, 0x0}, -+ } { -+ err := NewFloat(0).GobDecode(tc) -+ if err == nil { -+ t.Error("expected GobDecode to return error for malformed input") -+ } -+ } -+} -diff --git a/src/math/big/ratmarsh.go b/src/math/big/ratmarsh.go -index fbc7b6002d..56102e845b 100644 ---- a/src/math/big/ratmarsh.go -+++ b/src/math/big/ratmarsh.go -@@ -45,12 +45,18 @@ func (z *Rat) GobDecode(buf []byte) error { - *z = Rat{} - return nil - } -+ if len(buf) < 5 { -+ return errors.New("Rat.GobDecode: buffer too small") -+ } - b := buf[0] - if b>>1 != ratGobVersion { - return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) - } - const j = 1 + 4 - i := j + binary.BigEndian.Uint32(buf[j-4:j]) -+ if len(buf) < int(i) { -+ return errors.New("Rat.GobDecode: buffer too small") -+ } - z.a.neg = b&1 != 0 - z.a.abs = z.a.abs.setBytes(buf[j:i]) - z.b.abs = z.b.abs.setBytes(buf[i:]) -diff --git a/src/math/big/ratmarsh_test.go b/src/math/big/ratmarsh_test.go -index 351d109f8d..55a9878bb8 100644 ---- a/src/math/big/ratmarsh_test.go -+++ b/src/math/big/ratmarsh_test.go -@@ -123,3 +123,15 @@ func TestRatXMLEncoding(t *testing.T) { - } - } - } -+ -+func TestRatGobDecodeShortBuffer(t *testing.T) { -+ for _, tc := range [][]byte{ -+ []byte{0x2}, -+ []byte{0x2, 0x0, 0x0, 0x0, 0xff}, -+ } { -+ err := NewRat(1, 2).GobDecode(tc) -+ if err == nil { -+ t.Error("expected GobDecode to return error for malformed input") -+ } -+ } -+} --- -2.30.2 - diff --git a/0017-path-filepath-do-not-remove-prefix-.-when-following-.patch b/0017-path-filepath-do-not-remove-prefix-.-when-following-.patch deleted file mode 100644 index 0f44f3850d75025e402eebca56b103c2e0751d04..0000000000000000000000000000000000000000 --- a/0017-path-filepath-do-not-remove-prefix-.-when-following-.patch +++ /dev/null @@ -1,103 +0,0 @@ -From e903e474f9632a151fff2df3dd3e891395f1a8f1 Mon Sep 17 00:00:00 2001 -From: Yasuhiro Matsumoto -Date: Fri, 22 Apr 2022 10:07:51 +0900 -Subject: [PATCH 1/2] path/filepath: do not remove prefix "." when following - path contains ":". - -Fixes #52476 - -Change-Id: I9eb72ac7dbccd6322d060291f31831dc389eb9bb -Reviewed-on: https://go-review.googlesource.com/c/go/+/401595 -Auto-Submit: Ian Lance Taylor -Reviewed-by: Alex Brainman -Run-TryBot: Ian Lance Taylor -Reviewed-by: Ian Lance Taylor -Reviewed-by: Damien Neil -TryBot-Result: Gopher Robot - -Reference:https://go-review.googlesource.com/c/go/+/401595/ -Conflict:NA ---- - src/path/filepath/path.go | 14 +++++++++++++- - src/path/filepath/path_test.go | 3 +++ - src/path/filepath/path_windows_test.go | 26 ++++++++++++++++++++++++++ - 3 files changed, 42 insertions(+), 1 deletion(-) - -diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go -index b56534dead..8300a32cb1 100644 ---- a/src/path/filepath/path.go -+++ b/src/path/filepath/path.go -@@ -117,9 +117,21 @@ func Clean(path string) string { - case os.IsPathSeparator(path[r]): - // empty path element - r++ -- case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): -+ case path[r] == '.' && r+1 == n: - // . element - r++ -+ case path[r] == '.' && os.IsPathSeparator(path[r+1]): -+ // ./ element -+ r++ -+ -+ for r < len(path) && os.IsPathSeparator(path[r]) { -+ r++ -+ } -+ if out.w == 0 && volumeNameLen(path[r:]) > 0 { -+ // When joining prefix "." and an absolute path on Windows, -+ // the prefix should not be removed. -+ out.append('.') -+ } - case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): - // .. element: remove to last separator - r += 2 -diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go -index bc5509b49c..ed17a8854d 100644 ---- a/src/path/filepath/path_test.go -+++ b/src/path/filepath/path_test.go -@@ -93,6 +93,9 @@ var wincleantests = []PathTest{ - {`//host/share/foo/../baz`, `\\host\share\baz`}, - {`\\a\b\..\c`, `\\a\b\c`}, - {`\\a\b`, `\\a\b`}, -+ {`.\c:`, `.\c:`}, -+ {`.\c:\foo`, `.\c:\foo`}, -+ {`.\c:foo`, `.\c:foo`}, - } - - func TestClean(t *testing.T) { -diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go -index 76a459ac96..3edafb5a85 100644 ---- a/src/path/filepath/path_windows_test.go -+++ b/src/path/filepath/path_windows_test.go -@@ -530,3 +530,29 @@ func TestNTNamespaceSymlink(t *testing.T) { - t.Errorf(`EvalSymlinks(%q): got %q, want %q`, filelink, got, want) - } - } -+ -+func TestIssue52476(t *testing.T) { -+ tests := []struct { -+ lhs, rhs string -+ want string -+ }{ -+ {`..\.`, `C:`, `..\C:`}, -+ {`..`, `C:`, `..\C:`}, -+ {`.`, `:`, `:`}, -+ {`.`, `C:`, `.\C:`}, -+ {`.`, `C:/a/b/../c`, `.\C:\a\c`}, -+ {`.`, `\C:`, `.\C:`}, -+ {`C:\`, `.`, `C:\`}, -+ {`C:\`, `C:\`, `C:\C:`}, -+ {`C`, `:`, `C\:`}, -+ {`\.`, `C:`, `\C:`}, -+ {`\`, `C:`, `\C:`}, -+ } -+ -+ for _, test := range tests { -+ got := filepath.Join(test.lhs, test.rhs) -+ if got != test.want { -+ t.Errorf(`Join(%q, %q): got %q, want %q`, test.lhs, test.rhs, got, test.want) -+ } -+ } -+} --- -2.30.2 - diff --git a/0018-release-branch.go1.17-syscall-check-correct-group-in.patch b/0018-release-branch.go1.17-syscall-check-correct-group-in.patch deleted file mode 100644 index 23872111deb09ff6cf9b92db33cd86301899934d..0000000000000000000000000000000000000000 --- a/0018-release-branch.go1.17-syscall-check-correct-group-in.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 66cff0cda766c1533373fabf3bc26fc3397e55d5 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Tue, 12 Apr 2022 13:38:17 -0700 -Subject: [PATCH 2/2] [release-branch.go1.17] syscall: check correct group in - Faccessat - -The Faccessat call checks the user, group, or other permission bits of a -file to see if the calling process can access it. The test to see if the -group permissions should be used was made with the wrong group id, using -the process's group id rather than the file's group id. Fix this to use -the correct group id. - -No test since we cannot easily change file permissions when not running -as root and the test is meaningless if running as root. - -For #52313 -Fixes #52439 - -Change-Id: I4e2c84754b0af7830b40fd15dedcbc58374d75ee -Reviewed-on: https://go-review.googlesource.com/c/go/+/399539 -Reviewed-by: Ian Lance Taylor -Run-TryBot: Ian Lance Taylor -TryBot-Result: Gopher Robot -(cherry picked from commit f66925e854e71e0c54b581885380a490d7afa30c) -Reviewed-on: https://go-review.googlesource.com/c/go/+/401078 -Auto-Submit: Tatiana Bradley -Run-TryBot: Tatiana Bradley -Run-TryBot: Damien Neil -Auto-Submit: Damien Neil -Reviewed-by: Tatiana Bradley - -Reference:https://go-review.googlesource.com/c/go/+/401078/ -Conflict:NA ---- - src/syscall/syscall_linux.go | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go -index dfce3d0a4b..3387f3bdc2 100644 ---- a/src/syscall/syscall_linux.go -+++ b/src/syscall/syscall_linux.go -@@ -109,7 +109,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - gid = Getgid() - } - -- if uint32(gid) == st.Gid || isGroupMember(gid) { -+ if uint32(gid) == st.Gid || isGroupMember(int(st.Gid)) { - fmode = (st.Mode >> 3) & 7 - } else { - fmode = st.Mode & 7 --- -2.30.2 - diff --git a/0019-release-branch.go1.18-net-http-update-bundled-golang.patch b/0019-release-branch.go1.18-net-http-update-bundled-golang.patch deleted file mode 100644 index bb88ffd8f25334b9b38efb3a899543927ce056ad..0000000000000000000000000000000000000000 --- a/0019-release-branch.go1.18-net-http-update-bundled-golang.patch +++ /dev/null @@ -1,99 +0,0 @@ -From b2058191785138021b635f609de3d5f651ec02cd Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Mon, 22 Aug 2022 16:21:02 -0700 -Subject: [PATCH] [release-branch.go1.18] net/http: update bundled - golang.org/x/net/http2 - -Disable cmd/internal/moddeps test, since this update includes PRIVATE -track fixes. - -Fixes CVE-2022-27664 -Fixes #53977 -For #54658. - -Change-Id: I84b0b8f61e49e15ef55ef8d738730107a3cf849b -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1554415 -Reviewed-by: Roland Shoemaker -Reviewed-by: Tatiana Bradley -Reviewed-on: https://go-review.googlesource.com/c/go/+/428635 -Reviewed-by: Tatiana Bradley -Run-TryBot: Michael Knyszek -TryBot-Result: Gopher Robot -Reviewed-by: Carlos Amedee - -Conflict:NA -Reference:https://go-review.googlesource.com/c/go/+/428635/ ---- - src/cmd/internal/moddeps/moddeps_test.go | 2 ++ - src/net/http/h2_bundle.go | 21 +++++++++++++-------- - 2 files changed, 15 insertions(+), 8 deletions(-) - -diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go -index 56c3b2585c..3306e29431 100644 ---- a/src/cmd/internal/moddeps/moddeps_test.go -+++ b/src/cmd/internal/moddeps/moddeps_test.go -@@ -34,6 +34,8 @@ import ( - // See issues 36852, 41409, and 43687. - // (Also see golang.org/issue/27348.) - func TestAllDependencies(t *testing.T) { -+ t.Skip("TODO(#53977): 1.18.5 contains unreleased changes from vendored modules") -+ - goBin := testenv.GoToolPath(t) - - // Ensure that all packages imported within GOROOT -diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go -index 1b73da7f21..d7e2f764c8 100644 ---- a/src/net/http/h2_bundle.go -+++ b/src/net/http/h2_bundle.go -@@ -3339,10 +3339,11 @@ func (s http2SettingID) String() string { - // name (key). See httpguts.ValidHeaderName for the base rules. - // - // Further, http2 says: --// "Just as in HTTP/1.x, header field names are strings of ASCII --// characters that are compared in a case-insensitive --// fashion. However, header field names MUST be converted to --// lowercase prior to their encoding in HTTP/2. " -+// -+// "Just as in HTTP/1.x, header field names are strings of ASCII -+// characters that are compared in a case-insensitive -+// fashion. However, header field names MUST be converted to -+// lowercase prior to their encoding in HTTP/2. " - func http2validWireHeaderFieldName(v string) bool { - if len(v) == 0 { - return false -@@ -3533,8 +3534,8 @@ func (s *http2sorter) SortStrings(ss []string) { - // validPseudoPath reports whether v is a valid :path pseudo-header - // value. It must be either: - // --// *) a non-empty string starting with '/' --// *) the string '*', for OPTIONS requests. -+// *) a non-empty string starting with '/' -+// *) the string '*', for OPTIONS requests. - // - // For now this is only used a quick check for deciding when to clean - // up Opaque URLs before sending requests from the Transport. -@@ -4999,6 +5000,9 @@ func (sc *http2serverConn) startGracefulShutdownInternal() { - func (sc *http2serverConn) goAway(code http2ErrCode) { - sc.serveG.check() - if sc.inGoAway { -+ if sc.goAwayCode == http2ErrCodeNo { -+ sc.goAwayCode = code -+ } - return - } - sc.inGoAway = true -@@ -6211,8 +6215,9 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) { - // prior to the headers being written. If the set of trailers is fixed - // or known before the header is written, the normal Go trailers mechanism - // is preferred: --// https://golang.org/pkg/net/http/#ResponseWriter --// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers -+// -+// https://golang.org/pkg/net/http/#ResponseWriter -+// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers - const http2TrailerPrefix = "Trailer:" - - // promoteUndeclaredTrailers permits http.Handlers to set trailers --- -2.30.2 - diff --git a/0020-release-branch.go1.18-regexp-limit-size-of-parsed-re.patch b/0020-release-branch.go1.18-regexp-limit-size-of-parsed-re.patch deleted file mode 100644 index 436d179e6bff17d7fa124142248dc997ba68947d..0000000000000000000000000000000000000000 --- a/0020-release-branch.go1.18-regexp-limit-size-of-parsed-re.patch +++ /dev/null @@ -1,386 +0,0 @@ -From 8b3a5d153b7b255bafd1a82d61505088356d0458 Mon Sep 17 00:00:00 2001 -From: Russ Cox -Date: Wed, 28 Sep 2022 11:18:51 -0400 -Subject: [PATCH] regexp: limit size of parsed regexps - -Set a 128 MB limit on the amount of space used by []syntax.Inst -in the compiled form corresponding to a given regexp. - -Also set a 128 MB limit on the rune storage in the *syntax.Regexp -tree itself. - -Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting this issue. - -Fixes CVE-2022-41715. -Updates #55949. -Fixes #55950. - -Change-Id: Ia656baed81564436368cf950e1c5409752f28e1b -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1592136 -TryBot-Result: Security TryBots -Reviewed-by: Damien Neil -Run-TryBot: Roland Shoemaker -Reviewed-by: Julie Qiu -Reviewed-on: https://go-review.googlesource.com/c/go/+/438501 -Run-TryBot: Carlos Amedee -Reviewed-by: Carlos Amedee -Reviewed-by: Dmitri Shuralyov -TryBot-Result: Gopher Robot -Reviewed-by: Dmitri Shuralyov ---- - src/regexp/syntax/parse.go | 222 +++++++++++++++++++++++++++++++- - src/regexp/syntax/parse_test.go | 11 +- - 2 files changed, 224 insertions(+), 9 deletions(-) - -diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go -index 7b40309..67254d6 100644 ---- a/src/regexp/syntax/parse.go -+++ b/src/regexp/syntax/parse.go -@@ -43,6 +43,7 @@ const ( - ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator" - ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression" - ErrUnexpectedParen ErrorCode = "unexpected )" -+ ErrNestingDepth ErrorCode = "expression nests too deeply" - ) - - func (e ErrorCode) String() string { -@@ -76,13 +77,63 @@ const ( - opVerticalBar - ) - -+// maxHeight is the maximum height of a regexp parse tree. -+// It is somewhat arbitrarily chosen, but the idea is to be large enough -+// that no one will actually hit in real use but at the same time small enough -+// that recursion on the Regexp tree will not hit the 1GB Go stack limit. -+// The maximum amount of stack for a single recursive frame is probably -+// closer to 1kB, so this could potentially be raised, but it seems unlikely -+// that people have regexps nested even this deeply. -+// We ran a test on Google's C++ code base and turned up only -+// a single use case with depth > 100; it had depth 128. -+// Using depth 1000 should be plenty of margin. -+// As an optimization, we don't even bother calculating heights -+// until we've allocated at least maxHeight Regexp structures. -+const maxHeight = 1000 -+ -+// maxSize is the maximum size of a compiled regexp in Insts. -+// It too is somewhat arbitrarily chosen, but the idea is to be large enough -+// to allow significant regexps while at the same time small enough that -+// the compiled form will not take up too much memory. -+// 128 MB is enough for a 3.3 million Inst structures, which roughly -+// corresponds to a 3.3 MB regexp. -+const ( -+ maxSize = 128 << 20 / instSize -+ instSize = 5 * 8 // byte, 2 uint32, slice is 5 64-bit words -+) -+ -+// maxRunes is the maximum number of runes allowed in a regexp tree -+// counting the runes in all the nodes. -+// Ignoring character classes p.numRunes is always less than the length of the regexp. -+// Character classes can make it much larger: each \pL adds 1292 runes. -+// 128 MB is enough for 32M runes, which is over 26k \pL instances. -+// Note that repetitions do not make copies of the rune slices, -+// so \pL{1000} is only one rune slice, not 1000. -+// We could keep a cache of character classes we've seen, -+// so that all the \pL we see use the same rune list, -+// but that doesn't remove the problem entirely: -+// consider something like [\pL01234][\pL01235][\pL01236]...[\pL^&*()]. -+// And because the Rune slice is exposed directly in the Regexp, -+// there is not an opportunity to change the representation to allow -+// partial sharing between different character classes. -+// So the limit is the best we can do. -+const ( -+ maxRunes = 128 << 20 / runeSize -+ runeSize = 4 // rune is int32 -+) -+ - type parser struct { - flags Flags // parse mode flags - stack []*Regexp // stack of parsed expressions - free *Regexp - numCap int // number of capturing groups seen - wholeRegexp string -- tmpClass []rune // temporary char class work space -+ tmpClass []rune // temporary char class work space -+ numRegexp int // number of regexps allocated -+ numRunes int // number of runes in char classes -+ repeats int64 // product of all repetitions seen -+ height map[*Regexp]int // regexp height, for height limit check -+ size map[*Regexp]int64 // regexp compiled size, for size limit check - } - - func (p *parser) newRegexp(op Op) *Regexp { -@@ -92,20 +143,155 @@ func (p *parser) newRegexp(op Op) *Regexp { - *re = Regexp{} - } else { - re = new(Regexp) -+ p.numRegexp++ - } - re.Op = op - return re - } - - func (p *parser) reuse(re *Regexp) { -+ if p.height != nil { -+ delete(p.height, re) -+ } - re.Sub0[0] = p.free - p.free = re - } - -+func (p *parser) checkLimits(re *Regexp) { -+ if p.numRunes > maxRunes { -+ panic(ErrInternalError) -+ } -+ p.checkSize(re) -+ p.checkHeight(re) -+} -+ -+func (p *parser) checkSize(re *Regexp) { -+ if p.size == nil { -+ // We haven't started tracking size yet. -+ // Do a relatively cheap check to see if we need to start. -+ // Maintain the product of all the repeats we've seen -+ // and don't track if the total number of regexp nodes -+ // we've seen times the repeat product is in budget. -+ if p.repeats == 0 { -+ p.repeats = 1 -+ } -+ if re.Op == OpRepeat { -+ n := re.Max -+ if n == -1 { -+ n = re.Min -+ } -+ if n <= 0 { -+ n = 1 -+ } -+ if int64(n) > maxSize/p.repeats { -+ p.repeats = maxSize -+ } else { -+ p.repeats *= int64(n) -+ } -+ } -+ if int64(p.numRegexp) < maxSize/p.repeats { -+ return -+ } -+ -+ // We need to start tracking size. -+ // Make the map and belatedly populate it -+ // with info about everything we've constructed so far. -+ p.size = make(map[*Regexp]int64) -+ for _, re := range p.stack { -+ p.checkSize(re) -+ } -+ } -+ -+ if p.calcSize(re, true) > maxSize { -+ panic(ErrInternalError) -+ } -+} -+ -+func (p *parser) calcSize(re *Regexp, force bool) int64 { -+ if !force { -+ if size, ok := p.size[re]; ok { -+ return size -+ } -+ } -+ -+ var size int64 -+ switch re.Op { -+ case OpLiteral: -+ size = int64(len(re.Rune)) -+ case OpCapture, OpStar: -+ // star can be 1+ or 2+; assume 2 pessimistically -+ size = 2 + p.calcSize(re.Sub[0], false) -+ case OpPlus, OpQuest: -+ size = 1 + p.calcSize(re.Sub[0], false) -+ case OpConcat: -+ for _, sub := range re.Sub { -+ size += p.calcSize(sub, false) -+ } -+ case OpAlternate: -+ for _, sub := range re.Sub { -+ size += p.calcSize(sub, false) -+ } -+ if len(re.Sub) > 1 { -+ size += int64(len(re.Sub)) - 1 -+ } -+ case OpRepeat: -+ sub := p.calcSize(re.Sub[0], false) -+ if re.Max == -1 { -+ if re.Min == 0 { -+ size = 2 + sub // x* -+ } else { -+ size = 1 + int64(re.Min)*sub // xxx+ -+ } -+ break -+ } -+ // x{2,5} = xx(x(x(x)?)?)? -+ size = int64(re.Max)*sub + int64(re.Max-re.Min) -+ } -+ -+ if size < 1 { -+ size = 1 -+ } -+ p.size[re] = size -+ return size -+} -+ -+func (p *parser) checkHeight(re *Regexp) { -+ if p.numRegexp < maxHeight { -+ return -+ } -+ if p.height == nil { -+ p.height = make(map[*Regexp]int) -+ for _, re := range p.stack { -+ p.checkHeight(re) -+ } -+ } -+ if p.calcHeight(re, true) > maxHeight { -+ panic(ErrNestingDepth) -+ } -+} -+ -+func (p *parser) calcHeight(re *Regexp, force bool) int { -+ if !force { -+ if h, ok := p.height[re]; ok { -+ return h -+ } -+ } -+ h := 1 -+ for _, sub := range re.Sub { -+ hsub := p.calcHeight(sub, false) -+ if h < 1+hsub { -+ h = 1 + hsub -+ } -+ } -+ p.height[re] = h -+ return h -+} -+ - // Parse stack manipulation. - - // push pushes the regexp re onto the parse stack and returns the regexp. - func (p *parser) push(re *Regexp) *Regexp { -+ p.numRunes += len(re.Rune) - if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] { - // Single rune. - if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) { -@@ -137,6 +323,7 @@ func (p *parser) push(re *Regexp) *Regexp { - } - - p.stack = append(p.stack, re) -+ p.checkLimits(re) - return re - } - -@@ -246,6 +433,7 @@ func (p *parser) repeat(op Op, min, max int, before, after, lastRepeat string) ( - re.Sub = re.Sub0[:1] - re.Sub[0] = sub - p.stack[n-1] = re -+ p.checkLimits(re) - - if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { - return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} -@@ -390,12 +578,16 @@ func (p *parser) collapse(subs []*Regexp, op Op) *Regexp { - // frees (passes to p.reuse) any removed *Regexps. - // - // For example, --// ABC|ABD|AEF|BCX|BCY -+// -+// ABC|ABD|AEF|BCX|BCY -+// - // simplifies by literal prefix extraction to --// A(B(C|D)|EF)|BC(X|Y) -+// -+// A(B(C|D)|EF)|BC(X|Y) -+// - // which simplifies by character class introduction to --// A(B[CD]|EF)|BC[XY] - // -+// A(B[CD]|EF)|BC[XY] - func (p *parser) factor(sub []*Regexp) []*Regexp { - if len(sub) < 2 { - return sub -@@ -449,6 +641,7 @@ func (p *parser) factor(sub []*Regexp) []*Regexp { - - for j := start; j < i; j++ { - sub[j] = p.removeLeadingString(sub[j], len(str)) -+ p.checkLimits(sub[j]) - } - suffix := p.collapse(sub[start:i], OpAlternate) // recurse - -@@ -506,6 +699,7 @@ func (p *parser) factor(sub []*Regexp) []*Regexp { - for j := start; j < i; j++ { - reuse := j != start // prefix came from sub[start] - sub[j] = p.removeLeadingRegexp(sub[j], reuse) -+ p.checkLimits(sub[j]) - } - suffix := p.collapse(sub[start:i], OpAlternate) // recurse - -@@ -693,6 +887,23 @@ func literalRegexp(s string, flags Flags) *Regexp { - // Flags, and returns a regular expression parse tree. The syntax is - // described in the top-level comment. - func Parse(s string, flags Flags) (*Regexp, error) { -+ return parse(s, flags) -+} -+ -+func parse(s string, flags Flags) (_ *Regexp, err error) { -+ defer func() { -+ switch r := recover(); r { -+ default: -+ panic(r) -+ case nil: -+ // ok -+ case ErrInternalError: // too big -+ err = &Error{Code: ErrInternalError, Expr: s} -+ case ErrNestingDepth: -+ err = &Error{Code: ErrNestingDepth, Expr: s} -+ } -+ }() -+ - if flags&Literal != 0 { - // Trivial parser for literal string. - if err := checkUTF8(s); err != nil { -@@ -704,7 +915,6 @@ func Parse(s string, flags Flags) (*Regexp, error) { - // Otherwise, must do real work. - var ( - p parser -- err error - c rune - op Op - lastRepeat string -@@ -1733,7 +1943,7 @@ func appendClass(r []rune, x []rune) []rune { - return r - } - --// appendFolded returns the result of appending the case folding of the class x to the class r. -+// appendFoldedClass returns the result of appending the case folding of the class x to the class r. - func appendFoldedClass(r []rune, x []rune) []rune { - for i := 0; i < len(x); i += 2 { - r = appendFoldedRange(r, x[i], x[i+1]) -diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go -index 5581ba1..6044da6 100644 ---- a/src/regexp/syntax/parse_test.go -+++ b/src/regexp/syntax/parse_test.go -@@ -479,10 +479,15 @@ var invalidRegexps = []string{ - `(?P<>a)`, - `[a-Z]`, - `(?i)[a-Z]`, -- `a{100000}`, -- `a{100000,}`, -- "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", - `\Q\E*`, -+ `a{100000}`, // too much repetition -+ `a{100000,}`, // too much repetition -+ "((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}){2})", // too much repetition -+ strings.Repeat("(", 1000) + strings.Repeat(")", 1000), // too deep -+ strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000), // too deep -+ "(" + strings.Repeat("(xx?)", 1000) + "){1000}", // too long -+ strings.Repeat("(xx?){1000}", 1000), // too long -+ strings.Repeat(`\pL`, 27000), // too many runes - } - - var onlyPerl = []string{ --- -2.33.0 - diff --git a/0021-release-branch.go1.18-net-http-httputil-avoid-query-.patch b/0021-release-branch.go1.18-net-http-httputil-avoid-query-.patch deleted file mode 100644 index b07cf56be34db31d457fe07f457477c33be3122b..0000000000000000000000000000000000000000 --- a/0021-release-branch.go1.18-net-http-httputil-avoid-query-.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 51a477dc4f1130d53e66cd2003de0bac40e5e2be Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Thu, 22 Sep 2022 13:32:00 -0700 -Subject: [PATCH 2/3] [release-branch.go1.18] net/http/httputil: avoid query - parameter smuggling - -Query parameter smuggling occurs when a proxy's interpretation -of query parameters differs from that of a downstream server. -Change ReverseProxy to avoid forwarding ignored query parameters. - -Remove unparsable query parameters from the outbound request - - * if req.Form != nil after calling ReverseProxy.Director; and - * before calling ReverseProxy.Rewrite. - -This change preserves the existing behavior of forwarding the -raw query untouched if a Director hook does not parse the query -by calling Request.ParseForm (possibly indirectly). - -Fixes #55842 -For #54663 -For CVE-2022-2880 - -Change-Id: If1621f6b0e73a49d79059dae9e6b256e0ff18ca9 -Reviewed-on: https://go-review.googlesource.com/c/go/+/432976 -Reviewed-by: Roland Shoemaker -Reviewed-by: Brad Fitzpatrick -TryBot-Result: Gopher Robot -Run-TryBot: Damien Neil -(cherry picked from commit 7c84234142149bd24a4096c6cab691d3593f3431) -Reviewed-on: https://go-review.googlesource.com/c/go/+/433695 -Reviewed-by: Dmitri Shuralyov -Reviewed-by: Dmitri Shuralyov ---- - src/net/http/httputil/reverseproxy.go | 36 +++++++++++ - src/net/http/httputil/reverseproxy_test.go | 74 ++++++++++++++++++++++ - 2 files changed, 110 insertions(+) - -diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go -index 8b63368386..c76eec6987 100644 ---- a/src/net/http/httputil/reverseproxy.go -+++ b/src/net/http/httputil/reverseproxy.go -@@ -249,6 +249,9 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - } - - p.Director(outreq) -+ if outreq.Form != nil { -+ outreq.URL.RawQuery = cleanQueryParams(outreq.URL.RawQuery) -+ } - outreq.Close = false - - reqUpType := upgradeType(outreq.Header) -@@ -628,3 +631,36 @@ func (c switchProtocolCopier) copyToBackend(errc chan<- error) { - _, err := io.Copy(c.backend, c.user) - errc <- err - } -+ -+func cleanQueryParams(s string) string { -+ reencode := func(s string) string { -+ v, _ := url.ParseQuery(s) -+ return v.Encode() -+ } -+ for i := 0; i < len(s); { -+ switch s[i] { -+ case ';': -+ return reencode(s) -+ case '%': -+ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { -+ return reencode(s) -+ } -+ i += 3 -+ default: -+ i++ -+ } -+ } -+ return s -+} -+ -+func ishex(c byte) bool { -+ switch { -+ case '0' <= c && c <= '9': -+ return true -+ case 'a' <= c && c <= 'f': -+ return true -+ case 'A' <= c && c <= 'F': -+ return true -+ } -+ return false -+} -diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go -index 4b6ad77a29..8c0a4f136b 100644 ---- a/src/net/http/httputil/reverseproxy_test.go -+++ b/src/net/http/httputil/reverseproxy_test.go -@@ -1517,3 +1517,77 @@ func TestJoinURLPath(t *testing.T) { - } - } - } -+ -+const ( -+ testWantsCleanQuery = true -+ testWantsRawQuery = false -+) -+ -+func TestReverseProxyQueryParameterSmugglingDirectorDoesNotParseForm(t *testing.T) { -+ testReverseProxyQueryParameterSmuggling(t, testWantsRawQuery, func(u *url.URL) *ReverseProxy { -+ proxyHandler := NewSingleHostReverseProxy(u) -+ oldDirector := proxyHandler.Director -+ proxyHandler.Director = func(r *http.Request) { -+ oldDirector(r) -+ } -+ return proxyHandler -+ }) -+} -+ -+func TestReverseProxyQueryParameterSmugglingDirectorParsesForm(t *testing.T) { -+ testReverseProxyQueryParameterSmuggling(t, testWantsCleanQuery, func(u *url.URL) *ReverseProxy { -+ proxyHandler := NewSingleHostReverseProxy(u) -+ oldDirector := proxyHandler.Director -+ proxyHandler.Director = func(r *http.Request) { -+ // Parsing the form causes ReverseProxy to remove unparsable -+ // query parameters before forwarding. -+ r.FormValue("a") -+ oldDirector(r) -+ } -+ return proxyHandler -+ }) -+} -+ -+func testReverseProxyQueryParameterSmuggling(t *testing.T, wantCleanQuery bool, newProxy func(*url.URL) *ReverseProxy) { -+ const content = "response_content" -+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -+ w.Write([]byte(r.URL.RawQuery)) -+ })) -+ defer backend.Close() -+ backendURL, err := url.Parse(backend.URL) -+ if err != nil { -+ t.Fatal(err) -+ } -+ proxyHandler := newProxy(backendURL) -+ frontend := httptest.NewServer(proxyHandler) -+ defer frontend.Close() -+ -+ // Don't spam output with logs of queries containing semicolons. -+ backend.Config.ErrorLog = log.New(io.Discard, "", 0) -+ frontend.Config.ErrorLog = log.New(io.Discard, "", 0) -+ -+ for _, test := range []struct { -+ rawQuery string -+ cleanQuery string -+ }{{ -+ rawQuery: "a=1&a=2;b=3", -+ cleanQuery: "a=1", -+ }, { -+ rawQuery: "a=1&a=%zz&b=3", -+ cleanQuery: "a=1&b=3", -+ }} { -+ res, err := frontend.Client().Get(frontend.URL + "?" + test.rawQuery) -+ if err != nil { -+ t.Fatalf("Get: %v", err) -+ } -+ defer res.Body.Close() -+ body, _ := io.ReadAll(res.Body) -+ wantQuery := test.rawQuery -+ if wantCleanQuery { -+ wantQuery = test.cleanQuery -+ } -+ if got, want := string(body), wantQuery; got != want { -+ t.Errorf("proxy forwarded raw query %q as %q, want %q", test.rawQuery, got, want) -+ } -+ } -+} --- -2.33.0 - diff --git a/0022-release-branch.go1.18-archive-tar-limit-size-of-head.patch b/0022-release-branch.go1.18-archive-tar-limit-size-of-head.patch deleted file mode 100644 index 550877a2761d619b88ba92186052542583d1ad5c..0000000000000000000000000000000000000000 --- a/0022-release-branch.go1.18-archive-tar-limit-size-of-head.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 7dd44b287830fbb2256aceac4a36756b955c0279 Mon Sep 17 00:00:00 2001 -From: Damien Neil -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 -Run-TryBot: Roland Shoemaker -Reviewed-by: Roland Shoemaker -(cherry picked from commit 6ee768cef6b82adf7a90dcf367a1699ef694f3b2) -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1590622 -Reviewed-by: Damien Neil -Reviewed-by: Julie Qiu -Reviewed-on: https://go-review.googlesource.com/c/go/+/438500 -Reviewed-by: Dmitri Shuralyov -Reviewed-by: Carlos Amedee -Reviewed-by: Dmitri Shuralyov -Run-TryBot: Carlos Amedee -TryBot-Result: Gopher Robot ---- - src/archive/tar/format.go | 4 ++++ - src/archive/tar/reader.go | 14 ++++++++++++-- - src/archive/tar/reader_test.go | 11 ++++++++++- - src/archive/tar/writer.go | 3 +++ - src/archive/tar/writer_test.go | 27 +++++++++++++++++++++++++++ - 5 files changed, 56 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..5a644a4 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" -@@ -243,6 +244,9 @@ func TestReader(t *testing.T) { - }, { - file: "testdata/pax-bad-hdr-file.tar", - err: ErrHeader, -+ }, { -+ file: "testdata/pax-bad-hdr-large.tar.bz2", -+ err: ErrFieldTooLong, - }, { - file: "testdata/pax-bad-mtime-file.tar", - err: ErrHeader, -@@ -625,9 +629,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 } --- -2.33.0 - diff --git a/0023-syscall-os-exec-reject-environment-variables-contain.patch b/0023-syscall-os-exec-reject-environment-variables-contain.patch deleted file mode 100644 index 50c3d7566db0ccfd43deb45c407a21c9ac98bb4c..0000000000000000000000000000000000000000 --- a/0023-syscall-os-exec-reject-environment-variables-contain.patch +++ /dev/null @@ -1,248 +0,0 @@ -From 0c539fa7a4a9d29252523e41e073198195ba6691 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Mon, 17 Oct 2022 17:38:29 -0700 -Subject: [PATCH] syscall, os/exec: reject environment variables containing - NULs - -Check for and reject environment variables containing NULs. - -The conventions for passing environment variables to subprocesses -cause most or all systems to interpret a NUL as a separator. The -syscall package rejects environment variables containing a NUL -on most systems, but erroniously did not do so on Windows. This -causes an environment variable such as "FOO=a\x00BAR=b" to be -interpreted as "FOO=a", "BAR=b". - -Check for and reject NULs in environment variables passed to -syscall.StartProcess on Windows. - -Add a redundant check to os/exec as extra insurance. - -Fixes #56284 -Fixes CVE-2022-41716 - -Change-Id: I2950e2b0cb14ebd26e5629be1521858f66a7d4ae -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1609434 -Run-TryBot: Damien Neil -Reviewed-by: Tatiana Bradley -Reviewed-by: Roland Shoemaker -TryBot-Result: Security TryBots -Reviewed-on: https://go-review.googlesource.com/c/go/+/446916 -Reviewed-by: Tatiana Bradley -TryBot-Result: Gopher Robot -Run-TryBot: Matthew Dempsky -Reviewed-by: Heschi Kreinick - -Reference: https://go-review.googlesource.com/c/go/+/446916 -Conflict: src/os/exec/exec.go;src/syscall/exec_windows.go ---- - src/os/exec/env_test.go | 19 +++++++++++++------ - src/os/exec/exec.go | 38 ++++++++++++++++++++++++++++++++----- - src/os/exec/exec_test.go | 9 +++++++++ - src/syscall/exec_windows.go | 20 ++++++++++++++----- - 4 files changed, 70 insertions(+), 16 deletions(-) - -diff --git a/src/os/exec/env_test.go b/src/os/exec/env_test.go -index b5ac398..47b7c04 100644 ---- a/src/os/exec/env_test.go -+++ b/src/os/exec/env_test.go -@@ -11,9 +11,10 @@ import ( - - func TestDedupEnv(t *testing.T) { - tests := []struct { -- noCase bool -- in []string -- want []string -+ noCase bool -+ in []string -+ want []string -+ wantErr bool - }{ - { - noCase: true, -@@ -29,11 +30,17 @@ func TestDedupEnv(t *testing.T) { - in: []string{"=a", "=b", "foo", "bar"}, - want: []string{"=b", "foo", "bar"}, - }, -+ { -+ // Filter out entries containing NULs. -+ in: []string{"A=a\x00b", "B=b", "C\x00C=c"}, -+ want: []string{"B=b"}, -+ wantErr: true, -+ }, - } - for _, tt := range tests { -- got := dedupEnvCase(tt.noCase, tt.in) -- if !reflect.DeepEqual(got, tt.want) { -- t.Errorf("Dedup(%v, %q) = %q; want %q", tt.noCase, tt.in, got, tt.want) -+ got, err := dedupEnvCase(tt.noCase, tt.in) -+ if !reflect.DeepEqual(got, tt.want) || (err != nil) != tt.wantErr { -+ t.Errorf("Dedup(%v, %q) = %q, %v; want %q, error:%v", tt.noCase, tt.in, got, err, tt.want, tt.wantErr) - } - } - } -diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go -index 0c49575..6f5c61b 100644 ---- a/src/os/exec/exec.go -+++ b/src/os/exec/exec.go -@@ -414,7 +414,7 @@ func (c *Cmd) Start() error { - } - c.childFiles = append(c.childFiles, c.ExtraFiles...) - -- envv, err := c.envv() -+ env, err := c.environ() - if err != nil { - return err - } -@@ -422,7 +422,7 @@ func (c *Cmd) Start() error { - c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{ - Dir: c.Dir, - Files: c.childFiles, -- Env: addCriticalEnv(dedupEnv(envv)), -+ Env: env, - Sys: c.SysProcAttr, - }) - if err != nil { -@@ -738,16 +738,21 @@ func minInt(a, b int) int { - // dedupEnv returns a copy of env with any duplicates removed, in favor of - // later values. - // Items not of the normal environment "key=value" form are preserved unchanged. --func dedupEnv(env []string) []string { -+func dedupEnv(env []string) ([]string, error) { - return dedupEnvCase(runtime.GOOS == "windows", env) - } - - // dedupEnvCase is dedupEnv with a case option for testing. - // If caseInsensitive is true, the case of keys is ignored. --func dedupEnvCase(caseInsensitive bool, env []string) []string { -+func dedupEnvCase(caseInsensitive bool, env []string) ([]string, error) { -+ var err error - out := make([]string, 0, len(env)) - saw := make(map[string]int, len(env)) // key => index into out - for _, kv := range env { -+ if strings.IndexByte(kv, 0) != -1 { -+ err = errors.New("exec: environment variable contains NUL") -+ continue -+ } - eq := strings.Index(kv, "=") - if eq < 0 { - out = append(out, kv) -@@ -764,7 +769,7 @@ func dedupEnvCase(caseInsensitive bool, env []string) []string { - saw[k] = len(out) - out = append(out, kv) - } -- return out -+ return out, err - } - - // addCriticalEnv adds any critical environment variables that are required -@@ -787,3 +792,26 @@ func addCriticalEnv(env []string) []string { - } - return append(env, "SYSTEMROOT="+os.Getenv("SYSTEMROOT")) - } -+ -+// environ returns a best-effort copy of the environment in which the command -+// would be run as it is currently configured. If an error occurs in computing -+// the environment, it is returned alongside the best-effort copy. -+func (c *Cmd) environ() ([]string, error) { -+ env, err := c.envv() -+ if err != nil { -+ return env, err -+ } -+ env, dedupErr := dedupEnv(env) -+ if err == nil { -+ err = dedupErr -+ } -+ return addCriticalEnv(env), err -+} -+ -+// Environ returns a copy of the environment in which the command would be run -+// as it is currently configured. -+func (c *Cmd) Environ() []string { -+ // Intentionally ignore errors: environ returns a best-effort environment no matter what. -+ env, _ := c.environ() -+ return env -+} -diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go -index d854e0d..d03eab2 100644 ---- a/src/os/exec/exec_test.go -+++ b/src/os/exec/exec_test.go -@@ -1104,6 +1104,15 @@ func TestDedupEnvEcho(t *testing.T) { - } - } - -+func TestEnvNULCharacter(t *testing.T) { -+ cmd := helperCommand(t, "echoenv", "FOO", "BAR") -+ cmd.Env = append(cmd.Environ(), "FOO=foo\x00BAR=bar") -+ out, err := cmd.CombinedOutput() -+ if err == nil { -+ t.Errorf("output = %q; want error", string(out)) -+ } -+} -+ - func TestString(t *testing.T) { - echoPath, err := exec.LookPath("echo") - if err != nil { -diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go -index 9d10d6a..50892be 100644 ---- a/src/syscall/exec_windows.go -+++ b/src/syscall/exec_windows.go -@@ -7,6 +7,7 @@ - package syscall - - import ( -+ "internal/bytealg" - "runtime" - "sync" - "unicode/utf16" -@@ -115,12 +116,16 @@ func makeCmdLine(args []string) string { - // the representation required by CreateProcess: a sequence of NUL - // terminated strings followed by a nil. - // Last bytes are two UCS-2 NULs, or four NUL bytes. --func createEnvBlock(envv []string) *uint16 { -+// If any string contains a NUL, it returns (nil, EINVAL). -+func createEnvBlock(envv []string) (*uint16, error) { - if len(envv) == 0 { -- return &utf16.Encode([]rune("\x00\x00"))[0] -+ return &utf16.Encode([]rune("\x00\x00"))[0], nil - } - length := 0 - for _, s := range envv { -+ if bytealg.IndexByteString(s, 0) != -1 { -+ return nil, EINVAL -+ } - length += len(s) + 1 - } - length += 1 -@@ -135,7 +140,7 @@ func createEnvBlock(envv []string) *uint16 { - } - copy(b[i:i+1], []byte{0}) - -- return &utf16.Encode([]rune(string(b)))[0] -+ return &utf16.Encode([]rune(string(b)))[0], nil - } - - func CloseOnExec(fd Handle) { -@@ -400,12 +405,17 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle - } - } - -+ envBlock, err := createEnvBlock(attr.Env) -+ if err != nil { -+ return 0, 0, err -+ } -+ - pi := new(ProcessInformation) - flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT - if sys.Token != 0 { -- err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) -+ err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, envBlock, dirp, &si.StartupInfo, pi) - } else { -- err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, createEnvBlock(attr.Env), dirp, &si.StartupInfo, pi) -+ err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, envBlock, dirp, &si.StartupInfo, pi) - } - if err != nil { - return 0, 0, err --- -2.33.0 - diff --git a/0024-release-branch.go1.18-add-definition-byte-string-cut.patch b/0024-release-branch.go1.18-add-definition-byte-string-cut.patch deleted file mode 100644 index 61de0009d1278751b37df9fee1e8ba1d4fe099c5..0000000000000000000000000000000000000000 --- a/0024-release-branch.go1.18-add-definition-byte-string-cut.patch +++ /dev/null @@ -1,434 +0,0 @@ -From 719a248de7215aeb2ca38e71c0056a777712f1e2 Mon Sep 17 00:00:00 2001 -From: Russ Cox -Date: Tue, 21 Sep 2021 10:59:16 -0400 -Subject: [PATCH] bytes, strings: add Cut - -Using Cut is a clearer way to write the vast majority (>70%) -of existing code that calls Index, IndexByte, IndexRune, and SplitN. -There is more discussion on https://golang.org/issue/46336. - -Fixes #46336. - -Change-Id: Ia418ed7c3706c65bf61e1b2c5baf534cb783e4d3 -Reviewed-on: https://go-review.googlesource.com/c/go/+/351710 -Trust: Russ Cox -Run-TryBot: Russ Cox -TryBot-Result: Go Bot -Reviewed-by: Ian Lance Taylor ---- - src/bytes/bytes.go | 13 ++++ - src/bytes/bytes_test.go | 23 ++++++ - src/bytes/example_test.go | 138 ++++++++++++++++++------------------ - src/strings/example_test.go | 58 +++++++++------ - src/strings/strings.go | 11 +++ - src/strings/strings_test.go | 25 ++++++- - 6 files changed, 178 insertions(+), 90 deletions(-) - -diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go -index ce52649f13..ec9a2eb693 100644 ---- a/src/bytes/bytes.go -+++ b/src/bytes/bytes.go -@@ -1174,3 +1174,16 @@ func Index(s, sep []byte) int { - } - return -1 - } -+ -+// Cut slices s around the first instance of sep, -+// returning the text before and after sep. -+// The found result reports whether sep appears in s. -+// If sep does not appear in s, cut returns s, "", false. -+// -+// Cut returns slices of the original slice s, not copies. -+func Cut(s, sep []byte) (before, after []byte, found bool) { -+ if i := Index(s, sep); i >= 0 { -+ return s[:i], s[i+len(sep):], true -+ } -+ return s, nil, false -+} -diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go -index 544ee46f90..538e613c8e 100644 ---- a/src/bytes/bytes_test.go -+++ b/src/bytes/bytes_test.go -@@ -1565,6 +1565,29 @@ func TestEqualFold(t *testing.T) { - } - } - -+var cutTests = []struct { -+ s, sep string -+ before, after string -+ found bool -+}{ -+ {"abc", "b", "a", "c", true}, -+ {"abc", "a", "", "bc", true}, -+ {"abc", "c", "ab", "", true}, -+ {"abc", "abc", "", "", true}, -+ {"abc", "", "", "abc", true}, -+ {"abc", "d", "abc", "", false}, -+ {"", "d", "", "", false}, -+ {"", "", "", "", true}, -+} -+ -+func TestCut(t *testing.T) { -+ for _, tt := range cutTests { -+ if before, after, found := Cut([]byte(tt.s), []byte(tt.sep)); string(before) != tt.before || string(after) != tt.after || found != tt.found { -+ t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found) -+ } -+ } -+} -+ - func TestBufferGrowNegative(t *testing.T) { - defer func() { - if err := recover(); err == nil { -diff --git a/src/bytes/example_test.go b/src/bytes/example_test.go -index ae93202b57..a1a6c2d292 100644 ---- a/src/bytes/example_test.go -+++ b/src/bytes/example_test.go -@@ -92,36 +92,6 @@ func ExampleCompare_search() { - } - } - --func ExampleTrimSuffix() { -- var b = []byte("Hello, goodbye, etc!") -- b = bytes.TrimSuffix(b, []byte("goodbye, etc!")) -- b = bytes.TrimSuffix(b, []byte("gopher")) -- b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...) -- os.Stdout.Write(b) -- // Output: Hello, world! --} -- --func ExampleTrimPrefix() { -- var b = []byte("Goodbye,, world!") -- b = bytes.TrimPrefix(b, []byte("Goodbye,")) -- b = bytes.TrimPrefix(b, []byte("See ya,")) -- fmt.Printf("Hello%s", b) -- // Output: Hello, world! --} -- --func ExampleFields() { -- fmt.Printf("Fields are: %q", bytes.Fields([]byte(" foo bar baz "))) -- // Output: Fields are: ["foo" "bar" "baz"] --} -- --func ExampleFieldsFunc() { -- f := func(c rune) bool { -- return !unicode.IsLetter(c) && !unicode.IsNumber(c) -- } -- fmt.Printf("Fields are: %q", bytes.FieldsFunc([]byte(" foo1;bar2,baz3..."), f)) -- // Output: Fields are: ["foo1" "bar2" "baz3"] --} -- - func ExampleContains() { - fmt.Println(bytes.Contains([]byte("seafood"), []byte("foo"))) - fmt.Println(bytes.Contains([]byte("seafood"), []byte("bar"))) -@@ -168,6 +138,22 @@ func ExampleCount() { - // 5 - } - -+func ExampleCut() { -+ show := func(s, sep string) { -+ before, after, found := bytes.Cut([]byte(s), []byte(sep)) -+ fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found) -+ } -+ show("Gopher", "Go") -+ show("Gopher", "ph") -+ show("Gopher", "er") -+ show("Gopher", "Badger") -+ // Output: -+ // Cut("Gopher", "Go") = "", "pher", true -+ // Cut("Gopher", "ph") = "Go", "er", true -+ // Cut("Gopher", "er") = "Goph", "", true -+ // Cut("Gopher", "Badger") = "Gopher", "", false -+} -+ - func ExampleEqual() { - fmt.Println(bytes.Equal([]byte("Go"), []byte("Go"))) - fmt.Println(bytes.Equal([]byte("Go"), []byte("C++"))) -@@ -181,6 +167,19 @@ func ExampleEqualFold() { - // Output: true - } - -+func ExampleFields() { -+ fmt.Printf("Fields are: %q", bytes.Fields([]byte(" foo bar baz "))) -+ // Output: Fields are: ["foo" "bar" "baz"] -+} -+ -+func ExampleFieldsFunc() { -+ f := func(c rune) bool { -+ return !unicode.IsLetter(c) && !unicode.IsNumber(c) -+ } -+ fmt.Printf("Fields are: %q", bytes.FieldsFunc([]byte(" foo1;bar2,baz3..."), f)) -+ // Output: Fields are: ["foo1" "bar2" "baz3"] -+} -+ - func ExampleHasPrefix() { - fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("Go"))) - fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("C"))) -@@ -246,6 +245,12 @@ func ExampleIndexRune() { - // -1 - } - -+func ExampleJoin() { -+ s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")} -+ fmt.Printf("%s", bytes.Join(s, []byte(", "))) -+ // Output: foo, bar, baz -+} -+ - func ExampleLastIndex() { - fmt.Println(bytes.Index([]byte("go gopher"), []byte("go"))) - fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("go"))) -@@ -286,10 +291,12 @@ func ExampleLastIndexFunc() { - // -1 - } - --func ExampleJoin() { -- s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")} -- fmt.Printf("%s", bytes.Join(s, []byte(", "))) -- // Output: foo, bar, baz -+func ExampleReader_Len() { -+ fmt.Println(bytes.NewReader([]byte("Hi!")).Len()) -+ fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len()) -+ // Output: -+ // 3 -+ // 16 - } - - func ExampleRepeat() { -@@ -399,20 +406,6 @@ func ExampleTrimFunc() { - // go-gopher! - } - --func ExampleMap() { -- rot13 := func(r rune) rune { -- switch { -- case r >= 'A' && r <= 'Z': -- return 'A' + (r-'A'+13)%26 -- case r >= 'a' && r <= 'z': -- return 'a' + (r-'a'+13)%26 -- } -- return r -- } -- fmt.Printf("%s", bytes.Map(rot13, []byte("'Twas brillig and the slithy gopher..."))) -- // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure... --} -- - func ExampleTrimLeft() { - fmt.Print(string(bytes.TrimLeft([]byte("453gopher8257"), "0123456789"))) - // Output: -@@ -429,11 +422,28 @@ func ExampleTrimLeftFunc() { - // go-gopher!567 - } - -+func ExampleTrimPrefix() { -+ var b = []byte("Goodbye,, world!") -+ b = bytes.TrimPrefix(b, []byte("Goodbye,")) -+ b = bytes.TrimPrefix(b, []byte("See ya,")) -+ fmt.Printf("Hello%s", b) -+ // Output: Hello, world! -+} -+ - func ExampleTrimSpace() { - fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n"))) - // Output: a lone gopher - } - -+func ExampleTrimSuffix() { -+ var b = []byte("Hello, goodbye, etc!") -+ b = bytes.TrimSuffix(b, []byte("goodbye, etc!")) -+ b = bytes.TrimSuffix(b, []byte("gopher")) -+ b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...) -+ os.Stdout.Write(b) -+ // Output: Hello, world! -+} -+ - func ExampleTrimRight() { - fmt.Print(string(bytes.TrimRight([]byte("453gopher8257"), "0123456789"))) - // Output: -@@ -450,21 +460,6 @@ func ExampleTrimRightFunc() { - // 1234go-gopher! - } - --func ExampleToUpper() { -- fmt.Printf("%s", bytes.ToUpper([]byte("Gopher"))) -- // Output: GOPHER --} -- --func ExampleToUpperSpecial() { -- str := []byte("ahoj vývojári golang") -- totitle := bytes.ToUpperSpecial(unicode.AzeriCase, str) -- fmt.Println("Original : " + string(str)) -- fmt.Println("ToUpper : " + string(totitle)) -- // Output: -- // Original : ahoj vývojári golang -- // ToUpper : AHOJ VÝVOJÁRİ GOLANG --} -- - func ExampleToLower() { - fmt.Printf("%s", bytes.ToLower([]byte("Gopher"))) - // Output: gopher -@@ -480,10 +475,17 @@ func ExampleToLowerSpecial() { - // ToLower : ahoj vývojári golang - } - --func ExampleReader_Len() { -- fmt.Println(bytes.NewReader([]byte("Hi!")).Len()) -- fmt.Println(bytes.NewReader([]byte("こんにちは!")).Len()) -+func ExampleToUpper() { -+ fmt.Printf("%s", bytes.ToUpper([]byte("Gopher"))) -+ // Output: GOPHER -+} -+ -+func ExampleToUpperSpecial() { -+ str := []byte("ahoj vývojári golang") -+ totitle := bytes.ToUpperSpecial(unicode.AzeriCase, str) -+ fmt.Println("Original : " + string(str)) -+ fmt.Println("ToUpper : " + string(totitle)) - // Output: -- // 3 -- // 16 -+ // Original : ahoj vývojári golang -+ // ToUpper : AHOJ VÝVOJÁRİ GOLANG - } -diff --git a/src/strings/example_test.go b/src/strings/example_test.go -index 375f9cac65..94aa167f90 100644 ---- a/src/strings/example_test.go -+++ b/src/strings/example_test.go -@@ -10,17 +10,15 @@ import ( - "unicode" - ) - --func ExampleFields() { -- fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz ")) -- // Output: Fields are: ["foo" "bar" "baz"] --} -- --func ExampleFieldsFunc() { -- f := func(c rune) bool { -- return !unicode.IsLetter(c) && !unicode.IsNumber(c) -+func ExampleBuilder() { -+ var b strings.Builder -+ for i := 3; i >= 1; i-- { -+ fmt.Fprintf(&b, "%d...", i) - } -- fmt.Printf("Fields are: %q", strings.FieldsFunc(" foo1;bar2,baz3...", f)) -- // Output: Fields are: ["foo1" "bar2" "baz3"] -+ b.WriteString("ignition") -+ fmt.Println(b.String()) -+ -+ // Output: 3...2...1...ignition - } - - func ExampleCompare() { -@@ -79,11 +77,40 @@ func ExampleCount() { - // 5 - } - -+func ExampleCut() { -+ show := func(s, sep string) { -+ before, after, found := strings.Cut(s, sep) -+ fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found) -+ } -+ show("Gopher", "Go") -+ show("Gopher", "ph") -+ show("Gopher", "er") -+ show("Gopher", "Badger") -+ // Output: -+ // Cut("Gopher", "Go") = "", "pher", true -+ // Cut("Gopher", "ph") = "Go", "er", true -+ // Cut("Gopher", "er") = "Goph", "", true -+ // Cut("Gopher", "Badger") = "Gopher", "", false -+} -+ - func ExampleEqualFold() { - fmt.Println(strings.EqualFold("Go", "go")) - // Output: true - } - -+func ExampleFields() { -+ fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz ")) -+ // Output: Fields are: ["foo" "bar" "baz"] -+} -+ -+func ExampleFieldsFunc() { -+ f := func(c rune) bool { -+ return !unicode.IsLetter(c) && !unicode.IsNumber(c) -+ } -+ fmt.Printf("Fields are: %q", strings.FieldsFunc(" foo1;bar2,baz3...", f)) -+ // Output: Fields are: ["foo1" "bar2" "baz3"] -+} -+ - func ExampleHasPrefix() { - fmt.Println(strings.HasPrefix("Gopher", "Go")) - fmt.Println(strings.HasPrefix("Gopher", "C")) -@@ -370,14 +397,3 @@ func ExampleTrimRightFunc() { - })) - // Output: ¡¡¡Hello, Gophers - } -- --func ExampleBuilder() { -- var b strings.Builder -- for i := 3; i >= 1; i-- { -- fmt.Fprintf(&b, "%d...", i) -- } -- b.WriteString("ignition") -- fmt.Println(b.String()) -- -- // Output: 3...2...1...ignition --} -diff --git a/src/strings/strings.go b/src/strings/strings.go -index b429735fea..0c94395311 100644 ---- a/src/strings/strings.go -+++ b/src/strings/strings.go -@@ -1100,3 +1100,14 @@ func Index(s, substr string) int { - } - return -1 - } -+ -+// Cut slices s around the first instance of sep, -+// returning the text before and after sep. -+// The found result reports whether sep appears in s. -+// If sep does not appear in s, cut returns s, "", false. -+func Cut(s, sep string) (before, after string, found bool) { -+ if i := Index(s, sep); i >= 0 { -+ return s[:i], s[i+len(sep):], true -+ } -+ return s, "", false -+} -diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go -index 09e5b27cc3..5a02ba496f 100644 ---- a/src/strings/strings_test.go -+++ b/src/strings/strings_test.go -@@ -1577,7 +1577,30 @@ var CountTests = []struct { - func TestCount(t *testing.T) { - for _, tt := range CountTests { - if num := Count(tt.s, tt.sep); num != tt.num { -- t.Errorf("Count(\"%s\", \"%s\") = %d, want %d", tt.s, tt.sep, num, tt.num) -+ t.Errorf("Count(%q, %q) = %d, want %d", tt.s, tt.sep, num, tt.num) -+ } -+ } -+} -+ -+var cutTests = []struct { -+ s, sep string -+ before, after string -+ found bool -+}{ -+ {"abc", "b", "a", "c", true}, -+ {"abc", "a", "", "bc", true}, -+ {"abc", "c", "ab", "", true}, -+ {"abc", "abc", "", "", true}, -+ {"abc", "", "", "abc", true}, -+ {"abc", "d", "abc", "", false}, -+ {"", "d", "", "", false}, -+ {"", "", "", "", true}, -+} -+ -+func TestCut(t *testing.T) { -+ for _, tt := range cutTests { -+ if before, after, found := Cut(tt.s, tt.sep); before != tt.before || after != tt.after || found != tt.found { -+ t.Errorf("Cut(%q, %q) = %q, %q, %v, want %q, %q, %v", tt.s, tt.sep, before, after, found, tt.before, tt.after, tt.found) - } - } - } --- -2.21.0 - diff --git a/0025-release-branch.go1.17-crypto-elliptic-make-IsOnCurve.patch b/0025-release-branch.go1.17-crypto-elliptic-make-IsOnCurve.patch deleted file mode 100644 index aad114c82a844bf123da84998a20f816e3d04e51..0000000000000000000000000000000000000000 --- a/0025-release-branch.go1.17-crypto-elliptic-make-IsOnCurve.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 041fa43ad6669ac10ccdcdd8f47653897c592dfb Mon Sep 17 00:00:00 2001 -From: Filippo Valsorda -Date: Wed, 2 Feb 2022 09:14:57 -0800 -Subject: [PATCH] [release-branch.go1.17] crypto/elliptic: make IsOnCurve - return false for invalid field elements - -Updates #50974 -Fixes #50978 -Fixes CVE-2022-23806 - -Change-Id: I0201c2c88f13dd82910985a495973f1683af9259 -Reviewed-on: https://go-review.googlesource.com/c/go/+/382854 -Trust: Filippo Valsorda -Run-TryBot: Filippo Valsorda -Reviewed-by: Katie Hockman -Trust: Katie Hockman -TryBot-Result: Gopher Robot - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/382854 ---- - src/crypto/elliptic/elliptic.go | 5 +++ - src/crypto/elliptic/elliptic_test.go | 55 ++++++++++++++++++++++++++++ - src/crypto/elliptic/p224.go | 5 +++ - src/crypto/elliptic/p521.go | 5 +++ - 4 files changed, 70 insertions(+) - -diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go -index f072960bfed..b84339ec1c2 100644 ---- a/src/crypto/elliptic/elliptic.go -+++ b/src/crypto/elliptic/elliptic.go -@@ -86,6 +86,11 @@ func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool { - return specific.IsOnCurve(x, y) - } - -+ if x.Sign() < 0 || x.Cmp(curve.P) >= 0 || -+ y.Sign() < 0 || y.Cmp(curve.P) >= 0 { -+ return false -+ } -+ - // y² = x³ - 3x + b - y2 := new(big.Int).Mul(y, y) - y2.Mod(y2, curve.P) -diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go -index 183861a54b5..3fe53c5f332 100644 ---- a/src/crypto/elliptic/elliptic_test.go -+++ b/src/crypto/elliptic/elliptic_test.go -@@ -174,6 +174,61 @@ func testUnmarshalToLargeCoordinates(t *testing.T, curve Curve) { - } - } - -+// TestInvalidCoordinates tests big.Int values that are not valid field elements -+// (negative or bigger than P). They are expected to return false from -+// IsOnCurve, all other behavior is undefined. -+func TestInvalidCoordinates(t *testing.T) { -+ testAllCurves(t, testInvalidCoordinates) -+} -+ -+func testInvalidCoordinates(t *testing.T, curve Curve) { -+ checkIsOnCurveFalse := func(name string, x, y *big.Int) { -+ if curve.IsOnCurve(x, y) { -+ t.Errorf("IsOnCurve(%s) unexpectedly returned true", name) -+ } -+ } -+ -+ p := curve.Params().P -+ _, x, y, _ := GenerateKey(curve, rand.Reader) -+ xx, yy := new(big.Int), new(big.Int) -+ -+ // Check if the sign is getting dropped. -+ xx.Neg(x) -+ checkIsOnCurveFalse("-x, y", xx, y) -+ yy.Neg(y) -+ checkIsOnCurveFalse("x, -y", x, yy) -+ -+ // Check if negative values are reduced modulo P. -+ xx.Sub(x, p) -+ checkIsOnCurveFalse("x-P, y", xx, y) -+ yy.Sub(y, p) -+ checkIsOnCurveFalse("x, y-P", x, yy) -+ -+ // Check if positive values are reduced modulo P. -+ xx.Add(x, p) -+ checkIsOnCurveFalse("x+P, y", xx, y) -+ yy.Add(y, p) -+ checkIsOnCurveFalse("x, y+P", x, yy) -+ -+ // Check if the overflow is dropped. -+ xx.Add(x, new(big.Int).Lsh(big.NewInt(1), 535)) -+ checkIsOnCurveFalse("x+2⁵³⁵, y", xx, y) -+ yy.Add(y, new(big.Int).Lsh(big.NewInt(1), 535)) -+ checkIsOnCurveFalse("x, y+2⁵³⁵", x, yy) -+ -+ // Check if P is treated like zero (if possible). -+ // y^2 = x^3 - 3x + B -+ // y = mod_sqrt(x^3 - 3x + B) -+ // y = mod_sqrt(B) if x = 0 -+ // If there is no modsqrt, there is no point with x = 0, can't test x = P. -+ if yy := new(big.Int).ModSqrt(curve.Params().B, p); yy != nil { -+ if !curve.IsOnCurve(big.NewInt(0), yy) { -+ t.Fatal("(0, mod_sqrt(B)) is not on the curve?") -+ } -+ checkIsOnCurveFalse("P, y", p, yy) -+ } -+} -+ - func TestMarshalCompressed(t *testing.T) { - t.Run("P-256/03", func(t *testing.T) { - data, _ := hex.DecodeString("031e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79") -diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go -index 8c760214642..ff5c8344522 100644 ---- a/src/crypto/elliptic/p224.go -+++ b/src/crypto/elliptic/p224.go -@@ -48,6 +48,11 @@ func (curve p224Curve) Params() *CurveParams { - } - - func (curve p224Curve) IsOnCurve(bigX, bigY *big.Int) bool { -+ if bigX.Sign() < 0 || bigX.Cmp(curve.P) >= 0 || -+ bigY.Sign() < 0 || bigY.Cmp(curve.P) >= 0 { -+ return false -+ } -+ - var x, y p224FieldElement - p224FromBig(&x, bigX) - p224FromBig(&y, bigY) -diff --git a/src/crypto/elliptic/p521.go b/src/crypto/elliptic/p521.go -index 3d355943ec7..587991e31bf 100644 ---- a/src/crypto/elliptic/p521.go -+++ b/src/crypto/elliptic/p521.go -@@ -32,6 +32,11 @@ func (curve p521Curve) Params() *CurveParams { - } - - func (curve p521Curve) IsOnCurve(x, y *big.Int) bool { -+ if x.Sign() < 0 || x.Cmp(curve.P) >= 0 || -+ y.Sign() < 0 || y.Cmp(curve.P) >= 0 { -+ return false -+ } -+ - x1 := bigIntToFiatP521(x) - y1 := bigIntToFiatP521(y) - b := bigIntToFiatP521(curve.B) // TODO: precompute this value. --- -2.30.0 - diff --git a/0026-release-branch.go1.17-cmd-go-internal-modfetch-do-no.patch b/0026-release-branch.go1.17-cmd-go-internal-modfetch-do-no.patch deleted file mode 100644 index 59ab52a905f7771a4b5378318a22ce248732576d..0000000000000000000000000000000000000000 --- a/0026-release-branch.go1.17-cmd-go-internal-modfetch-do-no.patch +++ /dev/null @@ -1,749 +0,0 @@ -From 8d5747c8fdc3d952696505562e7804e8e5fa0ab2 Mon Sep 17 00:00:00 2001 -From: "Bryan C. Mills" -Date: Thu, 13 Jan 2022 15:38:14 -0500 -Subject: [PATCH 2/6] [release-branch.go1.17] cmd/go/internal/modfetch: do not - short-circuit canonical versions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since at least CL 121857, the conversion logic in -(*modfetch).codeRepo.Stat has had a short-circuit to use the version -requested by the caller if it successfully resolves and is already -canonical. - -However, we should not use that version if it refers to a branch -instead of a tag, because branches (unlike tags) usually do not refer -to a single, stable release: a branch named "v1.0.0" may be for the -development of the v1.0.0 release, or for the development of patches -based on v1.0.0, but only one commit (perhaps at the end of that -branch — but possibly not even written yet!) can be that specific -version. - -We already have some logic to prefer tags that are semver-equivalent -to the version requested by the caller. That more general case -suffices for exact equality too — so we can eliminate the -special-case, fixing the bug and (happily!) also somewhat simplifying -the code. - -Updates #35671 -Fixes #50687 -Fixes CVE-2022-23773 - -Change-Id: I2fd290190b8a99a580deec7e26d15659b58a50b0 -Reviewed-on: https://go-review.googlesource.com/c/go/+/378400 -Trust: Bryan Mills -Run-TryBot: Bryan Mills -Reviewed-by: Russ Cox -TryBot-Result: Gopher Robot -(cherry picked from commit fa4d9b8e2bc2612960c80474fca83a4c85a974eb) -Reviewed-on: https://go-review.googlesource.com/c/go/+/382835 - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/382835 ---- - src/cmd/go/internal/modfetch/coderepo.go | 216 ++++++------- - src/cmd/go/internal/modfetch/coderepo_test.go | 301 ++++++++++-------- - .../testdata/script/mod_invalid_version.txt | 10 +- - 3 files changed, 277 insertions(+), 250 deletions(-) - -diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go -index dfef9f73c27..0ee707025d0 100644 ---- a/src/cmd/go/internal/modfetch/coderepo.go -+++ b/src/cmd/go/internal/modfetch/coderepo.go -@@ -298,16 +298,13 @@ func (r *codeRepo) Latest() (*RevInfo, error) { - // If statVers is a valid module version, it is used for the Version field. - // Otherwise, the Version is derived from the passed-in info and recent tags. - func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) { -- info2 := &RevInfo{ -- Name: info.Name, -- Short: info.Short, -- Time: info.Time, -- } -- - // If this is a plain tag (no dir/ prefix) - // and the module path is unversioned, - // and if the underlying file tree has no go.mod, - // then allow using the tag with a +incompatible suffix. -+ // -+ // (If the version is +incompatible, then the go.mod file must not exist: -+ // +incompatible is not an ongoing opt-out from semantic import versioning.) - var canUseIncompatible func() bool - canUseIncompatible = func() bool { - var ok bool -@@ -321,19 +318,12 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e - return ok - } - -- invalidf := func(format string, args ...interface{}) error { -- return &module.ModuleError{ -- Path: r.modPath, -- Err: &module.InvalidVersionError{ -- Version: info2.Version, -- Err: fmt.Errorf(format, args...), -- }, -- } -- } -- -- // checkGoMod verifies that the go.mod file for the module exists or does not -- // exist as required by info2.Version and the module path represented by r. -- checkGoMod := func() (*RevInfo, error) { -+ // checkCanonical verifies that the canonical version v is compatible with the -+ // module path represented by r, adding a "+incompatible" suffix if needed. -+ // -+ // If statVers is also canonical, checkCanonical also verifies that v is -+ // either statVers or statVers with the added "+incompatible" suffix. -+ checkCanonical := func(v string) (*RevInfo, error) { - // If r.codeDir is non-empty, then the go.mod file must exist: the module - // author — not the module consumer, — gets to decide how to carve up the repo - // into modules. -@@ -344,73 +334,91 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e - // r.findDir verifies both of these conditions. Execute it now so that - // r.Stat will correctly return a notExistError if the go.mod location or - // declared module path doesn't match. -- _, _, _, err := r.findDir(info2.Version) -+ _, _, _, err := r.findDir(v) - if err != nil { - // TODO: It would be nice to return an error like "not a module". - // Right now we return "missing go.mod", which is a little confusing. - return nil, &module.ModuleError{ - Path: r.modPath, - Err: &module.InvalidVersionError{ -- Version: info2.Version, -+ Version: v, - Err: notExistError{err: err}, - }, - } - } - -- // If the version is +incompatible, then the go.mod file must not exist: -- // +incompatible is not an ongoing opt-out from semantic import versioning. -- if strings.HasSuffix(info2.Version, "+incompatible") { -- if !canUseIncompatible() { -+ invalidf := func(format string, args ...interface{}) error { -+ return &module.ModuleError{ -+ Path: r.modPath, -+ Err: &module.InvalidVersionError{ -+ Version: v, -+ Err: fmt.Errorf(format, args...), -+ }, -+ } -+ } -+ -+ // Add the +incompatible suffix if needed or requested explicitly, and -+ // verify that its presence or absence is appropriate for this version -+ // (which depends on whether it has an explicit go.mod file). -+ -+ if v == strings.TrimSuffix(statVers, "+incompatible") { -+ v = statVers -+ } -+ base := strings.TrimSuffix(v, "+incompatible") -+ var errIncompatible error -+ if !module.MatchPathMajor(base, r.pathMajor) { -+ if canUseIncompatible() { -+ v = base + "+incompatible" -+ } else { - if r.pathMajor != "" { -- return nil, invalidf("+incompatible suffix not allowed: module path includes a major version suffix, so major version must match") -+ errIncompatible = invalidf("module path includes a major version suffix, so major version must match") - } else { -- return nil, invalidf("+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required") -+ errIncompatible = invalidf("module contains a go.mod file, so module path must match major version (%q)", path.Join(r.pathPrefix, semver.Major(v))) - } - } -+ } else if strings.HasSuffix(v, "+incompatible") { -+ errIncompatible = invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(v)) -+ } - -- if err := module.CheckPathMajor(strings.TrimSuffix(info2.Version, "+incompatible"), r.pathMajor); err == nil { -- return nil, invalidf("+incompatible suffix not allowed: major version %s is compatible", semver.Major(info2.Version)) -+ if statVers != "" && statVers == module.CanonicalVersion(statVers) { -+ // Since the caller-requested version is canonical, it would be very -+ // confusing to resolve it to anything but itself, possibly with a -+ // "+incompatible" suffix. Error out explicitly. -+ if statBase := strings.TrimSuffix(statVers, "+incompatible"); statBase != base { -+ return nil, &module.ModuleError{ -+ Path: r.modPath, -+ Err: &module.InvalidVersionError{ -+ Version: statVers, -+ Err: fmt.Errorf("resolves to version %v (%s is not a tag)", v, statBase), -+ }, -+ } - } - } - -- return info2, nil -+ if errIncompatible != nil { -+ return nil, errIncompatible -+ } -+ -+ return &RevInfo{ -+ Name: info.Name, -+ Short: info.Short, -+ Time: info.Time, -+ Version: v, -+ }, nil - } - - // Determine version. -- // -- // If statVers is canonical, then the original call was repo.Stat(statVers). -- // Since the version is canonical, we must not resolve it to anything but -- // itself, possibly with a '+incompatible' annotation: we do not need to do -- // the work required to look for an arbitrary pseudo-version. -- if statVers != "" && statVers == module.CanonicalVersion(statVers) { -- info2.Version = statVers -- -- if module.IsPseudoVersion(info2.Version) { -- if err := r.validatePseudoVersion(info, info2.Version); err != nil { -- return nil, err -- } -- return checkGoMod() -- } - -- if err := module.CheckPathMajor(info2.Version, r.pathMajor); err != nil { -- if canUseIncompatible() { -- info2.Version += "+incompatible" -- return checkGoMod() -- } else { -- if vErr, ok := err.(*module.InvalidVersionError); ok { -- // We're going to describe why the version is invalid in more detail, -- // so strip out the existing “invalid version” wrapper. -- err = vErr.Err -- } -- return nil, invalidf("module contains a go.mod file, so major version must be compatible: %v", err) -- } -+ if module.IsPseudoVersion(statVers) { -+ if err := r.validatePseudoVersion(info, statVers); err != nil { -+ return nil, err - } -- -- return checkGoMod() -+ return checkCanonical(statVers) - } - -- // statVers is empty or non-canonical, so we need to resolve it to a canonical -- // version or pseudo-version. -+ // statVers is not a pseudo-version, so we need to either resolve it to a -+ // canonical version or verify that it is already a canonical tag -+ // (not a branch). - - // Derive or verify a version from a code repo tag. - // Tag must have a prefix matching codeDir. -@@ -441,71 +449,62 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e - if v == "" || !strings.HasPrefix(trimmed, v) { - return "", false // Invalid or incomplete version (just vX or vX.Y). - } -- if isRetracted(v) { -- return "", false -- } - if v == trimmed { - tagIsCanonical = true - } -- -- if err := module.CheckPathMajor(v, r.pathMajor); err != nil { -- if canUseIncompatible() { -- return v + "+incompatible", tagIsCanonical -- } -- return "", false -- } -- - return v, tagIsCanonical - } - - // If the VCS gave us a valid version, use that. - if v, tagIsCanonical := tagToVersion(info.Version); tagIsCanonical { -- info2.Version = v -- return checkGoMod() -+ if info, err := checkCanonical(v); err == nil { -+ return info, err -+ } - } - - // Look through the tags on the revision for either a usable canonical version - // or an appropriate base for a pseudo-version. -- var pseudoBase string -+ var ( -+ highestCanonical string -+ pseudoBase string -+ ) - for _, pathTag := range info.Tags { - v, tagIsCanonical := tagToVersion(pathTag) -- if tagIsCanonical { -- if statVers != "" && semver.Compare(v, statVers) == 0 { -- // The user requested a non-canonical version, but the tag for the -- // canonical equivalent refers to the same revision. Use it. -- info2.Version = v -- return checkGoMod() -+ if statVers != "" && semver.Compare(v, statVers) == 0 { -+ // The tag is equivalent to the version requested by the user. -+ if tagIsCanonical { -+ // This tag is the canonical form of the requested version, -+ // not some other form with extra build metadata. -+ // Use this tag so that the resolved version will match exactly. -+ // (If it isn't actually allowed, we'll error out in checkCanonical.) -+ return checkCanonical(v) - } else { -- // Save the highest canonical tag for the revision. If we don't find a -- // better match, we'll use it as the canonical version. -+ // The user explicitly requested something equivalent to this tag. We -+ // can't use the version from the tag directly: since the tag is not -+ // canonical, it could be ambiguous. For example, tags v0.0.1+a and -+ // v0.0.1+b might both exist and refer to different revisions. - // -- // NOTE: Do not replace this with semver.Max. Despite the name, -- // semver.Max *also* canonicalizes its arguments, which uses -- // semver.Canonical instead of module.CanonicalVersion and thereby -- // strips our "+incompatible" suffix. -- if semver.Compare(info2.Version, v) < 0 { -- info2.Version = v -- } -+ // The tag is otherwise valid for the module, so we can at least use it as -+ // the base of an unambiguous pseudo-version. -+ // -+ // If multiple tags match, tagToVersion will canonicalize them to the same -+ // base version. -+ pseudoBase = v -+ } -+ } -+ // Save the highest non-retracted canonical tag for the revision. -+ // If we don't find a better match, we'll use it as the canonical version. -+ if tagIsCanonical && semver.Compare(highestCanonical, v) < 0 && !isRetracted(v) { -+ if module.MatchPathMajor(v, r.pathMajor) || canUseIncompatible() { -+ highestCanonical = v - } -- } else if v != "" && semver.Compare(v, statVers) == 0 { -- // The user explicitly requested something equivalent to this tag. We -- // can't use the version from the tag directly: since the tag is not -- // canonical, it could be ambiguous. For example, tags v0.0.1+a and -- // v0.0.1+b might both exist and refer to different revisions. -- // -- // The tag is otherwise valid for the module, so we can at least use it as -- // the base of an unambiguous pseudo-version. -- // -- // If multiple tags match, tagToVersion will canonicalize them to the same -- // base version. -- pseudoBase = v - } - } - -- // If we found any canonical tag for the revision, return it. -+ // If we found a valid canonical tag for the revision, return it. - // Even if we found a good pseudo-version base, a canonical version is better. -- if info2.Version != "" { -- return checkGoMod() -+ if highestCanonical != "" { -+ return checkCanonical(highestCanonical) - } - - // Find the highest tagged version in the revision's history, subject to -@@ -528,11 +527,10 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e - tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v0")) - } - } -- pseudoBase, _ = tagToVersion(tag) // empty if the tag is invalid -+ pseudoBase, _ = tagToVersion(tag) - } - -- info2.Version = module.PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short) -- return checkGoMod() -+ return checkCanonical(module.PseudoVersion(r.pseudoMajor, pseudoBase, info.Time, info.Short)) - } - - // validatePseudoVersion checks that version has a major version compatible with -@@ -556,10 +554,6 @@ func (r *codeRepo) validatePseudoVersion(info *codehost.RevInfo, version string) - } - }() - -- if err := module.CheckPathMajor(version, r.pathMajor); err != nil { -- return err -- } -- - rev, err := module.PseudoVersionRev(version) - if err != nil { - return err -diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go -index 02e399f3525..d98ea87da2c 100644 ---- a/src/cmd/go/internal/modfetch/coderepo_test.go -+++ b/src/cmd/go/internal/modfetch/coderepo_test.go -@@ -418,171 +418,204 @@ var codeRepoTests = []codeRepoTest{ - zipSum: "h1:JItBZ+gwA5WvtZEGEbuDL4lUttGtLrs53lmdurq3bOg=", - zipFileHash: "9ea9ae1673cffcc44b7fdd3cc89953d68c102449b46c982dbf085e4f2e394da5", - }, -+ { -+ // Git branch with a semver name, +incompatible version, and no go.mod file. -+ vcs: "git", -+ path: "vcs-test.golang.org/go/mod/gitrepo1", -+ rev: "v2.3.4+incompatible", -+ err: `resolves to version v2.0.1+incompatible (v2.3.4 is not a tag)`, -+ }, -+ { -+ // Git branch with a semver name, matching go.mod file, and compatible version. -+ vcs: "git", -+ path: "vcs-test.golang.org/git/semver-branch.git", -+ rev: "v1.0.0", -+ err: `resolves to version v0.1.1-0.20220202191944-09c4d8f6938c (v1.0.0 is not a tag)`, -+ }, -+ { -+ // Git branch with a semver name, matching go.mod file, and disallowed +incompatible version. -+ // The version/tag mismatch takes precedence over the +incompatible mismatched. -+ vcs: "git", -+ path: "vcs-test.golang.org/git/semver-branch.git", -+ rev: "v2.0.0+incompatible", -+ err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`, -+ }, -+ { -+ // Git branch with a semver name, matching go.mod file, and mismatched version. -+ // The version/tag mismatch takes precedence over the +incompatible mismatched. -+ vcs: "git", -+ path: "vcs-test.golang.org/git/semver-branch.git", -+ rev: "v2.0.0", -+ err: `resolves to version v0.1.0 (v2.0.0 is not a tag)`, -+ }, -+ { -+ // v3.0.0-devel is the same as tag v4.0.0-beta.1, but v4.0.0-beta.1 would -+ // not be allowed because it is incompatible and a go.mod file exists. -+ // The error message should refer to a valid pseudo-version, not the -+ // unusable semver tag. -+ vcs: "git", -+ path: "vcs-test.golang.org/git/semver-branch.git", -+ rev: "v3.0.0-devel", -+ err: `resolves to version v0.1.1-0.20220203155313-d59622f6e4d7 (v3.0.0-devel is not a tag)`, -+ }, - } - - func TestCodeRepo(t *testing.T) { - testenv.MustHaveExternalNetwork(t) -+ tmpdir := t.TempDir() - -- tmpdir, err := os.MkdirTemp("", "modfetch-test-") -- if err != nil { -- t.Fatal(err) -- } -- defer os.RemoveAll(tmpdir) -+ for _, tt := range codeRepoTests { -+ f := func(tt codeRepoTest) func(t *testing.T) { -+ return func(t *testing.T) { -+ t.Parallel() -+ if tt.vcs != "mod" { -+ testenv.MustHaveExecPath(t, tt.vcs) -+ } - -- t.Run("parallel", func(t *testing.T) { -- for _, tt := range codeRepoTests { -- f := func(tt codeRepoTest) func(t *testing.T) { -- return func(t *testing.T) { -- t.Parallel() -- if tt.vcs != "mod" { -- testenv.MustHaveExecPath(t, tt.vcs) -- } -+ repo := Lookup("direct", tt.path) - -- repo := Lookup("direct", tt.path) -+ if tt.mpath == "" { -+ tt.mpath = tt.path -+ } -+ if mpath := repo.ModulePath(); mpath != tt.mpath { -+ t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath) -+ } - -- if tt.mpath == "" { -- tt.mpath = tt.path -- } -- if mpath := repo.ModulePath(); mpath != tt.mpath { -- t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath) -+ info, err := repo.Stat(tt.rev) -+ if err != nil { -+ if tt.err != "" { -+ if !strings.Contains(err.Error(), tt.err) { -+ t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err) -+ } -+ return - } -+ t.Fatalf("repo.Stat(%q): %v", tt.rev, err) -+ } -+ if tt.err != "" { -+ t.Errorf("repo.Stat(%q): success, wanted error", tt.rev) -+ } -+ if info.Version != tt.version { -+ t.Errorf("info.Version = %q, want %q", info.Version, tt.version) -+ } -+ if info.Name != tt.name { -+ t.Errorf("info.Name = %q, want %q", info.Name, tt.name) -+ } -+ if info.Short != tt.short { -+ t.Errorf("info.Short = %q, want %q", info.Short, tt.short) -+ } -+ if !info.Time.Equal(tt.time) { -+ t.Errorf("info.Time = %v, want %v", info.Time, tt.time) -+ } - -- info, err := repo.Stat(tt.rev) -- if err != nil { -- if tt.err != "" { -- if !strings.Contains(err.Error(), tt.err) { -- t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err) -- } -- return -+ if tt.gomod != "" || tt.gomodErr != "" { -+ data, err := repo.GoMod(tt.version) -+ if err != nil && tt.gomodErr == "" { -+ t.Errorf("repo.GoMod(%q): %v", tt.version, err) -+ } else if err != nil && tt.gomodErr != "" { -+ if err.Error() != tt.gomodErr { -+ t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr) - } -- t.Fatalf("repo.Stat(%q): %v", tt.rev, err) -- } -- if tt.err != "" { -- t.Errorf("repo.Stat(%q): success, wanted error", tt.rev) -- } -- if info.Version != tt.version { -- t.Errorf("info.Version = %q, want %q", info.Version, tt.version) -+ } else if tt.gomodErr != "" { -+ t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr) -+ } else if string(data) != tt.gomod { -+ t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod) - } -- if info.Name != tt.name { -- t.Errorf("info.Name = %q, want %q", info.Name, tt.name) -- } -- if info.Short != tt.short { -- t.Errorf("info.Short = %q, want %q", info.Short, tt.short) -+ } -+ -+ needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "") -+ if tt.zip != nil || tt.zipErr != "" || needHash { -+ f, err := os.CreateTemp(tmpdir, tt.version+".zip.") -+ if err != nil { -+ t.Fatalf("os.CreateTemp: %v", err) - } -- if !info.Time.Equal(tt.time) { -- t.Errorf("info.Time = %v, want %v", info.Time, tt.time) -+ zipfile := f.Name() -+ defer func() { -+ f.Close() -+ os.Remove(zipfile) -+ }() -+ -+ var w io.Writer -+ var h hash.Hash -+ if needHash { -+ h = sha256.New() -+ w = io.MultiWriter(f, h) -+ } else { -+ w = f - } -- -- if tt.gomod != "" || tt.gomodErr != "" { -- data, err := repo.GoMod(tt.version) -- if err != nil && tt.gomodErr == "" { -- t.Errorf("repo.GoMod(%q): %v", tt.version, err) -- } else if err != nil && tt.gomodErr != "" { -- if err.Error() != tt.gomodErr { -- t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomodErr) -+ err = repo.Zip(w, tt.version) -+ f.Close() -+ if err != nil { -+ if tt.zipErr != "" { -+ if err.Error() == tt.zipErr { -+ return - } -- } else if tt.gomodErr != "" { -- t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomodErr) -- } else if string(data) != tt.gomod { -- t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod) -+ t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr) - } -+ t.Fatalf("repo.Zip(%q): %v", tt.version, err) -+ } -+ if tt.zipErr != "" { -+ t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr) - } - -- needHash := !testing.Short() && (tt.zipFileHash != "" || tt.zipSum != "") -- if tt.zip != nil || tt.zipErr != "" || needHash { -- f, err := os.CreateTemp(tmpdir, tt.version+".zip.") -+ if tt.zip != nil { -+ prefix := tt.path + "@" + tt.version + "/" -+ z, err := zip.OpenReader(zipfile) - if err != nil { -- t.Fatalf("os.CreateTemp: %v", err) -+ t.Fatalf("open zip %s: %v", zipfile, err) - } -- zipfile := f.Name() -- defer func() { -- f.Close() -- os.Remove(zipfile) -- }() -- -- var w io.Writer -- var h hash.Hash -- if needHash { -- h = sha256.New() -- w = io.MultiWriter(f, h) -- } else { -- w = f -- } -- err = repo.Zip(w, tt.version) -- f.Close() -- if err != nil { -- if tt.zipErr != "" { -- if err.Error() == tt.zipErr { -- return -- } -- t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.zipErr) -+ var names []string -+ for _, file := range z.File { -+ if !strings.HasPrefix(file.Name, prefix) { -+ t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix) -+ continue - } -- t.Fatalf("repo.Zip(%q): %v", tt.version, err) -- } -- if tt.zipErr != "" { -- t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.zipErr) -+ names = append(names, file.Name[len(prefix):]) - } -- -- if tt.zip != nil { -- prefix := tt.path + "@" + tt.version + "/" -- z, err := zip.OpenReader(zipfile) -- if err != nil { -- t.Fatalf("open zip %s: %v", zipfile, err) -- } -- var names []string -- for _, file := range z.File { -- if !strings.HasPrefix(file.Name, prefix) { -- t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix) -- continue -- } -- names = append(names, file.Name[len(prefix):]) -- } -- z.Close() -- if !reflect.DeepEqual(names, tt.zip) { -- t.Fatalf("zip = %v\nwant %v\n", names, tt.zip) -- } -+ z.Close() -+ if !reflect.DeepEqual(names, tt.zip) { -+ t.Fatalf("zip = %v\nwant %v\n", names, tt.zip) - } -+ } - -- if needHash { -- sum, err := dirhash.HashZip(zipfile, dirhash.Hash1) -- if err != nil { -- t.Errorf("repo.Zip(%q): %v", tt.version, err) -- } else if sum != tt.zipSum { -- t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum) -- } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash { -- t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash) -- } -+ if needHash { -+ sum, err := dirhash.HashZip(zipfile, dirhash.Hash1) -+ if err != nil { -+ t.Errorf("repo.Zip(%q): %v", tt.version, err) -+ } else if sum != tt.zipSum { -+ t.Errorf("repo.Zip(%q): got file with sum %q, want %q", tt.version, sum, tt.zipSum) -+ } else if zipFileHash := hex.EncodeToString(h.Sum(nil)); zipFileHash != tt.zipFileHash { -+ t.Errorf("repo.Zip(%q): got file with hash %q, want %q (but content has correct sum)", tt.version, zipFileHash, tt.zipFileHash) - } - } - } - } -- t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt)) -- if strings.HasPrefix(tt.path, vgotest1git) { -- for vcs, alt := range altVgotests { -- altTest := tt -- altTest.vcs = vcs -- altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git) -- if strings.HasPrefix(altTest.mpath, vgotest1git) { -- altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git) -- } -- var m map[string]string -- if alt == vgotest1hg { -- m = hgmap -- } -- altTest.version = remap(altTest.version, m) -- altTest.name = remap(altTest.name, m) -- altTest.short = remap(altTest.short, m) -- altTest.rev = remap(altTest.rev, m) -- altTest.err = remap(altTest.err, m) -- altTest.gomodErr = remap(altTest.gomodErr, m) -- altTest.zipErr = remap(altTest.zipErr, m) -- altTest.zipSum = "" -- altTest.zipFileHash = "" -- t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest)) -+ } -+ t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f(tt)) -+ if strings.HasPrefix(tt.path, vgotest1git) { -+ for vcs, alt := range altVgotests { -+ altTest := tt -+ altTest.vcs = vcs -+ altTest.path = alt + strings.TrimPrefix(altTest.path, vgotest1git) -+ if strings.HasPrefix(altTest.mpath, vgotest1git) { -+ altTest.mpath = alt + strings.TrimPrefix(altTest.mpath, vgotest1git) -+ } -+ var m map[string]string -+ if alt == vgotest1hg { -+ m = hgmap - } -+ altTest.version = remap(altTest.version, m) -+ altTest.name = remap(altTest.name, m) -+ altTest.short = remap(altTest.short, m) -+ altTest.rev = remap(altTest.rev, m) -+ altTest.err = remap(altTest.err, m) -+ altTest.gomodErr = remap(altTest.gomodErr, m) -+ altTest.zipErr = remap(altTest.zipErr, m) -+ altTest.zipSum = "" -+ altTest.zipFileHash = "" -+ t.Run(strings.ReplaceAll(altTest.path, "/", "_")+"/"+altTest.rev, f(altTest)) - } - } -- }) -+ } - } - - var hgmap = map[string]string{ -diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt -index 6846a792a5d..d16991dd416 100644 ---- a/src/cmd/go/testdata/script/mod_invalid_version.txt -+++ b/src/cmd/go/testdata/script/mod_invalid_version.txt -@@ -194,10 +194,10 @@ cp go.mod.orig go.mod - go mod edit -require github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d+incompatible - cd outside - ! go list -m github.com/pierrec/lz4 --stderr 'go list -m: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' -+stderr '^go list -m: example.com@v0.0.0 requires\n\tgithub.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' - cd .. - ! go list -m github.com/pierrec/lz4 --stderr 'github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' -+stderr '^go list -m: github.com/pierrec/lz4@v2.0.9-0.20190209155647-9a39efadad3d\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' - - # A +incompatible pseudo-version is valid for a revision of the module - # that lacks a go.mod file. -@@ -222,7 +222,7 @@ stdout 'github.com/pierrec/lz4 v2.0.5\+incompatible' - # not resolve to a pseudo-version with a different major version. - cp go.mod.orig go.mod - ! go get -d github.com/pierrec/lz4@v2.0.8 --stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2' -+stderr 'go get: github.com/pierrec/lz4@v2.0.8: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' - - # An invalid +incompatible suffix for a canonical version should error out, - # not resolve to a pseudo-version. -@@ -233,10 +233,10 @@ cp go.mod.orig go.mod - go mod edit -require github.com/pierrec/lz4@v2.0.8+incompatible - cd outside - ! go list -m github.com/pierrec/lz4 --stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' -+stderr '^go list -m: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' - cd .. - ! go list -m github.com/pierrec/lz4 --stderr 'github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: \+incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required' -+stderr '^go list -m: github.com/pierrec/lz4@v2.0.8\+incompatible: invalid version: module contains a go.mod file, so module path must match major version \("github.com/pierrec/lz4/v2"\)$' - - -- go.mod.orig -- - module example.com --- -2.30.0 - diff --git a/0027-release-branch.go1.17-regexp-syntax-reject-very-deep.patch b/0027-release-branch.go1.17-regexp-syntax-reject-very-deep.patch deleted file mode 100644 index e09e5b1b8d056c8f4d341c1fbc0239675b947aab..0000000000000000000000000000000000000000 --- a/0027-release-branch.go1.17-regexp-syntax-reject-very-deep.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 94fbe72e320175d2655c04bee76974941edb2491 Mon Sep 17 00:00:00 2001 -From: Russ Cox -Date: Wed, 2 Feb 2022 16:41:32 -0500 -Subject: [PATCH] regexp/syntax: reject very deeply nested regexps in Parse -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The regexp code assumes it can recurse over the structure of -a regexp safely. Go's growable stacks make that reasonable -for all plausible regexps, but implausible ones can reach the -“infinite recursion?” stack limit. - -This CL limits the depth of any parsed regexp to 1000. -That is, the depth of the parse tree is required to be ≤ 1000. -Regexps that require deeper parse trees will return ErrInternalError. -A future CL will change the error to ErrInvalidDepth, -but using ErrInternalError for now avoids introducing new API -in point releases when this is backported. - -Fixes #51112. -Fixes #51118. - -Change-Id: I97d2cd82195946eb43a4ea8561f5b95f91fb14c5 -Reviewed-on: https://go-review.googlesource.com/c/go/+/384616 -Trust: Russ Cox -Run-TryBot: Russ Cox -Reviewed-by: Ian Lance Taylor -Reviewed-on: https://go-review.googlesource.com/c/go/+/384854 -TryBot-Result: Gopher Robot - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/384854/ ---- - src/regexp/syntax/parse.go | 19 ++++++------------- - src/regexp/syntax/parse_test.go | 5 +++++ - 2 files changed, 11 insertions(+), 13 deletions(-) - -diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go -index 67254d6..3792960 100644 ---- a/src/regexp/syntax/parse.go -+++ b/src/regexp/syntax/parse.go -@@ -43,7 +43,6 @@ const ( - ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator" - ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression" - ErrUnexpectedParen ErrorCode = "unexpected )" -- ErrNestingDepth ErrorCode = "expression nests too deeply" - ) - - func (e ErrorCode) String() string { -@@ -266,7 +265,7 @@ func (p *parser) checkHeight(re *Regexp) { - } - } - if p.calcHeight(re, true) > maxHeight { -- panic(ErrNestingDepth) -+ panic(ErrInternalError) - } - } - -@@ -578,16 +577,12 @@ func (p *parser) collapse(subs []*Regexp, op Op) *Regexp { - // frees (passes to p.reuse) any removed *Regexps. - // - // For example, --// --// ABC|ABD|AEF|BCX|BCY --// -+// ABC|ABD|AEF|BCX|BCY - // simplifies by literal prefix extraction to --// --// A(B(C|D)|EF)|BC(X|Y) --// -+// A(B(C|D)|EF)|BC(X|Y) - // which simplifies by character class introduction to -+// A(B[CD]|EF)|BC[XY] - // --// A(B[CD]|EF)|BC[XY] - func (p *parser) factor(sub []*Regexp) []*Regexp { - if len(sub) < 2 { - return sub -@@ -897,10 +892,8 @@ func parse(s string, flags Flags) (_ *Regexp, err error) { - panic(r) - case nil: - // ok -- case ErrInternalError: // too big -+ case ErrInternalError: - err = &Error{Code: ErrInternalError, Expr: s} -- case ErrNestingDepth: -- err = &Error{Code: ErrNestingDepth, Expr: s} - } - }() - -@@ -1943,7 +1936,7 @@ func appendClass(r []rune, x []rune) []rune { - return r - } - --// appendFoldedClass returns the result of appending the case folding of the class x to the class r. -+// appendFolded returns the result of appending the case folding of the class x to the class r. - func appendFoldedClass(r []rune, x []rune) []rune { - for i := 0; i < len(x); i += 2 { - r = appendFoldedRange(r, x[i], x[i+1]) -diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go -index 6044da6..67e3c56 100644 ---- a/src/regexp/syntax/parse_test.go -+++ b/src/regexp/syntax/parse_test.go -@@ -207,6 +207,11 @@ var parseTests = []parseTest{ - // Valid repetitions. - {`((((((((((x{2}){2}){2}){2}){2}){2}){2}){2}){2}))`, ``}, - {`((((((((((x{1}){2}){2}){2}){2}){2}){2}){2}){2}){2})`, ``}, -+ -+ // Valid nesting. -+ {strings.Repeat("(", 999) + strings.Repeat(")", 999), ``}, -+ {strings.Repeat("(?:", 999) + strings.Repeat(")*", 999), ``}, -+ {"(" + strings.Repeat("|", 12345) + ")", ``}, // not nested at all - } - - const testFlags = MatchNL | PerlX | UnicodeGroups --- -2.33.0 - diff --git a/0028-release-branch.go1.17-net-http-update-bundled-golang.patch b/0028-release-branch.go1.17-net-http-update-bundled-golang.patch deleted file mode 100644 index 4df95874b6b6581b9dd9c3f90d720e11f1674681..0000000000000000000000000000000000000000 --- a/0028-release-branch.go1.17-net-http-update-bundled-golang.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 9b62e5e5e979905fd53919dfa4ad53458574ee61 Mon Sep 17 00:00:00 2001 -From: Filippo Valsorda -Date: Thu, 9 Dec 2021 06:32:14 -0500 -Subject: [PATCH 4/6] [release-branch.go1.17] net/http: update bundled - golang.org/x/net/http2 - -Pull in security fix - - 84cba54 http2: cap the size of the server's canonical header cache - -Updates #50058 -Fixes CVE-2021-44716 - -Change-Id: Ia89e3d22a173c6cb83f03608d5186fcd08f2956c -Reviewed-on: https://go-review.googlesource.com/c/go/+/370574 -Trust: Filippo Valsorda -Run-TryBot: Filippo Valsorda -Reviewed-by: Alex Rakoczy -TryBot-Result: Gopher Robot - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/370574 ---- - src/go.mod | 2 +- - src/go.sum | 4 ++-- - src/net/http/h2_bundle.go | 10 +++++++++- - src/vendor/modules.txt | 2 +- - 4 files changed, 13 insertions(+), 5 deletions(-) - -diff --git a/src/go.mod b/src/go.mod -index 386b51a6569..ada50077937 100644 ---- a/src/go.mod -+++ b/src/go.mod -@@ -4,7 +4,7 @@ go 1.17 - - require ( - golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e -- golang.org/x/net v0.0.0-20211101194204-95aca89e93de -+ golang.org/x/net v0.0.0-20211209100829-84cba5454caf - ) - - require ( -diff --git a/src/go.sum b/src/go.sum -index 1f328206ecb..3e181c992f5 100644 ---- a/src/go.sum -+++ b/src/go.sum -@@ -1,8 +1,8 @@ - golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI= - golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= - golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= --golang.org/x/net v0.0.0-20211101194204-95aca89e93de h1:dKoXPECQZ51dGVSkuiD9YzeNpLT4UPUY4d3xo0sWrkU= --golang.org/x/net v0.0.0-20211101194204-95aca89e93de/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -+golang.org/x/net v0.0.0-20211209100829-84cba5454caf h1:Chci/BE/+xVqrcWnObL99NS8gtXyJrhHDlygBQrggHM= -+golang.org/x/net v0.0.0-20211209100829-84cba5454caf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= - golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= - golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= - golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q= -diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go -index 9112079a224..1b73da7f219 100644 ---- a/src/net/http/h2_bundle.go -+++ b/src/net/http/h2_bundle.go -@@ -4382,7 +4382,15 @@ func (sc *http2serverConn) canonicalHeader(v string) string { - sc.canonHeader = make(map[string]string) - } - cv = CanonicalHeaderKey(v) -- sc.canonHeader[v] = cv -+ // maxCachedCanonicalHeaders is an arbitrarily-chosen limit on the number of -+ // entries in the canonHeader cache. This should be larger than the number -+ // of unique, uncommon header keys likely to be sent by the peer, while not -+ // so high as to permit unreaasonable memory usage if the peer sends an unbounded -+ // number of unique header keys. -+ const maxCachedCanonicalHeaders = 32 -+ if len(sc.canonHeader) < maxCachedCanonicalHeaders { -+ sc.canonHeader[v] = cv -+ } - return cv - } - -diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt -index f61fc51ba82..bb0b4c561da 100644 ---- a/src/vendor/modules.txt -+++ b/src/vendor/modules.txt -@@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519 - golang.org/x/crypto/hkdf - golang.org/x/crypto/internal/subtle - golang.org/x/crypto/poly1305 --# golang.org/x/net v0.0.0-20211101194204-95aca89e93de -+# golang.org/x/net v0.0.0-20211209100829-84cba5454caf - ## explicit; go 1.17 - golang.org/x/net/dns/dnsmessage - golang.org/x/net/http/httpguts --- -2.30.0 - diff --git a/0029-release-branch.go1.17-math-big-prevent-overflow-in-R.patch b/0029-release-branch.go1.17-math-big-prevent-overflow-in-R.patch deleted file mode 100644 index bff2973a5e642d947fea3c193ae5a19f0864d759..0000000000000000000000000000000000000000 --- a/0029-release-branch.go1.17-math-big-prevent-overflow-in-R.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 174d5787fa52ec66aa29ee20a04b47d98d458082 Mon Sep 17 00:00:00 2001 -From: Katie Hockman -Date: Wed, 19 Jan 2022 16:54:41 -0500 -Subject: [PATCH 6/6] [release-branch.go1.17] math/big: prevent overflow in - (*Rat).SetString - -Credit to rsc@ for the original patch. - -Thanks to the OSS-Fuzz project for discovering this -issue and to Emmanuel Odeke (@odeke_et) for reporting it. - -Updates #50699 -Fixes #50701 -Fixes CVE-2022-23772 - -Change-Id: I590395a3d55689625390cf1e58f5f40623b26ee5 -Reviewed-on: https://go-review.googlesource.com/c/go/+/379537 -Trust: Katie Hockman -Run-TryBot: Katie Hockman -TryBot-Result: Gopher Robot -Reviewed-by: Emmanuel Odeke -Reviewed-by: Roland Shoemaker -Reviewed-by: Julie Qiu -(cherry picked from commit ad345c265916bbf6c646865e4642eafce6d39e78) -Reviewed-on: https://go-review.googlesource.com/c/go/+/381336 -Reviewed-by: Filippo Valsorda - -Conflict: NA -Reference: https://go-review.googlesource.com/c/go/+/381336 ---- - src/math/big/ratconv.go | 5 +++++ - src/math/big/ratconv_test.go | 1 + - 2 files changed, 6 insertions(+) - -diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go -index ac3c8bd11f8..90053a9c81d 100644 ---- a/src/math/big/ratconv.go -+++ b/src/math/big/ratconv.go -@@ -169,6 +169,11 @@ func (z *Rat) SetString(s string) (*Rat, bool) { - n := exp5 - if n < 0 { - n = -n -+ if n < 0 { -+ // This can occur if -n overflows. -(-1 << 63) would become -+ // -1 << 63, which is still negative. -+ return nil, false -+ } - } - if n > 1e6 { - return nil, false // avoid excessively large exponents -diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go -index 15d206cb386..e55e6557189 100644 ---- a/src/math/big/ratconv_test.go -+++ b/src/math/big/ratconv_test.go -@@ -104,6 +104,7 @@ var setStringTests = []StringTest{ - {in: "4/3/"}, - {in: "4/3."}, - {in: "4/"}, -+ {in: "13e-9223372036854775808"}, // CVE-2022-23772 - - // valid - {"0", "0", true}, --- -2.30.0 - diff --git a/go1.17.3.src.tar.gz b/go1.17.13.src.tar.gz similarity index 69% rename from go1.17.3.src.tar.gz rename to go1.17.13.src.tar.gz index 44c4f49fb37bd15237686ef83e5a0741e0e406df..4fa5af1332524804a25f4f7195f33f15607da1a4 100644 Binary files a/go1.17.3.src.tar.gz and b/go1.17.13.src.tar.gz differ diff --git a/golang.spec b/golang.spec index b62532775dd5f6575a0d7465efe1113f2f09486d..beaf83b0ed87998a0a45e980b23404f591bb8ff6 100644 --- a/golang.spec +++ b/golang.spec @@ -62,12 +62,12 @@ Name: golang -Version: 1.17.3 -Release: 21 +Version: 1.17.13 +Release: 1 Summary: The Go Programming Language License: BSD and Public Domain URL: https://golang.org/ -Source0: https://dl.google.com/go/go1.17.3.src.tar.gz +Source0: https://dl.google.com/go/go%{version}.src.tar.gz %if !%{golang_bootstrap} BuildRequires: gcc-go >= 5 @@ -150,35 +150,6 @@ Obsoletes: %{name}-vim < 1.4 Obsoletes: emacs-%{name} < 1.4 Requires: %{vendor}-rpm-config -Patch6001: 0001-release-branch.go1.17-crypto-elliptic-tolerate-zero-.patch -Patch6002: 0002-release-branch.go1.17-encoding-pem-fix-stack-overflo.patch -Patch6003: 0003-release-branch.go1.17-syscall-fix-ForkLock-spurious-.patch -Patch6004: 0004-backport-cmd-link-mark-unexported-methods-for-plugins.patch -Patch6005: 0005-release-branch.go1.17-net-http-preserve-nil-values-i.patch -Patch6006: 0006-release-branch.go1.17-go-parser-limit-recursion-dept.patch -Patch6007: 0007-release-branch.go1.17-net-http-don-t-strip-whitespac.patch -Patch6008: 0008-release-branch.go1.17-encoding-xml-limit-depth-of-ne.patch -Patch6009: 0009-release-branch.go1.17-encoding-gob-add-a-depth-limit.patch -Patch6010: 0010-release-branch.go1.17-io-fs-fix-stack-exhaustion-in-.patch -Patch6011: 0011-release-branch.go1.17-path-filepath-fix-stack-exhaus.patch -Patch6012: 0012-release-branch.go1.17-encoding-xml-use-iterative-Ski.patch -Patch6013: 0013-release-branch.go1.17-compress-gzip-fix-stack-exhaus.patch -Patch6014: 0014-release-branch.go1.17-crypto-tls-randomly-generate-t.patch -Patch6015: 0015-release-branch.go1.17-crypto-rand-properly-handle-la.patch -Patch6016: 0016-release-branch.go1.17-math-big-check-buffer-lengths-.patch -Patch6017: 0017-path-filepath-do-not-remove-prefix-.-when-following-.patch -Patch6018: 0018-release-branch.go1.17-syscall-check-correct-group-in.patch -Patch6019: 0019-release-branch.go1.18-net-http-update-bundled-golang.patch -Patch6020: 0020-release-branch.go1.18-regexp-limit-size-of-parsed-re.patch -Patch6021: 0021-release-branch.go1.18-net-http-httputil-avoid-query-.patch -Patch6022: 0022-release-branch.go1.18-archive-tar-limit-size-of-head.patch -Patch6023: 0023-syscall-os-exec-reject-environment-variables-contain.patch -Patch6024: 0024-release-branch.go1.18-add-definition-byte-string-cut.patch -Patch6025: 0025-release-branch.go1.17-crypto-elliptic-make-IsOnCurve.patch -Patch6026: 0026-release-branch.go1.17-cmd-go-internal-modfetch-do-no.patch -Patch6027: 0027-release-branch.go1.17-regexp-syntax-reject-very-deep.patch -Patch6028: 0028-release-branch.go1.17-net-http-update-bundled-golang.patch -Patch6029: 0029-release-branch.go1.17-math-big-prevent-overflow-in-R.patch Patch6030: 0030-release-branch.go1.18-net-http-update-bundled-golang.patch Patch6031: 0031-all-update-vendored-golang.org-x-net.patch Patch6032: 0032-crypto-tls-replace-all-usages-of-BytesOrPanic.patch @@ -436,6 +407,9 @@ fi %files devel -f go-tests.list -f go-misc.list -f go-src.list %changelog +* Wed Aug 31 2023 Funda Wang - 1.17.13-1 +- New version 1.17.13 + * Fri Aug 25 2023 sunchendong - 1.17.3-21 - permit invalid host header for docker