diff --git a/0001-Enable-go-plugin-support-for-riscv64-based-on-work-b.patch b/0001-Enable-go-plugin-support-for-riscv64-based-on-work-b.patch new file mode 100644 index 0000000000000000000000000000000000000000..46a4c7b24f3c5531dadd06d9af9e368774713541 --- /dev/null +++ b/0001-Enable-go-plugin-support-for-riscv64-based-on-work-b.patch @@ -0,0 +1,40 @@ +From 57777dcbc3d05c12ac2b227e7afd5435bf84128c Mon Sep 17 00:00:00 2001 +From: hanchao +Date: Mon, 3 Jul 2023 21:20:32 +0800 +Subject: [PATCH] Enable go plugin support for riscv64 (based on work by + yangjinghua) + +--- + src/cmd/link/internal/ld/config.go | 2 +- + src/internal/platform/supported.go | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go +index ba74b6f..836c10d 100644 +--- a/src/cmd/link/internal/ld/config.go ++++ b/src/cmd/link/internal/ld/config.go +@@ -84,7 +84,7 @@ func (mode *BuildMode) Set(s string) error { + switch buildcfg.GOOS { + case "linux": + switch buildcfg.GOARCH { +- case "386", "amd64", "arm", "arm64", "ppc64le", "s390x": ++ case "386", "amd64", "arm", "arm64", "riscv64", "ppc64le", "s390x": + default: + return badmode() + } +diff --git a/src/internal/platform/supported.go b/src/internal/platform/supported.go +index 046352f..644822f 100644 +--- a/src/internal/platform/supported.go ++++ b/src/internal/platform/supported.go +@@ -180,7 +180,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { + + case "plugin": + switch platform { +- case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le", ++ case "linux/amd64", "linux/arm", "linux/arm64", "linux/riscv64", "linux/386", "linux/s390x", "linux/ppc64le", + "android/amd64", "android/arm", "android/arm64", "android/386", + "darwin/amd64", "darwin/arm64", + "freebsd/amd64": +-- +2.33.0 + 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-cmd-go-use-local-proxy-and-sumdb.patch b/0002-cmd-go-use-local-proxy-and-sumdb.patch new file mode 100644 index 0000000000000000000000000000000000000000..7e8eb4490657b75f3328b68352b39afb97b62237 --- /dev/null +++ b/0002-cmd-go-use-local-proxy-and-sumdb.patch @@ -0,0 +1,31 @@ +--- go/src/cmd/go/internal/cfg/cfg.go.orig 2023-07-30 20:09:07.754216000 +0800 ++++ go/src/cmd/go/internal/cfg/cfg.go 2023-07-30 20:09:46.037239800 +0800 +@@ -383,8 +383,8 @@ + GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", buildcfg.GOPPC64)) + GOWASM = envOr("GOWASM", fmt.Sprint(buildcfg.GOWASM)) + +- GOPROXY = envOr("GOPROXY", "https://proxy.golang.org,direct") +- GOSUMDB = envOr("GOSUMDB", "sum.golang.org") ++ GOPROXY = envOr("GOPROXY", "https://repo.huaweicloud.com/repository/goproxy/,direct") ++ GOSUMDB = envOr("GOSUMDB", "sum.golang.google.cn") + GOPRIVATE = Getenv("GOPRIVATE") + GONOPROXY = envOr("GONOPROXY", GOPRIVATE) + GONOSUMDB = envOr("GONOSUMDB", GOPRIVATE) +--- go/src/cmd/go/testdata/script/mod_sumdb_golang.txt.orig 2023-07-30 20:09:55.992971800 +0800 ++++ go/src/cmd/go/testdata/script/mod_sumdb_golang.txt 2023-07-30 20:10:32.184846600 +0800 +@@ -2,12 +2,12 @@ + env GOPROXY= + env GOSUMDB= + go env GOPROXY +-stdout '^https://proxy.golang.org,direct$' ++stdout '^https://repo.huaweicloud.com/repository/goproxy/,direct$' + go env GOSUMDB +-stdout '^sum.golang.org$' ++stdout '^sum.golang.google.cn$' + env GOPROXY=https://proxy.golang.org + go env GOSUMDB +-stdout '^sum.golang.org$' ++stdout '^sum.golang.google.cn$' + + # Download direct from github. + 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/0048-Backport-net-http-permit-requests-with-invalid-Host-headers.patch b/0003-net-http-permit-requests-with-invalid-Host-headers.patch similarity index 99% rename from 0048-Backport-net-http-permit-requests-with-invalid-Host-headers.patch rename to 0003-net-http-permit-requests-with-invalid-Host-headers.patch index c9ccf3dba870c3050441e886429322d523e718b4..ca5d045c1e7bcc7db285476acbb00a2679bc801a 100644 --- a/0048-Backport-net-http-permit-requests-with-invalid-Host-headers.patch +++ b/0003-net-http-permit-requests-with-invalid-Host-headers.patch @@ -101,4 +101,3 @@ index 0892bc255f..a32b583c11 100644 -- 2.33.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/0030-release-branch.go1.18-net-http-update-bundled-golang.patch b/0030-release-branch.go1.18-net-http-update-bundled-golang.patch deleted file mode 100644 index c2fc8959d496cec78f07a3294c73c6622501b160..0000000000000000000000000000000000000000 --- a/0030-release-branch.go1.18-net-http-update-bundled-golang.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 15ffef9628c700156c3149d02fd27ea3409a4eb7 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Wed, 30 Nov 2022 16:37:07 -0500 -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. - -For #56350 -For #57008 -Fixes CVE-2022-41717 - -Change-Id: I31ebd2b9ae190ef6f7646187103ea1c8a713ff2e -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1663833 -Reviewed-by: Tatiana Bradley -Reviewed-by: Julie Qiu -Reviewed-on: https://go-review.googlesource.com/c/go/+/455361 -Run-TryBot: Jenny Rakoczy -Reviewed-by: Michael Pratt -TryBot-Result: Gopher Robot - -Reference:https://go-review.googlesource.com/c/go/+/455361 -Conflict: NA - ---- - src/net/http/h2_bundle.go | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go -index d7e2f764c8..5433ebdc51 100644 ---- a/src/net/http/h2_bundle.go -+++ b/src/net/http/h2_bundle.go -@@ -4189,6 +4189,7 @@ type http2serverConn struct { - headerTableSize uint32 - peerMaxHeaderListSize uint32 // zero means unknown (default) - canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case -+ canonHeaderKeysSize int // canonHeader keys size in bytes - writingFrame bool // started writing a frame (on serve goroutine or separate) - writingFrameAsync bool // started a frame on its own goroutine but haven't heard back on wroteFrameCh - needsFrameFlush bool // last frame write wasn't a flush -@@ -4368,6 +4369,13 @@ func (sc *http2serverConn) condlogf(err error, format string, args ...interface{ - } - } - -+// maxCachedCanonicalHeadersKeysSize is an arbitrarily-chosen limit on the size -+// of the entries in the canonHeader cache. -+// This should be larger than the size of unique, uncommon header keys likely to -+// be sent by the peer, while not so high as to permit unreasonable memory usage -+// if the peer sends an unbounded number of unique header keys. -+const http2maxCachedCanonicalHeadersKeysSize = 2048 -+ - func (sc *http2serverConn) canonicalHeader(v string) string { - sc.serveG.check() - http2buildCommonHeaderMapsOnce() -@@ -4383,14 +4391,10 @@ func (sc *http2serverConn) canonicalHeader(v string) string { - sc.canonHeader = make(map[string]string) - } - cv = CanonicalHeaderKey(v) -- // 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 { -+ size := 100 + len(v)*2 // 100 bytes of map overhead + key + value -+ if sc.canonHeaderKeysSize+size <= http2maxCachedCanonicalHeadersKeysSize { - sc.canonHeader[v] = cv -+ sc.canonHeaderKeysSize += size - } - return cv - } --- -2.33.0 - diff --git a/0031-all-update-vendored-golang.org-x-net.patch b/0031-all-update-vendored-golang.org-x-net.patch deleted file mode 100644 index 775091c98a7e46b12f9d488b4d9c4fd71cb8dcc4..0000000000000000000000000000000000000000 --- a/0031-all-update-vendored-golang.org-x-net.patch +++ /dev/null @@ -1,150 +0,0 @@ -From d855dd004678eec0109514a4529f8afab42c4ce1 Mon Sep 17 00:00:00 2001 -From: Michael Pratt -Date: Tue, 14 Feb 2023 13:04:12 -0500 -Subject: [PATCH] all: update vendored golang.org/x/net - -Pull in HTTP/2 security fix: - - CL 468135: http2/hpack: avoid quadratic complexity in hpack decoding - -For #57855 - -Change-Id: Id6b05dc52a1a585c41c6aff0c51665614fd5e215 -Reviewed-on: https://go-review.googlesource.com/c/go/+/468295 -Reviewed-by: Than McIntosh -Reviewed-by: Damien Neil -TryBot-Result: Gopher Robot -Run-TryBot: Michael Pratt - -Reference:https://go-review.googlesource.com/c/go/+/468295 -Conflict:NA ---- - .../golang.org/x/net/http2/hpack/hpack.go | 79 ++++++++++++------- - 1 file changed, 49 insertions(+), 30 deletions(-) - -diff --git a/src/vendor/golang.org/x/net/http2/hpack/hpack.go b/src/vendor/golang.org/x/net/http2/hpack/hpack.go -index 85f18a2b0a..02e80e30a4 100644 ---- a/src/vendor/golang.org/x/net/http2/hpack/hpack.go -+++ b/src/vendor/golang.org/x/net/http2/hpack/hpack.go -@@ -359,6 +359,7 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error { - - var hf HeaderField - wantStr := d.emitEnabled || it.indexed() -+ var undecodedName undecodedString - if nameIdx > 0 { - ihf, ok := d.at(nameIdx) - if !ok { -@@ -366,15 +367,27 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error { - } - hf.Name = ihf.Name - } else { -- hf.Name, buf, err = d.readString(buf, wantStr) -+ undecodedName, buf, err = d.readString(buf) - if err != nil { - return err - } - } -- hf.Value, buf, err = d.readString(buf, wantStr) -+ undecodedValue, buf, err := d.readString(buf) - if err != nil { - return err - } -+ if wantStr { -+ if nameIdx <= 0 { -+ hf.Name, err = d.decodeString(undecodedName) -+ if err != nil { -+ return err -+ } -+ } -+ hf.Value, err = d.decodeString(undecodedValue) -+ if err != nil { -+ return err -+ } -+ } - d.buf = buf - if it.indexed() { - d.dynTab.add(hf) -@@ -459,46 +472,52 @@ func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) { - return 0, origP, errNeedMore - } - --// readString decodes an hpack string from p. -+// readString reads an hpack string from p. - // --// wantStr is whether s will be used. If false, decompression and --// []byte->string garbage are skipped if s will be ignored --// anyway. This does mean that huffman decoding errors for non-indexed --// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server --// is returning an error anyway, and because they're not indexed, the error --// won't affect the decoding state. --func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) { -+// It returns a reference to the encoded string data to permit deferring decode costs -+// until after the caller verifies all data is present. -+func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error) { - if len(p) == 0 { -- return "", p, errNeedMore -+ return u, p, errNeedMore - } - isHuff := p[0]&128 != 0 - strLen, p, err := readVarInt(7, p) - if err != nil { -- return "", p, err -+ return u, p, err - } - if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) { -- return "", nil, ErrStringLength -+ // Returning an error here means Huffman decoding errors -+ // for non-indexed strings past the maximum string length -+ // are ignored, but the server is returning an error anyway -+ // and because the string is not indexed the error will not -+ // affect the decoding state. -+ return u, nil, ErrStringLength - } - if uint64(len(p)) < strLen { -- return "", p, errNeedMore -- } -- if !isHuff { -- if wantStr { -- s = string(p[:strLen]) -- } -- return s, p[strLen:], nil -+ return u, p, errNeedMore - } -+ u.isHuff = isHuff -+ u.b = p[:strLen] -+ return u, p[strLen:], nil -+} - -- if wantStr { -- buf := bufPool.Get().(*bytes.Buffer) -- buf.Reset() // don't trust others -- defer bufPool.Put(buf) -- if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil { -- buf.Reset() -- return "", nil, err -- } -+type undecodedString struct { -+ isHuff bool -+ b []byte -+} -+ -+func (d *Decoder) decodeString(u undecodedString) (string, error) { -+ if !u.isHuff { -+ return string(u.b), nil -+ } -+ buf := bufPool.Get().(*bytes.Buffer) -+ buf.Reset() // don't trust others -+ var s string -+ err := huffmanDecode(buf, d.maxStrLen, u.b) -+ if err == nil { - s = buf.String() -- buf.Reset() // be nice to GC - } -- return s, p[strLen:], nil -+ buf.Reset() // be nice to GC -+ bufPool.Put(buf) -+ return s, err - } --- -2.33.0 - diff --git a/0032-crypto-tls-replace-all-usages-of-BytesOrPanic.patch b/0032-crypto-tls-replace-all-usages-of-BytesOrPanic.patch deleted file mode 100644 index fa85f5e71c75f3e5bdbd3f8e74c11c768ce45287..0000000000000000000000000000000000000000 --- a/0032-crypto-tls-replace-all-usages-of-BytesOrPanic.patch +++ /dev/null @@ -1,2390 +0,0 @@ -From 3c7915e992eaf30c39d5c4e67f1a429867ce1080 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Wed, 14 Dec 2022 09:43:16 -0800 -Subject: [PATCH] crypto/tls: replace all usages of BytesOrPanic - -Message marshalling makes use of BytesOrPanic a lot, under the -assumption that it will never panic. This assumption was incorrect, and -specifically crafted handshakes could trigger panics. Rather than just -surgically replacing the usages of BytesOrPanic in paths that could -panic, replace all usages of it with proper error returns in case there -are other ways of triggering panics which we didn't find. - -In one specific case, the tree routed by expandLabel, we replace the -usage of BytesOrPanic, but retain a panic. This function already -explicitly panicked elsewhere, and returning an error from it becomes -rather painful because it requires changing a large number of APIs. -The marshalling is unlikely to ever panic, as the inputs are all either -fixed length, or already limited to the sizes required. If it were to -panic, it'd likely only be during development. A close inspection shows -no paths for a user to cause a panic currently. - -This patches ends up being rather large, since it requires routing -errors back through functions which previously had no error returns. -Where possible I've tried to use helpers that reduce the verbosity -of frequently repeated stanzas, and to make the diffs as minimal as -possible. - -Thanks to Marten Seemann for reporting this issue. - -Fixes #58001 -Fixes CVE-2022-41724 - -Change-Id: Ieb55867ef0a3e1e867b33f09421932510cb58851 -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1679436 -Reviewed-by: Julie Qiu -TryBot-Result: Security TryBots -Run-TryBot: Roland Shoemaker -Reviewed-by: Damien Neil -Reviewed-on: https://go-review.googlesource.com/c/go/+/468125 -Run-TryBot: Michael Pratt -Reviewed-by: Than McIntosh -TryBot-Result: Gopher Robot -Auto-Submit: Michael Pratt - -Reference:https://go-review.googlesource.com/c/go/+/468125 -Conflict:NA ---- - src/crypto/tls/common.go | 2 +- - src/crypto/tls/conn.go | 43 +- - src/crypto/tls/handshake_client.go | 95 +-- - src/crypto/tls/handshake_client_test.go | 4 +- - src/crypto/tls/handshake_client_tls13.go | 74 ++- - src/crypto/tls/handshake_messages.go | 716 +++++++++++----------- - src/crypto/tls/handshake_messages_test.go | 19 +- - src/crypto/tls/handshake_server.go | 73 ++- - src/crypto/tls/handshake_server_test.go | 31 +- - src/crypto/tls/handshake_server_tls13.go | 71 ++- - src/crypto/tls/key_schedule.go | 19 +- - src/crypto/tls/ticket.go | 8 +- - 12 files changed, 654 insertions(+), 501 deletions(-) - -diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go -index d561e61707..eb73ace159 100644 ---- a/src/crypto/tls/common.go -+++ b/src/crypto/tls/common.go -@@ -1357,7 +1357,7 @@ func (c *Certificate) leaf() (*x509.Certificate, error) { - } - - type handshakeMessage interface { -- marshal() []byte -+ marshal() ([]byte, error) - unmarshal([]byte) bool - } - -diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go -index 969f357834..d12ef5be28 100644 ---- a/src/crypto/tls/conn.go -+++ b/src/crypto/tls/conn.go -@@ -993,18 +993,36 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { - return n, nil - } - --// writeRecord writes a TLS record with the given type and payload to the --// connection and updates the record layer state. --func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) { -+// writeHandshakeRecord writes a handshake message to the connection and updates -+// the record layer state. If transcript is non-nil the marshalled message is -+// written to it. -+func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) { - c.out.Lock() - defer c.out.Unlock() - -- return c.writeRecordLocked(typ, data) -+ data, err := msg.marshal() -+ if err != nil { -+ return 0, err -+ } -+ if transcript != nil { -+ transcript.Write(data) -+ } -+ -+ return c.writeRecordLocked(recordTypeHandshake, data) -+} -+ -+// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and -+// updates the record layer state. -+func (c *Conn) writeChangeCipherRecord() error { -+ c.out.Lock() -+ defer c.out.Unlock() -+ _, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1}) -+ return err - } - - // readHandshake reads the next handshake message from - // the record layer. --func (c *Conn) readHandshake() (interface{}, error) { -+func (c *Conn) readHandshake(transcript transcriptHash) (interface{}, error) { - for c.hand.Len() < 4 { - if err := c.readRecord(); err != nil { - return nil, err -@@ -1083,6 +1101,11 @@ func (c *Conn) readHandshake() (interface{}, error) { - if !m.unmarshal(data) { - return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) - } -+ -+ if transcript != nil { -+ transcript.Write(data) -+ } -+ - return m, nil - } - -@@ -1158,7 +1181,7 @@ func (c *Conn) handleRenegotiation() error { - return errors.New("tls: internal error: unexpected renegotiation") - } - -- msg, err := c.readHandshake() -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -@@ -1204,7 +1227,7 @@ func (c *Conn) handlePostHandshakeMessage() error { - return c.handleRenegotiation() - } - -- msg, err := c.readHandshake() -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -@@ -1240,7 +1263,11 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error { - defer c.out.Unlock() - - msg := &keyUpdateMsg{} -- _, err := c.writeRecordLocked(recordTypeHandshake, msg.marshal()) -+ msgBytes, err := msg.marshal() -+ if err != nil { -+ return err -+ } -+ _, err = c.writeRecordLocked(recordTypeHandshake, msgBytes) - if err != nil { - // Surface the error at the next write. - c.out.setErrorLocked(err) -diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go -index 4af3d998a3..85622f159b 100644 ---- a/src/crypto/tls/handshake_client.go -+++ b/src/crypto/tls/handshake_client.go -@@ -157,7 +157,10 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { - } - c.serverName = hello.serverName - -- cacheKey, session, earlySecret, binderKey := c.loadSession(hello) -+ cacheKey, session, earlySecret, binderKey, err := c.loadSession(hello) -+ if err != nil { -+ return err -+ } - if cacheKey != "" && session != nil { - defer func() { - // If we got a handshake failure when resuming a session, throw away -@@ -172,11 +175,12 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { - }() - } - -- if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil { -+ if _, err := c.writeHandshakeRecord(hello, nil); err != nil { - return err - } - -- msg, err := c.readHandshake() -+ // serverHelloMsg is not included in the transcript -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -@@ -241,9 +245,9 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { - } - - func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, -- session *ClientSessionState, earlySecret, binderKey []byte) { -+ session *ClientSessionState, earlySecret, binderKey []byte, err error) { - if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil { -- return "", nil, nil, nil -+ return "", nil, nil, nil, nil - } - - hello.ticketSupported = true -@@ -258,14 +262,14 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, - // renegotiation is primarily used to allow a client to send a client - // certificate, which would be skipped if session resumption occurred. - if c.handshakes != 0 { -- return "", nil, nil, nil -+ return "", nil, nil, nil, nil - } - - // Try to resume a previously negotiated TLS session, if available. - cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config) - session, ok := c.config.ClientSessionCache.Get(cacheKey) - if !ok || session == nil { -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - - // Check that version used for the previous session is still valid. -@@ -277,7 +281,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, - } - } - if !versOk { -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - - // Check that the cached server certificate is not expired, and that it's -@@ -286,16 +290,16 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, - if !c.config.InsecureSkipVerify { - if len(session.verifiedChains) == 0 { - // The original connection had InsecureSkipVerify, while this doesn't. -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - serverCert := session.serverCertificates[0] - if c.config.time().After(serverCert.NotAfter) { - // Expired certificate, delete the entry. - c.config.ClientSessionCache.Put(cacheKey, nil) -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - if err := serverCert.VerifyHostname(c.config.ServerName); err != nil { -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - } - -@@ -303,7 +307,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, - // In TLS 1.2 the cipher suite must match the resumed session. Ensure we - // are still offering it. - if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil { -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - - hello.sessionTicket = session.sessionTicket -@@ -313,14 +317,14 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, - // Check that the session ticket is not expired. - if c.config.time().After(session.useBy) { - c.config.ClientSessionCache.Put(cacheKey, nil) -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - - // In TLS 1.3 the KDF hash must match the resumed session. Ensure we - // offer at least one cipher suite with that hash. - cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite) - if cipherSuite == nil { -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - cipherSuiteOk := false - for _, offeredID := range hello.cipherSuites { -@@ -331,7 +335,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, - } - } - if !cipherSuiteOk { -- return cacheKey, nil, nil, nil -+ return cacheKey, nil, nil, nil, nil - } - - // Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1. -@@ -349,9 +353,15 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string, - earlySecret = cipherSuite.extract(psk, nil) - binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil) - transcript := cipherSuite.hash.New() -- transcript.Write(hello.marshalWithoutBinders()) -+ helloBytes, err := hello.marshalWithoutBinders() -+ if err != nil { -+ return "", nil, nil, nil, err -+ } -+ transcript.Write(helloBytes) - pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)} -- hello.updateBinders(pskBinders) -+ if err := hello.updateBinders(pskBinders); err != nil { -+ return "", nil, nil, nil, err -+ } - - return - } -@@ -396,8 +406,12 @@ func (hs *clientHandshakeState) handshake() error { - hs.finishedHash.discardHandshakeBuffer() - } - -- hs.finishedHash.Write(hs.hello.marshal()) -- hs.finishedHash.Write(hs.serverHello.marshal()) -+ if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil { -+ return err -+ } -+ if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil { -+ return err -+ } - - c.buffering = true - c.didResume = isResume -@@ -468,7 +482,7 @@ func (hs *clientHandshakeState) pickCipherSuite() error { - func (hs *clientHandshakeState) doFullHandshake() error { - c := hs.c - -- msg, err := c.readHandshake() -+ msg, err := c.readHandshake(&hs.finishedHash) - if err != nil { - return err - } -@@ -477,9 +491,8 @@ func (hs *clientHandshakeState) doFullHandshake() error { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } -- hs.finishedHash.Write(certMsg.marshal()) - -- msg, err = c.readHandshake() -+ msg, err = c.readHandshake(&hs.finishedHash) - if err != nil { - return err - } -@@ -497,11 +510,10 @@ func (hs *clientHandshakeState) doFullHandshake() error { - c.sendAlert(alertUnexpectedMessage) - return errors.New("tls: received unexpected CertificateStatus message") - } -- hs.finishedHash.Write(cs.marshal()) - - c.ocspResponse = cs.response - -- msg, err = c.readHandshake() -+ msg, err = c.readHandshake(&hs.finishedHash) - if err != nil { - return err - } -@@ -530,14 +542,13 @@ func (hs *clientHandshakeState) doFullHandshake() error { - - skx, ok := msg.(*serverKeyExchangeMsg) - if ok { -- hs.finishedHash.Write(skx.marshal()) - err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx) - if err != nil { - c.sendAlert(alertUnexpectedMessage) - return err - } - -- msg, err = c.readHandshake() -+ msg, err = c.readHandshake(&hs.finishedHash) - if err != nil { - return err - } -@@ -548,7 +559,6 @@ func (hs *clientHandshakeState) doFullHandshake() error { - certReq, ok := msg.(*certificateRequestMsg) - if ok { - certRequested = true -- hs.finishedHash.Write(certReq.marshal()) - - cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq) - if chainToSend, err = c.getClientCertificate(cri); err != nil { -@@ -556,7 +566,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { - return err - } - -- msg, err = c.readHandshake() -+ msg, err = c.readHandshake(&hs.finishedHash) - if err != nil { - return err - } -@@ -567,7 +577,6 @@ func (hs *clientHandshakeState) doFullHandshake() error { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(shd, msg) - } -- hs.finishedHash.Write(shd.marshal()) - - // If the server requested a certificate then we have to send a - // Certificate message, even if it's empty because we don't have a -@@ -575,8 +584,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { - if certRequested { - certMsg = new(certificateMsg) - certMsg.certificates = chainToSend.Certificate -- hs.finishedHash.Write(certMsg.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil { - return err - } - } -@@ -587,8 +595,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { - return err - } - if ckx != nil { -- hs.finishedHash.Write(ckx.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil { - return err - } - } -@@ -635,8 +642,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { - return err - } - -- hs.finishedHash.Write(certVerify.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil { - return err - } - } -@@ -771,7 +777,10 @@ func (hs *clientHandshakeState) readFinished(out []byte) error { - return err - } - -- msg, err := c.readHandshake() -+ // finishedMsg is included in the transcript, but not until after we -+ // check the client version, since the state before this message was -+ // sent is used during verification. -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -@@ -787,7 +796,11 @@ func (hs *clientHandshakeState) readFinished(out []byte) error { - c.sendAlert(alertHandshakeFailure) - return errors.New("tls: server's Finished message was incorrect") - } -- hs.finishedHash.Write(serverFinished.marshal()) -+ -+ if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil { -+ return err -+ } -+ - copy(out, verify) - return nil - } -@@ -798,7 +811,7 @@ func (hs *clientHandshakeState) readSessionTicket() error { - } - - c := hs.c -- msg, err := c.readHandshake() -+ msg, err := c.readHandshake(&hs.finishedHash) - if err != nil { - return err - } -@@ -807,7 +820,6 @@ func (hs *clientHandshakeState) readSessionTicket() error { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(sessionTicketMsg, msg) - } -- hs.finishedHash.Write(sessionTicketMsg.marshal()) - - hs.session = &ClientSessionState{ - sessionTicket: sessionTicketMsg.ticket, -@@ -827,14 +839,13 @@ func (hs *clientHandshakeState) readSessionTicket() error { - func (hs *clientHandshakeState) sendFinished(out []byte) error { - c := hs.c - -- if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { -+ if err := c.writeChangeCipherRecord(); err != nil { - return err - } - - finished := new(finishedMsg) - finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) -- hs.finishedHash.Write(finished.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil { - return err - } - copy(out, finished.verifyData) -diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go -index b6eb488a4d..0228745155 100644 ---- a/src/crypto/tls/handshake_client_test.go -+++ b/src/crypto/tls/handshake_client_test.go -@@ -1257,7 +1257,7 @@ func TestServerSelectingUnconfiguredApplicationProtocol(t *testing.T) { - cipherSuite: TLS_RSA_WITH_AES_128_GCM_SHA256, - alpnProtocol: "how-about-this", - } -- serverHelloBytes := serverHello.marshal() -+ serverHelloBytes := mustMarshal(t, serverHello) - - s.Write([]byte{ - byte(recordTypeHandshake), -@@ -1500,7 +1500,7 @@ func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) { - random: make([]byte, 32), - cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384, - } -- serverHelloBytes := serverHello.marshal() -+ serverHelloBytes := mustMarshal(t, serverHello) - - s.Write([]byte{ - byte(recordTypeHandshake), -diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go -index eb59ac90d1..d51303aeab 100644 ---- a/src/crypto/tls/handshake_client_tls13.go -+++ b/src/crypto/tls/handshake_client_tls13.go -@@ -58,7 +58,10 @@ func (hs *clientHandshakeStateTLS13) handshake() error { - } - - hs.transcript = hs.suite.hash.New() -- hs.transcript.Write(hs.hello.marshal()) -+ -+ if err := transcriptMsg(hs.hello, hs.transcript); err != nil { -+ return err -+ } - - if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) { - if err := hs.sendDummyChangeCipherSpec(); err != nil { -@@ -69,7 +72,9 @@ func (hs *clientHandshakeStateTLS13) handshake() error { - } - } - -- hs.transcript.Write(hs.serverHello.marshal()) -+ if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil { -+ return err -+ } - - c.buffering = true - if err := hs.processServerHello(); err != nil { -@@ -168,8 +173,7 @@ func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error { - } - hs.sentDummyCCS = true - -- _, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) -- return err -+ return hs.c.writeChangeCipherRecord() - } - - // processHelloRetryRequest handles the HRR in hs.serverHello, modifies and -@@ -184,7 +188,9 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { - hs.transcript.Reset() - hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) - hs.transcript.Write(chHash) -- hs.transcript.Write(hs.serverHello.marshal()) -+ if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil { -+ return err -+ } - - // The only HelloRetryRequest extensions we support are key_share and - // cookie, and clients must abort the handshake if the HRR would not result -@@ -249,10 +255,18 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { - transcript := hs.suite.hash.New() - transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) - transcript.Write(chHash) -- transcript.Write(hs.serverHello.marshal()) -- transcript.Write(hs.hello.marshalWithoutBinders()) -+ if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil { -+ return err -+ } -+ helloBytes, err := hs.hello.marshalWithoutBinders() -+ if err != nil { -+ return err -+ } -+ transcript.Write(helloBytes) - pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)} -- hs.hello.updateBinders(pskBinders) -+ if err := hs.hello.updateBinders(pskBinders); err != nil { -+ return err -+ } - } else { - // Server selected a cipher suite incompatible with the PSK. - hs.hello.pskIdentities = nil -@@ -260,12 +274,12 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { - } - } - -- hs.transcript.Write(hs.hello.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil { - return err - } - -- msg, err := c.readHandshake() -+ // serverHelloMsg is not included in the transcript -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -@@ -354,6 +368,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { - if !hs.usingPSK { - earlySecret = hs.suite.extract(nil, nil) - } -+ - handshakeSecret := hs.suite.extract(sharedKey, - hs.suite.deriveSecret(earlySecret, "derived", nil)) - -@@ -384,7 +399,7 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { - func (hs *clientHandshakeStateTLS13) readServerParameters() error { - c := hs.c - -- msg, err := c.readHandshake() -+ msg, err := c.readHandshake(hs.transcript) - if err != nil { - return err - } -@@ -394,7 +409,6 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(encryptedExtensions, msg) - } -- hs.transcript.Write(encryptedExtensions.marshal()) - - if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil { - c.sendAlert(alertUnsupportedExtension) -@@ -423,18 +437,16 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error { - return nil - } - -- msg, err := c.readHandshake() -+ msg, err := c.readHandshake(hs.transcript) - if err != nil { - return err - } - - certReq, ok := msg.(*certificateRequestMsgTLS13) - if ok { -- hs.transcript.Write(certReq.marshal()) -- - hs.certReq = certReq - -- msg, err = c.readHandshake() -+ msg, err = c.readHandshake(hs.transcript) - if err != nil { - return err - } -@@ -449,7 +461,6 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error { - c.sendAlert(alertDecodeError) - return errors.New("tls: received empty certificates message") - } -- hs.transcript.Write(certMsg.marshal()) - - c.scts = certMsg.certificate.SignedCertificateTimestamps - c.ocspResponse = certMsg.certificate.OCSPStaple -@@ -458,7 +469,10 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error { - return err - } - -- msg, err = c.readHandshake() -+ // certificateVerifyMsg is included in the transcript, but not until -+ // after we verify the handshake signature, since the state before -+ // this message was sent is used. -+ msg, err = c.readHandshake(nil) - if err != nil { - return err - } -@@ -489,7 +503,9 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error { - return errors.New("tls: invalid signature by the server certificate: " + err.Error()) - } - -- hs.transcript.Write(certVerify.marshal()) -+ if err := transcriptMsg(certVerify, hs.transcript); err != nil { -+ return err -+ } - - return nil - } -@@ -497,7 +513,10 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error { - func (hs *clientHandshakeStateTLS13) readServerFinished() error { - c := hs.c - -- msg, err := c.readHandshake() -+ // finishedMsg is included in the transcript, but not until after we -+ // check the client version, since the state before this message was -+ // sent is used during verification. -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -@@ -514,7 +533,9 @@ func (hs *clientHandshakeStateTLS13) readServerFinished() error { - return errors.New("tls: invalid server finished hash") - } - -- hs.transcript.Write(finished.marshal()) -+ if err := transcriptMsg(finished, hs.transcript); err != nil { -+ return err -+ } - - // Derive secrets that take context through the server Finished. - -@@ -563,8 +584,7 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error { - certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0 - certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0 - -- hs.transcript.Write(certMsg.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil { - return err - } - -@@ -601,8 +621,7 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error { - } - certVerifyMsg.signature = sig - -- hs.transcript.Write(certVerifyMsg.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil { - return err - } - -@@ -616,8 +635,7 @@ func (hs *clientHandshakeStateTLS13) sendClientFinished() error { - verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript), - } - -- hs.transcript.Write(finished.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil { - return err - } - -diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go -index b5f81e4436..3541d3ceec 100644 ---- a/src/crypto/tls/handshake_messages.go -+++ b/src/crypto/tls/handshake_messages.go -@@ -5,6 +5,7 @@ - package tls - - import ( -+ "errors" - "fmt" - "strings" - -@@ -94,9 +95,181 @@ type clientHelloMsg struct { - pskBinders [][]byte - } - --func (m *clientHelloMsg) marshal() []byte { -+func (m *clientHelloMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil -+ } -+ -+ var exts cryptobyte.Builder -+ if len(m.serverName) > 0 { -+ // RFC 6066, Section 3 -+ exts.AddUint16(extensionServerName) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8(0) // name_type = host_name -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes([]byte(m.serverName)) -+ }) -+ }) -+ }) -+ } -+ if m.ocspStapling { -+ // RFC 4366, Section 3.6 -+ exts.AddUint16(extensionStatusRequest) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8(1) // status_type = ocsp -+ exts.AddUint16(0) // empty responder_id_list -+ exts.AddUint16(0) // empty request_extensions -+ }) -+ } -+ if len(m.supportedCurves) > 0 { -+ // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 -+ exts.AddUint16(extensionSupportedCurves) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, curve := range m.supportedCurves { -+ exts.AddUint16(uint16(curve)) -+ } -+ }) -+ }) -+ } -+ if len(m.supportedPoints) > 0 { -+ // RFC 4492, Section 5.1.2 -+ exts.AddUint16(extensionSupportedPoints) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.supportedPoints) -+ }) -+ }) -+ } -+ if m.ticketSupported { -+ // RFC 5077, Section 3.2 -+ exts.AddUint16(extensionSessionTicket) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.sessionTicket) -+ }) -+ } -+ if len(m.supportedSignatureAlgorithms) > 0 { -+ // RFC 5246, Section 7.4.1.4.1 -+ exts.AddUint16(extensionSignatureAlgorithms) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, sigAlgo := range m.supportedSignatureAlgorithms { -+ exts.AddUint16(uint16(sigAlgo)) -+ } -+ }) -+ }) -+ } -+ if len(m.supportedSignatureAlgorithmsCert) > 0 { -+ // RFC 8446, Section 4.2.3 -+ exts.AddUint16(extensionSignatureAlgorithmsCert) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { -+ exts.AddUint16(uint16(sigAlgo)) -+ } -+ }) -+ }) -+ } -+ if m.secureRenegotiationSupported { -+ // RFC 5746, Section 3.2 -+ exts.AddUint16(extensionRenegotiationInfo) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.secureRenegotiation) -+ }) -+ }) -+ } -+ if len(m.alpnProtocols) > 0 { -+ // RFC 7301, Section 3.1 -+ exts.AddUint16(extensionALPN) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, proto := range m.alpnProtocols { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes([]byte(proto)) -+ }) -+ } -+ }) -+ }) -+ } -+ if m.scts { -+ // RFC 6962, Section 3.3.1 -+ exts.AddUint16(extensionSCT) -+ exts.AddUint16(0) // empty extension_data -+ } -+ if len(m.supportedVersions) > 0 { -+ // RFC 8446, Section 4.2.1 -+ exts.AddUint16(extensionSupportedVersions) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, vers := range m.supportedVersions { -+ exts.AddUint16(vers) -+ } -+ }) -+ }) -+ } -+ if len(m.cookie) > 0 { -+ // RFC 8446, Section 4.2.2 -+ exts.AddUint16(extensionCookie) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.cookie) -+ }) -+ }) -+ } -+ if len(m.keyShares) > 0 { -+ // RFC 8446, Section 4.2.8 -+ exts.AddUint16(extensionKeyShare) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, ks := range m.keyShares { -+ exts.AddUint16(uint16(ks.group)) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(ks.data) -+ }) -+ } -+ }) -+ }) -+ } -+ if m.earlyData { -+ // RFC 8446, Section 4.2.10 -+ exts.AddUint16(extensionEarlyData) -+ exts.AddUint16(0) // empty extension_data -+ } -+ if len(m.pskModes) > 0 { -+ // RFC 8446, Section 4.2.9 -+ exts.AddUint16(extensionPSKModes) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.pskModes) -+ }) -+ }) -+ } -+ if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension -+ // RFC 8446, Section 4.2.11 -+ exts.AddUint16(extensionPreSharedKey) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, psk := range m.pskIdentities { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(psk.label) -+ }) -+ exts.AddUint32(psk.obfuscatedTicketAge) -+ } -+ }) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, binder := range m.pskBinders { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(binder) -+ }) -+ } -+ }) -+ }) -+ } -+ extBytes, err := exts.Bytes() -+ if err != nil { -+ return nil, err - } - - var b cryptobyte.Builder -@@ -116,219 +289,53 @@ func (m *clientHelloMsg) marshal() []byte { - b.AddBytes(m.compressionMethods) - }) - -- // If extensions aren't present, omit them. -- var extensionsPresent bool -- bWithoutExtensions := *b -- -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- if len(m.serverName) > 0 { -- // RFC 6066, Section 3 -- b.AddUint16(extensionServerName) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8(0) // name_type = host_name -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes([]byte(m.serverName)) -- }) -- }) -- }) -- } -- if m.ocspStapling { -- // RFC 4366, Section 3.6 -- b.AddUint16(extensionStatusRequest) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8(1) // status_type = ocsp -- b.AddUint16(0) // empty responder_id_list -- b.AddUint16(0) // empty request_extensions -- }) -- } -- if len(m.supportedCurves) > 0 { -- // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 -- b.AddUint16(extensionSupportedCurves) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, curve := range m.supportedCurves { -- b.AddUint16(uint16(curve)) -- } -- }) -- }) -- } -- if len(m.supportedPoints) > 0 { -- // RFC 4492, Section 5.1.2 -- b.AddUint16(extensionSupportedPoints) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.supportedPoints) -- }) -- }) -- } -- if m.ticketSupported { -- // RFC 5077, Section 3.2 -- b.AddUint16(extensionSessionTicket) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.sessionTicket) -- }) -- } -- if len(m.supportedSignatureAlgorithms) > 0 { -- // RFC 5246, Section 7.4.1.4.1 -- b.AddUint16(extensionSignatureAlgorithms) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, sigAlgo := range m.supportedSignatureAlgorithms { -- b.AddUint16(uint16(sigAlgo)) -- } -- }) -- }) -- } -- if len(m.supportedSignatureAlgorithmsCert) > 0 { -- // RFC 8446, Section 4.2.3 -- b.AddUint16(extensionSignatureAlgorithmsCert) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { -- b.AddUint16(uint16(sigAlgo)) -- } -- }) -- }) -- } -- if m.secureRenegotiationSupported { -- // RFC 5746, Section 3.2 -- b.AddUint16(extensionRenegotiationInfo) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.secureRenegotiation) -- }) -- }) -- } -- if len(m.alpnProtocols) > 0 { -- // RFC 7301, Section 3.1 -- b.AddUint16(extensionALPN) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, proto := range m.alpnProtocols { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes([]byte(proto)) -- }) -- } -- }) -- }) -- } -- if m.scts { -- // RFC 6962, Section 3.3.1 -- b.AddUint16(extensionSCT) -- b.AddUint16(0) // empty extension_data -- } -- if len(m.supportedVersions) > 0 { -- // RFC 8446, Section 4.2.1 -- b.AddUint16(extensionSupportedVersions) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, vers := range m.supportedVersions { -- b.AddUint16(vers) -- } -- }) -- }) -- } -- if len(m.cookie) > 0 { -- // RFC 8446, Section 4.2.2 -- b.AddUint16(extensionCookie) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.cookie) -- }) -- }) -- } -- if len(m.keyShares) > 0 { -- // RFC 8446, Section 4.2.8 -- b.AddUint16(extensionKeyShare) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, ks := range m.keyShares { -- b.AddUint16(uint16(ks.group)) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(ks.data) -- }) -- } -- }) -- }) -- } -- if m.earlyData { -- // RFC 8446, Section 4.2.10 -- b.AddUint16(extensionEarlyData) -- b.AddUint16(0) // empty extension_data -- } -- if len(m.pskModes) > 0 { -- // RFC 8446, Section 4.2.9 -- b.AddUint16(extensionPSKModes) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.pskModes) -- }) -- }) -- } -- if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension -- // RFC 8446, Section 4.2.11 -- b.AddUint16(extensionPreSharedKey) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, psk := range m.pskIdentities { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(psk.label) -- }) -- b.AddUint32(psk.obfuscatedTicketAge) -- } -- }) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, binder := range m.pskBinders { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(binder) -- }) -- } -- }) -- }) -- } -- -- extensionsPresent = len(b.BytesOrPanic()) > 2 -- }) -- -- if !extensionsPresent { -- *b = bWithoutExtensions -+ if len(extBytes) > 0 { -+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -+ b.AddBytes(extBytes) -+ }) - } - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - // marshalWithoutBinders returns the ClientHello through the - // PreSharedKeyExtension.identities field, according to RFC 8446, Section - // 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length. --func (m *clientHelloMsg) marshalWithoutBinders() []byte { -+func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) { - bindersLen := 2 // uint16 length prefix - for _, binder := range m.pskBinders { - bindersLen += 1 // uint8 length prefix - bindersLen += len(binder) - } - -- fullMessage := m.marshal() -- return fullMessage[:len(fullMessage)-bindersLen] -+ fullMessage, err := m.marshal() -+ if err != nil { -+ return nil, err -+ } -+ return fullMessage[:len(fullMessage)-bindersLen], nil - } - - // updateBinders updates the m.pskBinders field, if necessary updating the - // cached marshaled representation. The supplied binders must have the same - // length as the current m.pskBinders. --func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) { -+func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error { - if len(pskBinders) != len(m.pskBinders) { -- panic("tls: internal error: pskBinders length mismatch") -+ return errors.New("tls: internal error: pskBinders length mismatch") - } - for i := range m.pskBinders { - if len(pskBinders[i]) != len(m.pskBinders[i]) { -- panic("tls: internal error: pskBinders length mismatch") -+ return errors.New("tls: internal error: pskBinders length mismatch") - } - } - m.pskBinders = pskBinders - if m.raw != nil { -- lenWithoutBinders := len(m.marshalWithoutBinders()) -+ helloBytes, err := m.marshalWithoutBinders() -+ if err != nil { -+ return err -+ } -+ lenWithoutBinders := len(helloBytes) - // TODO(filippo): replace with NewFixedBuilder once CL 148882 is imported. - b := cryptobyte.NewBuilder(m.raw[:lenWithoutBinders]) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -@@ -339,9 +346,11 @@ func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) { - } - }) - if len(b.BytesOrPanic()) != len(m.raw) { -- panic("tls: internal error: failed to update binders") -+ return errors.New("tls: internal error: failed to update binders") - } - } -+ -+ return nil - } - - func (m *clientHelloMsg) unmarshal(data []byte) bool { -@@ -613,9 +622,98 @@ type serverHelloMsg struct { - selectedGroup CurveID - } - --func (m *serverHelloMsg) marshal() []byte { -+func (m *serverHelloMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil -+ } -+ -+ var exts cryptobyte.Builder -+ if m.ocspStapling { -+ exts.AddUint16(extensionStatusRequest) -+ exts.AddUint16(0) // empty extension_data -+ } -+ if m.ticketSupported { -+ exts.AddUint16(extensionSessionTicket) -+ exts.AddUint16(0) // empty extension_data -+ } -+ if m.secureRenegotiationSupported { -+ exts.AddUint16(extensionRenegotiationInfo) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.secureRenegotiation) -+ }) -+ }) -+ } -+ if len(m.alpnProtocol) > 0 { -+ exts.AddUint16(extensionALPN) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes([]byte(m.alpnProtocol)) -+ }) -+ }) -+ }) -+ } -+ if len(m.scts) > 0 { -+ exts.AddUint16(extensionSCT) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ for _, sct := range m.scts { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(sct) -+ }) -+ } -+ }) -+ }) -+ } -+ if m.supportedVersion != 0 { -+ exts.AddUint16(extensionSupportedVersions) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16(m.supportedVersion) -+ }) -+ } -+ if m.serverShare.group != 0 { -+ exts.AddUint16(extensionKeyShare) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16(uint16(m.serverShare.group)) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.serverShare.data) -+ }) -+ }) -+ } -+ if m.selectedIdentityPresent { -+ exts.AddUint16(extensionPreSharedKey) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16(m.selectedIdentity) -+ }) -+ } -+ -+ if len(m.cookie) > 0 { -+ exts.AddUint16(extensionCookie) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.cookie) -+ }) -+ }) -+ } -+ if m.selectedGroup != 0 { -+ exts.AddUint16(extensionKeyShare) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint16(uint16(m.selectedGroup)) -+ }) -+ } -+ if len(m.supportedPoints) > 0 { -+ exts.AddUint16(extensionSupportedPoints) -+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { -+ exts.AddBytes(m.supportedPoints) -+ }) -+ }) -+ } -+ -+ extBytes, err := exts.Bytes() -+ if err != nil { -+ return nil, err - } - - var b cryptobyte.Builder -@@ -629,104 +727,15 @@ func (m *serverHelloMsg) marshal() []byte { - b.AddUint16(m.cipherSuite) - b.AddUint8(m.compressionMethod) - -- // If extensions aren't present, omit them. -- var extensionsPresent bool -- bWithoutExtensions := *b -- -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- if m.ocspStapling { -- b.AddUint16(extensionStatusRequest) -- b.AddUint16(0) // empty extension_data -- } -- if m.ticketSupported { -- b.AddUint16(extensionSessionTicket) -- b.AddUint16(0) // empty extension_data -- } -- if m.secureRenegotiationSupported { -- b.AddUint16(extensionRenegotiationInfo) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.secureRenegotiation) -- }) -- }) -- } -- if len(m.alpnProtocol) > 0 { -- b.AddUint16(extensionALPN) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes([]byte(m.alpnProtocol)) -- }) -- }) -- }) -- } -- if len(m.scts) > 0 { -- b.AddUint16(extensionSCT) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- for _, sct := range m.scts { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(sct) -- }) -- } -- }) -- }) -- } -- if m.supportedVersion != 0 { -- b.AddUint16(extensionSupportedVersions) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16(m.supportedVersion) -- }) -- } -- if m.serverShare.group != 0 { -- b.AddUint16(extensionKeyShare) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16(uint16(m.serverShare.group)) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.serverShare.data) -- }) -- }) -- } -- if m.selectedIdentityPresent { -- b.AddUint16(extensionPreSharedKey) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16(m.selectedIdentity) -- }) -- } -- -- if len(m.cookie) > 0 { -- b.AddUint16(extensionCookie) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.cookie) -- }) -- }) -- } -- if m.selectedGroup != 0 { -- b.AddUint16(extensionKeyShare) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint16(uint16(m.selectedGroup)) -- }) -- } -- if len(m.supportedPoints) > 0 { -- b.AddUint16(extensionSupportedPoints) -- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { -- b.AddBytes(m.supportedPoints) -- }) -- }) -- } -- -- extensionsPresent = len(b.BytesOrPanic()) > 2 -- }) -- -- if !extensionsPresent { -- *b = bWithoutExtensions -+ if len(extBytes) > 0 { -+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { -+ b.AddBytes(extBytes) -+ }) - } - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func (m *serverHelloMsg) unmarshal(data []byte) bool { -@@ -844,9 +853,9 @@ type encryptedExtensionsMsg struct { - alpnProtocol string - } - --func (m *encryptedExtensionsMsg) marshal() []byte { -+func (m *encryptedExtensionsMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var b cryptobyte.Builder -@@ -866,8 +875,9 @@ func (m *encryptedExtensionsMsg) marshal() []byte { - }) - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ var err error -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { -@@ -915,10 +925,10 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { - - type endOfEarlyDataMsg struct{} - --func (m *endOfEarlyDataMsg) marshal() []byte { -+func (m *endOfEarlyDataMsg) marshal() ([]byte, error) { - x := make([]byte, 4) - x[0] = typeEndOfEarlyData -- return x -+ return x, nil - } - - func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool { -@@ -930,9 +940,9 @@ type keyUpdateMsg struct { - updateRequested bool - } - --func (m *keyUpdateMsg) marshal() []byte { -+func (m *keyUpdateMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var b cryptobyte.Builder -@@ -945,8 +955,9 @@ func (m *keyUpdateMsg) marshal() []byte { - } - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ var err error -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func (m *keyUpdateMsg) unmarshal(data []byte) bool { -@@ -978,9 +989,9 @@ type newSessionTicketMsgTLS13 struct { - maxEarlyData uint32 - } - --func (m *newSessionTicketMsgTLS13) marshal() []byte { -+func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var b cryptobyte.Builder -@@ -1005,8 +1016,9 @@ func (m *newSessionTicketMsgTLS13) marshal() []byte { - }) - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ var err error -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool { -@@ -1059,9 +1071,9 @@ type certificateRequestMsgTLS13 struct { - certificateAuthorities [][]byte - } - --func (m *certificateRequestMsgTLS13) marshal() []byte { -+func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var b cryptobyte.Builder -@@ -1120,8 +1132,9 @@ func (m *certificateRequestMsgTLS13) marshal() []byte { - }) - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ var err error -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool { -@@ -1205,9 +1218,9 @@ type certificateMsg struct { - certificates [][]byte - } - --func (m *certificateMsg) marshal() (x []byte) { -+func (m *certificateMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var i int -@@ -1216,7 +1229,7 @@ func (m *certificateMsg) marshal() (x []byte) { - } - - length := 3 + 3*len(m.certificates) + i -- x = make([]byte, 4+length) -+ x := make([]byte, 4+length) - x[0] = typeCertificate - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) -@@ -1237,7 +1250,7 @@ func (m *certificateMsg) marshal() (x []byte) { - } - - m.raw = x -- return -+ return m.raw, nil - } - - func (m *certificateMsg) unmarshal(data []byte) bool { -@@ -1284,9 +1297,9 @@ type certificateMsgTLS13 struct { - scts bool - } - --func (m *certificateMsgTLS13) marshal() []byte { -+func (m *certificateMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var b cryptobyte.Builder -@@ -1304,8 +1317,9 @@ func (m *certificateMsgTLS13) marshal() []byte { - marshalCertificate(b, certificate) - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ var err error -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) { -@@ -1428,9 +1442,9 @@ type serverKeyExchangeMsg struct { - key []byte - } - --func (m *serverKeyExchangeMsg) marshal() []byte { -+func (m *serverKeyExchangeMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - length := len(m.key) - x := make([]byte, length+4) -@@ -1441,7 +1455,7 @@ func (m *serverKeyExchangeMsg) marshal() []byte { - copy(x[4:], m.key) - - m.raw = x -- return x -+ return x, nil - } - - func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { -@@ -1458,9 +1472,9 @@ type certificateStatusMsg struct { - response []byte - } - --func (m *certificateStatusMsg) marshal() []byte { -+func (m *certificateStatusMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var b cryptobyte.Builder -@@ -1472,8 +1486,9 @@ func (m *certificateStatusMsg) marshal() []byte { - }) - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ var err error -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func (m *certificateStatusMsg) unmarshal(data []byte) bool { -@@ -1492,10 +1507,10 @@ func (m *certificateStatusMsg) unmarshal(data []byte) bool { - - type serverHelloDoneMsg struct{} - --func (m *serverHelloDoneMsg) marshal() []byte { -+func (m *serverHelloDoneMsg) marshal() ([]byte, error) { - x := make([]byte, 4) - x[0] = typeServerHelloDone -- return x -+ return x, nil - } - - func (m *serverHelloDoneMsg) unmarshal(data []byte) bool { -@@ -1507,9 +1522,9 @@ type clientKeyExchangeMsg struct { - ciphertext []byte - } - --func (m *clientKeyExchangeMsg) marshal() []byte { -+func (m *clientKeyExchangeMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - length := len(m.ciphertext) - x := make([]byte, length+4) -@@ -1520,7 +1535,7 @@ func (m *clientKeyExchangeMsg) marshal() []byte { - copy(x[4:], m.ciphertext) - - m.raw = x -- return x -+ return x, nil - } - - func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { -@@ -1541,9 +1556,9 @@ type finishedMsg struct { - verifyData []byte - } - --func (m *finishedMsg) marshal() []byte { -+func (m *finishedMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var b cryptobyte.Builder -@@ -1552,8 +1567,9 @@ func (m *finishedMsg) marshal() []byte { - b.AddBytes(m.verifyData) - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ var err error -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func (m *finishedMsg) unmarshal(data []byte) bool { -@@ -1575,9 +1591,9 @@ type certificateRequestMsg struct { - certificateAuthorities [][]byte - } - --func (m *certificateRequestMsg) marshal() (x []byte) { -+func (m *certificateRequestMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - // See RFC 4346, Section 7.4.4. -@@ -1592,7 +1608,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) { - length += 2 + 2*len(m.supportedSignatureAlgorithms) - } - -- x = make([]byte, 4+length) -+ x := make([]byte, 4+length) - x[0] = typeCertificateRequest - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) -@@ -1627,7 +1643,7 @@ func (m *certificateRequestMsg) marshal() (x []byte) { - } - - m.raw = x -- return -+ return m.raw, nil - } - - func (m *certificateRequestMsg) unmarshal(data []byte) bool { -@@ -1713,9 +1729,9 @@ type certificateVerifyMsg struct { - signature []byte - } - --func (m *certificateVerifyMsg) marshal() (x []byte) { -+func (m *certificateVerifyMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - var b cryptobyte.Builder -@@ -1729,8 +1745,9 @@ func (m *certificateVerifyMsg) marshal() (x []byte) { - }) - }) - -- m.raw = b.BytesOrPanic() -- return m.raw -+ var err error -+ m.raw, err = b.Bytes() -+ return m.raw, err - } - - func (m *certificateVerifyMsg) unmarshal(data []byte) bool { -@@ -1753,15 +1770,15 @@ type newSessionTicketMsg struct { - ticket []byte - } - --func (m *newSessionTicketMsg) marshal() (x []byte) { -+func (m *newSessionTicketMsg) marshal() ([]byte, error) { - if m.raw != nil { -- return m.raw -+ return m.raw, nil - } - - // See RFC 5077, Section 3.3. - ticketLen := len(m.ticket) - length := 2 + 4 + ticketLen -- x = make([]byte, 4+length) -+ x := make([]byte, 4+length) - x[0] = typeNewSessionTicket - x[1] = uint8(length >> 16) - x[2] = uint8(length >> 8) -@@ -1772,7 +1789,7 @@ func (m *newSessionTicketMsg) marshal() (x []byte) { - - m.raw = x - -- return -+ return m.raw, nil - } - - func (m *newSessionTicketMsg) unmarshal(data []byte) bool { -@@ -1800,10 +1817,25 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool { - type helloRequestMsg struct { - } - --func (*helloRequestMsg) marshal() []byte { -- return []byte{typeHelloRequest, 0, 0, 0} -+func (*helloRequestMsg) marshal() ([]byte, error) { -+ return []byte{typeHelloRequest, 0, 0, 0}, nil - } - - func (*helloRequestMsg) unmarshal(data []byte) bool { - return len(data) == 4 - } -+ -+type transcriptHash interface { -+ Write([]byte) (int, error) -+} -+ -+// transcriptMsg is a helper used to marshal and hash messages which typically -+// are not written to the wire, and as such aren't hashed during Conn.writeRecord. -+func transcriptMsg(msg handshakeMessage, h transcriptHash) error { -+ data, err := msg.marshal() -+ if err != nil { -+ return err -+ } -+ h.Write(data) -+ return nil -+} -diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go -index bb8aea8670..5a6e89f5ba 100644 ---- a/src/crypto/tls/handshake_messages_test.go -+++ b/src/crypto/tls/handshake_messages_test.go -@@ -37,6 +37,15 @@ var tests = []interface{}{ - &certificateMsgTLS13{}, - } - -+func mustMarshal(t *testing.T, msg handshakeMessage) []byte { -+ t.Helper() -+ b, err := msg.marshal() -+ if err != nil { -+ t.Fatal(err) -+ } -+ return b -+} -+ - func TestMarshalUnmarshal(t *testing.T) { - rand := rand.New(rand.NewSource(time.Now().UnixNano())) - -@@ -55,7 +64,7 @@ func TestMarshalUnmarshal(t *testing.T) { - } - - m1 := v.Interface().(handshakeMessage) -- marshaled := m1.marshal() -+ marshaled := mustMarshal(t, m1) - m2 := iface.(handshakeMessage) - if !m2.unmarshal(marshaled) { - t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled) -@@ -408,12 +417,12 @@ func TestRejectEmptySCTList(t *testing.T) { - - var random [32]byte - sct := []byte{0x42, 0x42, 0x42, 0x42} -- serverHello := serverHelloMsg{ -+ serverHello := &serverHelloMsg{ - vers: VersionTLS12, - random: random[:], - scts: [][]byte{sct}, - } -- serverHelloBytes := serverHello.marshal() -+ serverHelloBytes := mustMarshal(t, serverHello) - - var serverHelloCopy serverHelloMsg - if !serverHelloCopy.unmarshal(serverHelloBytes) { -@@ -451,12 +460,12 @@ func TestRejectEmptySCT(t *testing.T) { - // not be zero length. - - var random [32]byte -- serverHello := serverHelloMsg{ -+ serverHello := &serverHelloMsg{ - vers: VersionTLS12, - random: random[:], - scts: [][]byte{nil}, - } -- serverHelloBytes := serverHello.marshal() -+ serverHelloBytes := mustMarshal(t, serverHello) - - var serverHelloCopy serverHelloMsg - if serverHelloCopy.unmarshal(serverHelloBytes) { -diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go -index 43f30e2fef..8d51e7e55f 100644 ---- a/src/crypto/tls/handshake_server.go -+++ b/src/crypto/tls/handshake_server.go -@@ -129,7 +129,9 @@ func (hs *serverHandshakeState) handshake() error { - - // readClientHello reads a ClientHello message and selects the protocol version. - func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) { -- msg, err := c.readHandshake() -+ // clientHelloMsg is included in the transcript, but we haven't initialized -+ // it yet. The respective handshake functions will record it themselves. -+ msg, err := c.readHandshake(nil) - if err != nil { - return nil, err - } -@@ -456,9 +458,10 @@ func (hs *serverHandshakeState) doResumeHandshake() error { - hs.hello.ticketSupported = hs.sessionState.usedOldKey - hs.finishedHash = newFinishedHash(c.vers, hs.suite) - hs.finishedHash.discardHandshakeBuffer() -- hs.finishedHash.Write(hs.clientHello.marshal()) -- hs.finishedHash.Write(hs.hello.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { -+ if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil { -+ return err -+ } -+ if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil { - return err - } - -@@ -496,24 +499,23 @@ func (hs *serverHandshakeState) doFullHandshake() error { - // certificates won't be used. - hs.finishedHash.discardHandshakeBuffer() - } -- hs.finishedHash.Write(hs.clientHello.marshal()) -- hs.finishedHash.Write(hs.hello.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { -+ if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil { -+ return err -+ } -+ if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil { - return err - } - - certMsg := new(certificateMsg) - certMsg.certificates = hs.cert.Certificate -- hs.finishedHash.Write(certMsg.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil { - return err - } - - if hs.hello.ocspStapling { - certStatus := new(certificateStatusMsg) - certStatus.response = hs.cert.OCSPStaple -- hs.finishedHash.Write(certStatus.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certStatus, &hs.finishedHash); err != nil { - return err - } - } -@@ -525,8 +527,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { - return err - } - if skx != nil { -- hs.finishedHash.Write(skx.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil { - return err - } - } -@@ -552,15 +553,13 @@ func (hs *serverHandshakeState) doFullHandshake() error { - if c.config.ClientCAs != nil { - certReq.certificateAuthorities = c.config.ClientCAs.Subjects() - } -- hs.finishedHash.Write(certReq.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certReq, &hs.finishedHash); err != nil { - return err - } - } - - helloDone := new(serverHelloDoneMsg) -- hs.finishedHash.Write(helloDone.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(helloDone, &hs.finishedHash); err != nil { - return err - } - -@@ -570,7 +569,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { - - var pub crypto.PublicKey // public key for client auth, if any - -- msg, err := c.readHandshake() -+ msg, err := c.readHandshake(&hs.finishedHash) - if err != nil { - return err - } -@@ -583,7 +582,6 @@ func (hs *serverHandshakeState) doFullHandshake() error { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } -- hs.finishedHash.Write(certMsg.marshal()) - - if err := c.processCertsFromClient(Certificate{ - Certificate: certMsg.certificates, -@@ -594,7 +592,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { - pub = c.peerCertificates[0].PublicKey - } - -- msg, err = c.readHandshake() -+ msg, err = c.readHandshake(&hs.finishedHash) - if err != nil { - return err - } -@@ -612,7 +610,6 @@ func (hs *serverHandshakeState) doFullHandshake() error { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(ckx, msg) - } -- hs.finishedHash.Write(ckx.marshal()) - - preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers) - if err != nil { -@@ -632,7 +629,10 @@ func (hs *serverHandshakeState) doFullHandshake() error { - // to the client's certificate. This allows us to verify that the client is in - // possession of the private key of the certificate. - if len(c.peerCertificates) > 0 { -- msg, err = c.readHandshake() -+ // certificateVerifyMsg is included in the transcript, but not until -+ // after we verify the handshake signature, since the state before -+ // this message was sent is used. -+ msg, err = c.readHandshake(nil) - if err != nil { - return err - } -@@ -667,7 +667,9 @@ func (hs *serverHandshakeState) doFullHandshake() error { - return errors.New("tls: invalid signature by the client certificate: " + err.Error()) - } - -- hs.finishedHash.Write(certVerify.marshal()) -+ if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil { -+ return err -+ } - } - - hs.finishedHash.discardHandshakeBuffer() -@@ -707,7 +709,10 @@ func (hs *serverHandshakeState) readFinished(out []byte) error { - return err - } - -- msg, err := c.readHandshake() -+ // finishedMsg is included in the transcript, but not until after we -+ // check the client version, since the state before this message was -+ // sent is used during verification. -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -@@ -724,7 +729,10 @@ func (hs *serverHandshakeState) readFinished(out []byte) error { - return errors.New("tls: client's Finished message is incorrect") - } - -- hs.finishedHash.Write(clientFinished.marshal()) -+ if err := transcriptMsg(clientFinished, &hs.finishedHash); err != nil { -+ return err -+ } -+ - copy(out, verify) - return nil - } -@@ -758,14 +766,16 @@ func (hs *serverHandshakeState) sendSessionTicket() error { - masterSecret: hs.masterSecret, - certificates: certsFromClient, - } -- var err error -- m.ticket, err = c.encryptTicket(state.marshal()) -+ stateBytes, err := state.marshal() -+ if err != nil { -+ return err -+ } -+ m.ticket, err = c.encryptTicket(stateBytes) - if err != nil { - return err - } - -- hs.finishedHash.Write(m.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(m, &hs.finishedHash); err != nil { - return err - } - -@@ -775,14 +785,13 @@ func (hs *serverHandshakeState) sendSessionTicket() error { - func (hs *serverHandshakeState) sendFinished(out []byte) error { - c := hs.c - -- if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { -+ if err := c.writeChangeCipherRecord(); err != nil { - return err - } - - finished := new(finishedMsg) - finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) -- hs.finishedHash.Write(finished.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil { - return err - } - -diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go -index f61b4c88ef..3d23b3f57d 100644 ---- a/src/crypto/tls/handshake_server_test.go -+++ b/src/crypto/tls/handshake_server_test.go -@@ -30,6 +30,13 @@ func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) { - testClientHelloFailure(t, serverConfig, m, "") - } - -+// testFatal is a hack to prevent the compiler from complaining that there is a -+// call to t.Fatal from a non-test goroutine -+func testFatal(t *testing.T, err error) { -+ t.Helper() -+ t.Fatal(err) -+} -+ - func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) { - c, s := localPipe(t) - go func() { -@@ -37,7 +44,9 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa - if ch, ok := m.(*clientHelloMsg); ok { - cli.vers = ch.vers - } -- cli.writeRecord(recordTypeHandshake, m.marshal()) -+ if _, err := cli.writeHandshakeRecord(m, nil); err != nil { -+ testFatal(t, err) -+ } - c.Close() - }() - ctx := context.Background() -@@ -194,7 +203,9 @@ func TestRenegotiationExtension(t *testing.T) { - go func() { - cli := Client(c, testConfig) - cli.vers = clientHello.vers -- cli.writeRecord(recordTypeHandshake, clientHello.marshal()) -+ if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil { -+ testFatal(t, err) -+ } - - buf := make([]byte, 1024) - n, err := c.Read(buf) -@@ -253,8 +264,10 @@ func TestTLS12OnlyCipherSuites(t *testing.T) { - go func() { - cli := Client(c, testConfig) - cli.vers = clientHello.vers -- cli.writeRecord(recordTypeHandshake, clientHello.marshal()) -- reply, err := cli.readHandshake() -+ if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil { -+ testFatal(t, err) -+ } -+ reply, err := cli.readHandshake(nil) - c.Close() - if err != nil { - replyChan <- err -@@ -308,8 +321,10 @@ func TestTLSPointFormats(t *testing.T) { - go func() { - cli := Client(c, testConfig) - cli.vers = clientHello.vers -- cli.writeRecord(recordTypeHandshake, clientHello.marshal()) -- reply, err := cli.readHandshake() -+ if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil { -+ testFatal(t, err) -+ } -+ reply, err := cli.readHandshake(nil) - c.Close() - if err != nil { - replyChan <- err -@@ -1425,7 +1440,9 @@ func TestSNIGivenOnFailure(t *testing.T) { - go func() { - cli := Client(c, testConfig) - cli.vers = clientHello.vers -- cli.writeRecord(recordTypeHandshake, clientHello.marshal()) -+ if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil { -+ testFatal(t, err) -+ } - c.Close() - }() - conn := Server(s, serverConfig) -diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go -index 6aa52698a3..d2ab263fc6 100644 ---- a/src/crypto/tls/handshake_server_tls13.go -+++ b/src/crypto/tls/handshake_server_tls13.go -@@ -298,7 +298,12 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error { - c.sendAlert(alertInternalError) - return errors.New("tls: internal error: failed to clone hash") - } -- transcript.Write(hs.clientHello.marshalWithoutBinders()) -+ clientHelloBytes, err := hs.clientHello.marshalWithoutBinders() -+ if err != nil { -+ c.sendAlert(alertInternalError) -+ return err -+ } -+ transcript.Write(clientHelloBytes) - pskBinder := hs.suite.finishedHash(binderKey, transcript) - if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) { - c.sendAlert(alertDecryptError) -@@ -389,8 +394,7 @@ func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error { - } - hs.sentDummyCCS = true - -- _, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) -- return err -+ return hs.c.writeChangeCipherRecord() - } - - func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error { -@@ -398,7 +402,9 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) - - // The first ClientHello gets double-hashed into the transcript upon a - // HelloRetryRequest. See RFC 8446, Section 4.4.1. -- hs.transcript.Write(hs.clientHello.marshal()) -+ if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { -+ return err -+ } - chHash := hs.transcript.Sum(nil) - hs.transcript.Reset() - hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) -@@ -414,8 +420,7 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) - selectedGroup: selectedGroup, - } - -- hs.transcript.Write(helloRetryRequest.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil { - return err - } - -@@ -423,7 +428,8 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) - return err - } - -- msg, err := c.readHandshake() -+ // clientHelloMsg is not included in the transcript. -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -@@ -514,9 +520,10 @@ func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool { - func (hs *serverHandshakeStateTLS13) sendServerParameters() error { - c := hs.c - -- hs.transcript.Write(hs.clientHello.marshal()) -- hs.transcript.Write(hs.hello.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil { -+ if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { -+ return err -+ } -+ if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil { - return err - } - -@@ -559,8 +566,7 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error { - encryptedExtensions.alpnProtocol = selectedProto - c.clientProtocol = selectedProto - -- hs.transcript.Write(encryptedExtensions.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(encryptedExtensions, hs.transcript); err != nil { - return err - } - -@@ -589,8 +595,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error { - certReq.certificateAuthorities = c.config.ClientCAs.Subjects() - } - -- hs.transcript.Write(certReq.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certReq, hs.transcript); err != nil { - return err - } - } -@@ -601,8 +606,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error { - certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0 - certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 - -- hs.transcript.Write(certMsg.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil { - return err - } - -@@ -633,8 +637,7 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error { - } - certVerifyMsg.signature = sig - -- hs.transcript.Write(certVerifyMsg.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil { - return err - } - -@@ -648,8 +651,7 @@ func (hs *serverHandshakeStateTLS13) sendServerFinished() error { - verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript), - } - -- hs.transcript.Write(finished.marshal()) -- if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil { -+ if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil { - return err - } - -@@ -710,7 +712,9 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { - finishedMsg := &finishedMsg{ - verifyData: hs.clientFinished, - } -- hs.transcript.Write(finishedMsg.marshal()) -+ if err := transcriptMsg(finishedMsg, hs.transcript); err != nil { -+ return err -+ } - - if !hs.shouldSendSessionTickets() { - return nil -@@ -735,8 +739,12 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { - SignedCertificateTimestamps: c.scts, - }, - } -- var err error -- m.label, err = c.encryptTicket(state.marshal()) -+ stateBytes, err := state.marshal() -+ if err != nil { -+ c.sendAlert(alertInternalError) -+ return err -+ } -+ m.label, err = c.encryptTicket(stateBytes) - if err != nil { - return err - } -@@ -755,7 +763,7 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { - // 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 { -+ if _, err := c.writeHandshakeRecord(m, nil); err != nil { - return err - } - -@@ -780,7 +788,7 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error { - // If we requested a client certificate, then the client must send a - // certificate message. If it's empty, no CertificateVerify is sent. - -- msg, err := c.readHandshake() -+ msg, err := c.readHandshake(hs.transcript) - if err != nil { - return err - } -@@ -790,7 +798,6 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } -- hs.transcript.Write(certMsg.marshal()) - - if err := c.processCertsFromClient(certMsg.certificate); err != nil { - return err -@@ -804,7 +811,10 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error { - } - - if len(certMsg.certificate.Certificate) != 0 { -- msg, err = c.readHandshake() -+ // certificateVerifyMsg is included in the transcript, but not until -+ // after we verify the handshake signature, since the state before -+ // this message was sent is used. -+ msg, err = c.readHandshake(nil) - if err != nil { - return err - } -@@ -835,7 +845,9 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error { - return errors.New("tls: invalid signature by the client certificate: " + err.Error()) - } - -- hs.transcript.Write(certVerify.marshal()) -+ if err := transcriptMsg(certVerify, hs.transcript); err != nil { -+ return err -+ } - } - - // If we waited until the client certificates to send session tickets, we -@@ -850,7 +862,8 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error { - func (hs *serverHandshakeStateTLS13) readClientFinished() error { - c := hs.c - -- msg, err := c.readHandshake() -+ // finishedMsg is not included in the transcript. -+ msg, err := c.readHandshake(nil) - if err != nil { - return err - } -diff --git a/src/crypto/tls/key_schedule.go b/src/crypto/tls/key_schedule.go -index 314016979a..185137ba06 100644 ---- a/src/crypto/tls/key_schedule.go -+++ b/src/crypto/tls/key_schedule.go -@@ -8,6 +8,7 @@ import ( - "crypto/elliptic" - "crypto/hmac" - "errors" -+ "fmt" - "hash" - "io" - "math/big" -@@ -42,8 +43,24 @@ func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []by - hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(context) - }) -+ hkdfLabelBytes, err := hkdfLabel.Bytes() -+ if err != nil { -+ // Rather than calling BytesOrPanic, we explicitly handle this error, in -+ // order to provide a reasonable error message. It should be basically -+ // impossible for this to panic, and routing errors back through the -+ // tree rooted in this function is quite painful. The labels are fixed -+ // size, and the context is either a fixed-length computed hash, or -+ // parsed from a field which has the same length limitation. As such, an -+ // error here is likely to only be caused during development. -+ // -+ // NOTE: another reasonable approach here might be to return a -+ // randomized slice if we encounter an error, which would break the -+ // connection, but avoid panicking. This would perhaps be safer but -+ // significantly more confusing to users. -+ panic(fmt.Errorf("failed to construct HKDF label: %s", err)) -+ } - out := make([]byte, length) -- n, err := hkdf.Expand(c.hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out) -+ n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out) - if err != nil || n != length { - panic("tls: HKDF-Expand-Label invocation failed unexpectedly") - } -diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go -index 6c1d20da20..b82ccd141e 100644 ---- a/src/crypto/tls/ticket.go -+++ b/src/crypto/tls/ticket.go -@@ -32,7 +32,7 @@ type sessionState struct { - usedOldKey bool - } - --func (m *sessionState) marshal() []byte { -+func (m *sessionState) marshal() ([]byte, error) { - var b cryptobyte.Builder - b.AddUint16(m.vers) - b.AddUint16(m.cipherSuite) -@@ -47,7 +47,7 @@ func (m *sessionState) marshal() []byte { - }) - } - }) -- return b.BytesOrPanic() -+ return b.Bytes() - } - - func (m *sessionState) unmarshal(data []byte) bool { -@@ -86,7 +86,7 @@ type sessionStateTLS13 struct { - certificate Certificate // CertificateEntry certificate_list<0..2^24-1>; - } - --func (m *sessionStateTLS13) marshal() []byte { -+func (m *sessionStateTLS13) marshal() ([]byte, error) { - var b cryptobyte.Builder - b.AddUint16(VersionTLS13) - b.AddUint8(0) // revision -@@ -96,7 +96,7 @@ func (m *sessionStateTLS13) marshal() []byte { - b.AddBytes(m.resumptionSecret) - }) - marshalCertificate(&b, m.certificate) -- return b.BytesOrPanic() -+ return b.Bytes() - } - - func (m *sessionStateTLS13) unmarshal(data []byte) bool { --- -2.33.0 - diff --git a/0033-mime-multipart-limit-memory-inode-consumption-of-Rea.patch b/0033-mime-multipart-limit-memory-inode-consumption-of-Rea.patch deleted file mode 100644 index 4de87a1b8420cb784fe39ffe4a75910b7f5c3508..0000000000000000000000000000000000000000 --- a/0033-mime-multipart-limit-memory-inode-consumption-of-Rea.patch +++ /dev/null @@ -1,727 +0,0 @@ -From ac28aeccf77fed9d34b658fbe3507d01713ae840 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Wed, 25 Jan 2023 09:27:01 -0800 -Subject: [PATCH] mime/multipart: limit memory/inode consumption of ReadForm - -Reader.ReadForm is documented as storing "up to maxMemory bytes + 10MB" -in memory. Parsed forms can consume substantially more memory than -this limit, since ReadForm does not account for map entry overhead -and MIME headers. - -In addition, while the amount of disk memory consumed by ReadForm can -be constrained by limiting the size of the parsed input, ReadForm will -create one temporary file per form part stored on disk, potentially -consuming a large number of inodes. - -Update ReadForm's memory accounting to include part names, -MIME headers, and map entry overhead. - -Update ReadForm to store all on-disk file parts in a single -temporary file. - -Files returned by FileHeader.Open are documented as having a concrete -type of *os.File when a file is stored on disk. The change to use a -single temporary file for all parts means that this is no longer the -case when a form contains more than a single file part stored on disk. - -The previous behavior of storing each file part in a separate disk -file may be reenabled with GODEBUG=multipartfiles=distinct. - -Update Reader.NextPart and Reader.NextRawPart to set a 10MiB cap -on the size of MIME headers. - -Thanks to Jakob Ackermann (@das7pad) for reporting this issue. - -Updates #58006 -Fixes #58362 -Fixes CVE-2022-41725 - -Change-Id: Ibd780a6c4c83ac8bcfd3cbe344f042e9940f2eab -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1714276 -Reviewed-by: Julie Qiu -TryBot-Result: Security TryBots -Reviewed-by: Roland Shoemaker -Run-TryBot: Damien Neil -(cherry picked from commit ed4664330edcd91b24914c9371c377c132dbce8c) -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1728949 -Reviewed-by: Tatiana Bradley -Run-TryBot: Roland Shoemaker -Reviewed-by: Damien Neil -Reviewed-on: https://go-review.googlesource.com/c/go/+/468116 -TryBot-Result: Gopher Robot -Reviewed-by: Than McIntosh -Run-TryBot: Michael Pratt -Auto-Submit: Michael Pratt - -Reference:https://go-review.googlesource.com/c/go/+/468116 -Conflict:NA ---- - src/internal/godebug/godebug.go | 34 +++++++ - src/internal/godebug/godebug_test.go | 34 +++++++ - src/mime/multipart/formdata.go | 132 ++++++++++++++++++++----- - src/mime/multipart/formdata_test.go | 140 ++++++++++++++++++++++++++- - src/mime/multipart/multipart.go | 29 ++++-- - src/mime/multipart/readmimeheader.go | 14 +++ - src/net/http/request_test.go | 2 +- - src/net/textproto/reader.go | 18 ++++ - 8 files changed, 364 insertions(+), 39 deletions(-) - create mode 100644 src/internal/godebug/godebug.go - create mode 100644 src/internal/godebug/godebug_test.go - create mode 100644 src/mime/multipart/readmimeheader.go - -diff --git a/src/internal/godebug/godebug.go b/src/internal/godebug/godebug.go -new file mode 100644 -index 0000000..ac434e5 ---- /dev/null -+++ b/src/internal/godebug/godebug.go -@@ -0,0 +1,34 @@ -+// Copyright 2021 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+// Package godebug parses the GODEBUG environment variable. -+package godebug -+ -+import "os" -+ -+// Get returns the value for the provided GODEBUG key. -+func Get(key string) string { -+ return get(os.Getenv("GODEBUG"), key) -+} -+ -+// get returns the value part of key=value in s (a GODEBUG value). -+func get(s, key string) string { -+ for i := 0; i < len(s)-len(key)-1; i++ { -+ if i > 0 && s[i-1] != ',' { -+ continue -+ } -+ afterKey := s[i+len(key):] -+ if afterKey[0] != '=' || s[i:i+len(key)] != key { -+ continue -+ } -+ val := afterKey[1:] -+ for i, b := range val { -+ if b == ',' { -+ return val[:i] -+ } -+ } -+ return val -+ } -+ return "" -+} -diff --git a/src/internal/godebug/godebug_test.go b/src/internal/godebug/godebug_test.go -new file mode 100644 -index 0000000..41b9117 ---- /dev/null -+++ b/src/internal/godebug/godebug_test.go -@@ -0,0 +1,34 @@ -+// Copyright 2021 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+ -+package godebug -+ -+import "testing" -+ -+func TestGet(t *testing.T) { -+ tests := []struct { -+ godebug string -+ key string -+ want string -+ }{ -+ {"", "", ""}, -+ {"", "foo", ""}, -+ {"foo=bar", "foo", "bar"}, -+ {"foo=bar,after=x", "foo", "bar"}, -+ {"before=x,foo=bar,after=x", "foo", "bar"}, -+ {"before=x,foo=bar", "foo", "bar"}, -+ {",,,foo=bar,,,", "foo", "bar"}, -+ {"foodecoy=wrong,foo=bar", "foo", "bar"}, -+ {"foo=", "foo", ""}, -+ {"foo", "foo", ""}, -+ {",foo", "foo", ""}, -+ {"foo=bar,baz", "loooooooong", ""}, -+ } -+ for _, tt := range tests { -+ got := get(tt.godebug, tt.key) -+ if got != tt.want { -+ t.Errorf("get(%q, %q) = %q; want %q", tt.godebug, tt.key, got, tt.want) -+ } -+ } -+} -diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go -index fca5f9e..a7d4ca9 100644 ---- a/src/mime/multipart/formdata.go -+++ b/src/mime/multipart/formdata.go -@@ -7,6 +7,7 @@ package multipart - import ( - "bytes" - "errors" -+ "internal/godebug" - "io" - "math" - "net/textproto" -@@ -33,23 +34,58 @@ func (r *Reader) ReadForm(maxMemory int64) (*Form, error) { - - func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - form := &Form{make(map[string][]string), make(map[string][]*FileHeader)} -+ var ( -+ file *os.File -+ fileOff int64 -+ ) -+ numDiskFiles := 0 -+ multipartFiles := godebug.Get("multipartfiles") -+ combineFiles := multipartFiles != "distinct" - defer func() { -+ if file != nil { -+ if cerr := file.Close(); err == nil { -+ err = cerr -+ } -+ } -+ if combineFiles && numDiskFiles > 1 { -+ for _, fhs := range form.File { -+ for _, fh := range fhs { -+ fh.tmpshared = true -+ } -+ } -+ } - if err != nil { - form.RemoveAll() -+ if file != nil { -+ os.Remove(file.Name()) -+ } - } - }() - -- // Reserve an additional 10 MB for non-file parts. -- maxValueBytes := maxMemory + int64(10<<20) -- if maxValueBytes <= 0 { -+ // maxFileMemoryBytes is the maximum bytes of file data we will store in memory. -+ // Data past this limit is written to disk. -+ // This limit strictly applies to content, not metadata (filenames, MIME headers, etc.), -+ // since metadata is always stored in memory, not disk. -+ // -+ // maxMemoryBytes is the maximum bytes we will store in memory, including file content, -+ // non-file part values, metdata, and map entry overhead. -+ // -+ // We reserve an additional 10 MB in maxMemoryBytes for non-file data. -+ // -+ // The relationship between these parameters, as well as the overly-large and -+ // unconfigurable 10 MB added on to maxMemory, is unfortunate but difficult to change -+ // within the constraints of the API as documented. -+ maxFileMemoryBytes := maxMemory -+ maxMemoryBytes := maxMemory + int64(10<<20) -+ if maxMemoryBytes <= 0 { - if maxMemory < 0 { -- maxValueBytes = 0 -+ maxMemoryBytes = 0 - } else { -- maxValueBytes = math.MaxInt64 -+ maxMemoryBytes = math.MaxInt64 - } - } - for { -- p, err := r.NextPart() -+ p, err := r.nextPart(false, maxMemoryBytes) - if err == io.EOF { - break - } -@@ -63,16 +99,27 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - } - filename := p.FileName() - -+ // Multiple values for the same key (one map entry, longer slice) are cheaper -+ // than the same number of values for different keys (many map entries), but -+ // using a consistent per-value cost for overhead is simpler. -+ maxMemoryBytes -= int64(len(name)) -+ maxMemoryBytes -= 100 // map overhead -+ if maxMemoryBytes < 0 { -+ // We can't actually take this path, since nextPart would already have -+ // rejected the MIME headers for being too large. Check anyway. -+ return nil, ErrMessageTooLarge -+ } -+ - var b bytes.Buffer - - if filename == "" { - // value, store as string in memory -- n, err := io.CopyN(&b, p, maxValueBytes+1) -+ n, err := io.CopyN(&b, p, maxMemoryBytes+1) - if err != nil && err != io.EOF { - return nil, err - } -- maxValueBytes -= n -- if maxValueBytes < 0 { -+ maxMemoryBytes -= n -+ if maxMemoryBytes < 0 { - return nil, ErrMessageTooLarge - } - form.Value[name] = append(form.Value[name], b.String()) -@@ -80,35 +127,45 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - } - - // file, store in memory or on disk -+ maxMemoryBytes -= mimeHeaderSize(p.Header) -+ if maxMemoryBytes < 0 { -+ return nil, ErrMessageTooLarge -+ } - fh := &FileHeader{ - Filename: filename, - Header: p.Header, - } -- n, err := io.CopyN(&b, p, maxMemory+1) -+ n, err := io.CopyN(&b, p, maxFileMemoryBytes+1) - if err != nil && err != io.EOF { - return nil, err - } -- if n > maxMemory { -- // too big, write to disk and flush buffer -- file, err := os.CreateTemp("", "multipart-") -- if err != nil { -- return nil, err -+ if n > maxFileMemoryBytes { -+ if file == nil { -+ file, err = os.CreateTemp(r.tempDir, "multipart-") -+ if err != nil { -+ return nil, err -+ } - } -+ numDiskFiles++ - size, err := io.Copy(file, io.MultiReader(&b, p)) -- if cerr := file.Close(); err == nil { -- err = cerr -- } - if err != nil { -- os.Remove(file.Name()) - return nil, err - } - fh.tmpfile = file.Name() - fh.Size = size -+ fh.tmpoff = fileOff -+ fileOff += size -+ if !combineFiles { -+ if err := file.Close(); err != nil { -+ return nil, err -+ } -+ file = nil -+ } - } else { - fh.content = b.Bytes() - fh.Size = int64(len(fh.content)) -- maxMemory -= n -- maxValueBytes -= n -+ maxFileMemoryBytes -= n -+ maxMemoryBytes -= n - } - form.File[name] = append(form.File[name], fh) - } -@@ -116,6 +173,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - return form, nil - } - -+func mimeHeaderSize(h textproto.MIMEHeader) (size int64) { -+ for k, vs := range h { -+ size += int64(len(k)) -+ size += 100 // map entry overhead -+ for _, v := range vs { -+ size += int64(len(v)) -+ } -+ } -+ return size -+} -+ - // Form is a parsed multipart form. - // Its File parts are stored either in memory or on disk, - // and are accessible via the *FileHeader's Open method. -@@ -133,7 +201,7 @@ func (f *Form) RemoveAll() error { - for _, fh := range fhs { - if fh.tmpfile != "" { - e := os.Remove(fh.tmpfile) -- if e != nil && err == nil { -+ if e != nil && !errors.Is(e, os.ErrNotExist) && err == nil { - err = e - } - } -@@ -148,15 +216,25 @@ type FileHeader struct { - Header textproto.MIMEHeader - Size int64 - -- content []byte -- tmpfile string -+ content []byte -+ tmpfile string -+ tmpoff int64 -+ tmpshared bool - } - - // Open opens and returns the FileHeader's associated File. - func (fh *FileHeader) Open() (File, error) { - if b := fh.content; b != nil { - r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))) -- return sectionReadCloser{r}, nil -+ return sectionReadCloser{r, nil}, nil -+ } -+ if fh.tmpshared { -+ f, err := os.Open(fh.tmpfile) -+ if err != nil { -+ return nil, err -+ } -+ r := io.NewSectionReader(f, fh.tmpoff, fh.Size) -+ return sectionReadCloser{r, f}, nil - } - return os.Open(fh.tmpfile) - } -@@ -175,8 +253,12 @@ type File interface { - - type sectionReadCloser struct { - *io.SectionReader -+ io.Closer - } - - func (rc sectionReadCloser) Close() error { -+ if rc.Closer != nil { -+ return rc.Closer.Close() -+ } - return nil - } -diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go -index e3a3a3e..5cded71 100644 ---- a/src/mime/multipart/formdata_test.go -+++ b/src/mime/multipart/formdata_test.go -@@ -6,8 +6,10 @@ package multipart - - import ( - "bytes" -+ "fmt" - "io" - "math" -+ "net/textproto" - "os" - "strings" - "testing" -@@ -208,8 +210,8 @@ Content-Disposition: form-data; name="largetext" - maxMemory int64 - err error - }{ -- {"smaller", 50, nil}, -- {"exact-fit", 25, nil}, -+ {"smaller", 50 + int64(len("largetext")) + 100, nil}, -+ {"exact-fit", 25 + int64(len("largetext")) + 100, nil}, - {"too-large", 0, ErrMessageTooLarge}, - } - for _, tc := range testCases { -@@ -224,7 +226,7 @@ Content-Disposition: form-data; name="largetext" - defer f.RemoveAll() - } - if tc.err != err { -- t.Fatalf("ReadForm error - got: %v; expected: %v", tc.err, err) -+ t.Fatalf("ReadForm error - got: %v; expected: %v", err, tc.err) - } - if err == nil { - if g := f.Value["largetext"][0]; g != largeTextValue { -@@ -234,3 +236,135 @@ Content-Disposition: form-data; name="largetext" - }) - } - } -+ -+// TestReadForm_MetadataTooLarge verifies that we account for the size of field names, -+// MIME headers, and map entry overhead while limiting the memory consumption of parsed forms. -+func TestReadForm_MetadataTooLarge(t *testing.T) { -+ for _, test := range []struct { -+ name string -+ f func(*Writer) -+ }{{ -+ name: "large name", -+ f: func(fw *Writer) { -+ name := strings.Repeat("a", 10<<20) -+ w, _ := fw.CreateFormField(name) -+ w.Write([]byte("value")) -+ }, -+ }, { -+ name: "large MIME header", -+ f: func(fw *Writer) { -+ h := make(textproto.MIMEHeader) -+ h.Set("Content-Disposition", `form-data; name="a"`) -+ h.Set("X-Foo", strings.Repeat("a", 10<<20)) -+ w, _ := fw.CreatePart(h) -+ w.Write([]byte("value")) -+ }, -+ }, { -+ name: "many parts", -+ f: func(fw *Writer) { -+ for i := 0; i < 110000; i++ { -+ w, _ := fw.CreateFormField("f") -+ w.Write([]byte("v")) -+ } -+ }, -+ }} { -+ t.Run(test.name, func(t *testing.T) { -+ var buf bytes.Buffer -+ fw := NewWriter(&buf) -+ test.f(fw) -+ if err := fw.Close(); err != nil { -+ t.Fatal(err) -+ } -+ fr := NewReader(&buf, fw.Boundary()) -+ _, err := fr.ReadForm(0) -+ if err != ErrMessageTooLarge { -+ t.Errorf("fr.ReadForm() = %v, want ErrMessageTooLarge", err) -+ } -+ }) -+ } -+} -+ -+// TestReadForm_ManyFiles_Combined tests that a multipart form containing many files only -+// results in a single on-disk file. -+func TestReadForm_ManyFiles_Combined(t *testing.T) { -+ const distinct = false -+ testReadFormManyFiles(t, distinct) -+} -+ -+// TestReadForm_ManyFiles_Distinct tests that setting GODEBUG=multipartfiles=distinct -+// results in every file in a multipart form being placed in a distinct on-disk file. -+func TestReadForm_ManyFiles_Distinct(t *testing.T) { -+ t.Setenv("GODEBUG", "multipartfiles=distinct") -+ const distinct = true -+ testReadFormManyFiles(t, distinct) -+} -+ -+func testReadFormManyFiles(t *testing.T, distinct bool) { -+ var buf bytes.Buffer -+ fw := NewWriter(&buf) -+ const numFiles = 10 -+ for i := 0; i < numFiles; i++ { -+ name := fmt.Sprint(i) -+ w, err := fw.CreateFormFile(name, name) -+ if err != nil { -+ t.Fatal(err) -+ } -+ w.Write([]byte(name)) -+ } -+ if err := fw.Close(); err != nil { -+ t.Fatal(err) -+ } -+ fr := NewReader(&buf, fw.Boundary()) -+ fr.tempDir = t.TempDir() -+ form, err := fr.ReadForm(0) -+ if err != nil { -+ t.Fatal(err) -+ } -+ for i := 0; i < numFiles; i++ { -+ name := fmt.Sprint(i) -+ if got := len(form.File[name]); got != 1 { -+ t.Fatalf("form.File[%q] has %v entries, want 1", name, got) -+ } -+ fh := form.File[name][0] -+ file, err := fh.Open() -+ if err != nil { -+ t.Fatalf("form.File[%q].Open() = %v", name, err) -+ } -+ if distinct { -+ if _, ok := file.(*os.File); !ok { -+ t.Fatalf("form.File[%q].Open: %T, want *os.File", name, file) -+ } -+ } -+ got, err := io.ReadAll(file) -+ file.Close() -+ if string(got) != name || err != nil { -+ t.Fatalf("read form.File[%q]: %q, %v; want %q, nil", name, string(got), err, name) -+ } -+ } -+ dir, err := os.Open(fr.tempDir) -+ if err != nil { -+ t.Fatal(err) -+ } -+ defer dir.Close() -+ names, err := dir.Readdirnames(0) -+ if err != nil { -+ t.Fatal(err) -+ } -+ wantNames := 1 -+ if distinct { -+ wantNames = numFiles -+ } -+ if len(names) != wantNames { -+ t.Fatalf("temp dir contains %v files; want 1", len(names)) -+ } -+ if err := form.RemoveAll(); err != nil { -+ t.Fatalf("form.RemoveAll() = %v", err) -+ } -+ names, err = dir.Readdirnames(0) -+ if err != nil { -+ t.Fatal(err) -+ } -+ if len(names) != 0 { -+ t.Fatalf("temp dir contains %v files; want 0", len(names)) -+ } -+} -diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go -index 81bf722..465b376 100644 ---- a/src/mime/multipart/multipart.go -+++ b/src/mime/multipart/multipart.go -@@ -128,12 +128,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) { - return n, r.err - } - --func newPart(mr *Reader, rawPart bool) (*Part, error) { -+func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { - bp := &Part{ - Header: make(map[string][]string), - mr: mr, - } -- if err := bp.populateHeaders(); err != nil { -+ if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil { - return nil, err - } - bp.r = partReader{bp} -@@ -149,11 +149,15 @@ func newPart(mr *Reader, rawPart bool) (*Part, error) { - return bp, nil - } - --func (bp *Part) populateHeaders() error { -- r := textproto.NewReader(bp.mr.bufReader) -- header, err := r.ReadMIMEHeader() -+func (p *Part) populateHeaders(maxMIMEHeaderSize int64) error { -+ r := textproto.NewReader(p.mr.bufReader) -+ header, err := readMIMEHeader(r, maxMIMEHeaderSize) - if err == nil { -- bp.Header = header -+ p.Header = header -+ } -+ // TODO: Add a distinguishable error to net/textproto. -+ if err != nil && err.Error() == "message too large" { -+ err = ErrMessageTooLarge - } - return err - } -@@ -294,6 +298,7 @@ func (p *Part) Close() error { - // isn't supported. - type Reader struct { - bufReader *bufio.Reader -+ tempDir string // used in tests - - currentPart *Part - partsRead int -@@ -304,6 +309,10 @@ type Reader struct { - dashBoundary []byte // "--boundary" - } - -+// maxMIMEHeaderSize is the maximum size of a MIME header we will parse, -+// including header keys, values, and map overhead. -+const maxMIMEHeaderSize = 10 << 20 -+ - // NextPart returns the next part in the multipart or an error. - // When there are no more parts, the error io.EOF is returned. - // -@@ -311,7 +320,7 @@ type Reader struct { - // has a value of "quoted-printable", that header is instead - // hidden and the body is transparently decoded during Read calls. - func (r *Reader) NextPart() (*Part, error) { -- return r.nextPart(false) -+ return r.nextPart(false, maxMIMEHeaderSize) - } - - // NextRawPart returns the next part in the multipart or an error. -@@ -320,10 +329,10 @@ func (r *Reader) NextPart() (*Part, error) { - // Unlike NextPart, it does not have special handling for - // "Content-Transfer-Encoding: quoted-printable". - func (r *Reader) NextRawPart() (*Part, error) { -- return r.nextPart(true) -+ return r.nextPart(true, maxMIMEHeaderSize) - } - --func (r *Reader) nextPart(rawPart bool) (*Part, error) { -+func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { - if r.currentPart != nil { - r.currentPart.Close() - } -@@ -348,7 +357,7 @@ func (r *Reader) nextPart(rawPart bool) (*Part, error) { - - if r.isBoundaryDelimiterLine(line) { - r.partsRead++ -- bp, err := newPart(r, rawPart) -+ bp, err := newPart(r, rawPart, maxMIMEHeaderSize) - if err != nil { - return nil, err - } -diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go -new file mode 100644 -index 0000000..6836928 ---- /dev/null -+++ b/src/mime/multipart/readmimeheader.go -@@ -0,0 +1,14 @@ -+// Copyright 2023 The Go Authors. All rights reserved. -+// Use of this source code is governed by a BSD-style -+// license that can be found in the LICENSE file. -+package multipart -+ -+import ( -+ "net/textproto" -+ _ "unsafe" // for go:linkname -+) -+ -+// readMIMEHeader is defined in package net/textproto. -+// -+//go:linkname readMIMEHeader net/textproto.readMIMEHeader -+func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error) -diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go -index 4e0c4ba..fac12b7 100644 ---- a/src/net/http/request_test.go -+++ b/src/net/http/request_test.go -@@ -1110,7 +1110,7 @@ func testMissingFile(t *testing.T, req *Request) { - t.Errorf("FormFile file = %v, want nil", f) - } - if fh != nil { -- t.Errorf("FormFile file header = %q, want nil", fh) -+ t.Errorf("FormFile file header = %v, want nil", fh) - } - if err != ErrMissingFile { - t.Errorf("FormFile err = %q, want ErrMissingFile", err) -diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go -index 5c3084f..83db3b2 100644 ---- a/src/net/textproto/reader.go -+++ b/src/net/textproto/reader.go -@@ -7,8 +7,10 @@ package textproto - import ( - "bufio" - "bytes" -+ "errors" - "fmt" - "io" -+ "math" - "strconv" - "strings" - "sync" -@@ -481,6 +483,12 @@ func (r *Reader) ReadDotLines() ([]string, error) { - // } - // - func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { -+ return readMIMEHeader(r, math.MaxInt64) -+} -+ -+// readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. -+// It is called by the mime/multipart package. -+func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { - // Avoid lots of small slice allocations later by allocating one - // large one ahead of time which we'll cut up into smaller - // slices. If this isn't big enough later, we allocate small ones. -@@ -529,6 +537,16 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { - value := string(kv[i:]) - - vv := m[key] -+ if vv == nil { -+ lim -= int64(len(key)) -+ lim -= 100 // map entry overhead -+ } -+ lim -= int64(len(value)) -+ if lim < 0 { -+ // TODO: This should be a distinguishable error (ErrMessageTooLarge) -+ // to allow mime/multipart to detect it. -+ return m, errors.New("message too large") -+ } - if vv == nil && len(strs) > 0 { - // More than likely this will be a single-element key. - // Most headers aren't multi-valued. --- -2.33.0 - diff --git a/0034-release-branch.go1.19-net-textproto-avoid-overpredic.patch b/0034-release-branch.go1.19-net-textproto-avoid-overpredic.patch deleted file mode 100644 index 169a44da63ad9b8213fb605480d1452109f567e9..0000000000000000000000000000000000000000 --- a/0034-release-branch.go1.19-net-textproto-avoid-overpredic.patch +++ /dev/null @@ -1,197 +0,0 @@ -From da60f6100bbf663997609d8168af317dd32e83b9 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Fri, 10 Mar 2023 14:21:05 -0800 -Subject: [PATCH 1/6] [release-branch.go1.19] net/textproto: avoid - overpredicting the number of MIME header keys - -A parsed MIME header is a map[string][]string. In the common case, -a header contains many one-element []string slices. To avoid -allocating a separate slice for each key, ReadMIMEHeader looks -ahead in the input to predict the number of keys that will be -parsed, and allocates a single []string of that length. -The individual slices are then allocated out of the larger one. - -The prediction of the number of header keys was done by counting -newlines in the input buffer, which does not take into account -header continuation lines (where a header key/value spans multiple -lines) or the end of the header block and the start of the body. -This could lead to a substantial amount of overallocation, for -example when the body consists of nothing but a large block of -newlines. - -Fix header key count prediction to take into account the end of -the headers (indicated by a blank line) and continuation lines -(starting with whitespace). - -Thanks to Jakob Ackermann (@das7pad) for reporting this issue. - -Fixes CVE-2023-24534 -For #58975 -Fixes #59267 - -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802452 -Run-TryBot: Damien Neil -Reviewed-by: Roland Shoemaker -Reviewed-by: Julie Qiu -(cherry picked from commit f739f080a72fd5b06d35c8e244165159645e2ed6) -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802393 -Reviewed-by: Damien Neil -Run-TryBot: Roland Shoemaker -Change-Id: I675451438d619a9130360c56daf529559004903f -Reviewed-on: https://go-review.googlesource.com/c/go/+/481982 -Run-TryBot: Michael Knyszek -TryBot-Result: Gopher Robot -Reviewed-by: Matthew Dempsky -Auto-Submit: Michael Knyszek ---- - src/net/textproto/reader.go | 30 ++++++++++------ - src/net/textproto/reader_test.go | 59 ++++++++++++++++++++++++++++++++ - 2 files changed, 78 insertions(+), 11 deletions(-) - -diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go -index 83db3b21ea9..98056b0de55 100644 ---- a/src/net/textproto/reader.go -+++ b/src/net/textproto/reader.go -@@ -493,8 +493,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { - // large one ahead of time which we'll cut up into smaller - // slices. If this isn't big enough later, we allocate small ones. - var strs []string -- hint := r.upcomingHeaderNewlines() -+ hint := r.upcomingHeaderKeys() - if hint > 0 { -+ if hint > 1000 { -+ hint = 1000 // set a cap to avoid overallocation -+ } - strs = make([]string, hint) - } - -@@ -579,9 +582,11 @@ func mustHaveFieldNameColon(line []byte) error { - return nil - } - --// upcomingHeaderNewlines returns an approximation of the number of newlines -+var nl = []byte("\n") -+ -+// upcomingHeaderKeys returns an approximation of the number of keys - // that will be in this header. If it gets confused, it returns 0. --func (r *Reader) upcomingHeaderNewlines() (n int) { -+func (r *Reader) upcomingHeaderKeys() (n int) { - // Try to determine the 'hint' size. - r.R.Peek(1) // force a buffer load if empty - s := r.R.Buffered() -@@ -589,17 +594,20 @@ func (r *Reader) upcomingHeaderNewlines() (n int) { - return - } - peek, _ := r.R.Peek(s) -- for len(peek) > 0 { -- i := bytes.IndexByte(peek, '\n') -- if i < 3 { -- // Not present (-1) or found within the next few bytes, -- // implying we're at the end ("\r\n\r\n" or "\n\n") -- return -+ for len(peek) > 0 && n < 1000 { -+ var line []byte -+ line, peek, _ = bytes.Cut(peek, nl) -+ if len(line) == 0 || (len(line) == 1 && line[0] == '\r') { -+ // Blank line separating headers from the body. -+ break -+ } -+ if line[0] == ' ' || line[0] == '\t' { -+ // Folded continuation of the previous line. -+ continue - } - n++ -- peek = peek[i+1:] - } -- return -+ return n - } - - // CanonicalMIMEHeaderKey returns the canonical format of the -diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go -index 3124d438fa5..3ae0de13530 100644 ---- a/src/net/textproto/reader_test.go -+++ b/src/net/textproto/reader_test.go -@@ -9,6 +9,7 @@ import ( - "bytes" - "io" - "reflect" -+ "runtime" - "strings" - "testing" - ) -@@ -127,6 +128,42 @@ func TestReadMIMEHeaderSingle(t *testing.T) { - } - } - -+// TestReaderUpcomingHeaderKeys is testing an internal function, but it's very -+// difficult to test well via the external API. -+func TestReaderUpcomingHeaderKeys(t *testing.T) { -+ for _, test := range []struct { -+ input string -+ want int -+ }{{ -+ input: "", -+ want: 0, -+ }, { -+ input: "A: v", -+ want: 1, -+ }, { -+ input: "A: v\r\nB: v\r\n", -+ want: 2, -+ }, { -+ input: "A: v\nB: v\n", -+ want: 2, -+ }, { -+ input: "A: v\r\n continued\r\n still continued\r\nB: v\r\n\r\n", -+ want: 2, -+ }, { -+ input: "A: v\r\n\r\nB: v\r\nC: v\r\n", -+ want: 1, -+ }, { -+ input: "A: v" + strings.Repeat("\n", 1000), -+ want: 1, -+ }} { -+ r := reader(test.input) -+ got := r.upcomingHeaderKeys() -+ if test.want != got { -+ t.Fatalf("upcomingHeaderKeys(%q): %v; want %v", test.input, got, test.want) -+ } -+ } -+} -+ - func TestReadMIMEHeaderNoKey(t *testing.T) { - r := reader(": bar\ntest-1: 1\n\n") - m, err := r.ReadMIMEHeader() -@@ -223,6 +260,28 @@ func TestReadMIMEHeaderTrimContinued(t *testing.T) { - } - } - -+// Test that reading a header doesn't overallocate. Issue 58975. -+func TestReadMIMEHeaderAllocations(t *testing.T) { -+ var totalAlloc uint64 -+ const count = 200 -+ for i := 0; i < count; i++ { -+ r := reader("A: b\r\n\r\n" + strings.Repeat("\n", 4096)) -+ var m1, m2 runtime.MemStats -+ runtime.ReadMemStats(&m1) -+ _, err := r.ReadMIMEHeader() -+ if err != nil { -+ t.Fatalf("ReadMIMEHeader: %v", err) -+ } -+ runtime.ReadMemStats(&m2) -+ totalAlloc += m2.TotalAlloc - m1.TotalAlloc -+ } -+ // 32k is large and we actually allocate substantially less, -+ // but prior to the fix for #58975 we allocated ~400k in this case. -+ if got, want := totalAlloc/count, uint64(32768); got > want { -+ t.Fatalf("ReadMIMEHeader allocated %v bytes, want < %v", got, want) -+ } -+} -+ - type readResponseTest struct { - in string - inCode int --- -2.33.0 - diff --git a/0035-release-branch.go1.19-go-scanner-reject-large-line-a.patch b/0035-release-branch.go1.19-go-scanner-reject-large-line-a.patch deleted file mode 100644 index 1cfb32ebd1f5f055ab9b959dbabfa1e56855b60e..0000000000000000000000000000000000000000 --- a/0035-release-branch.go1.19-go-scanner-reject-large-line-a.patch +++ /dev/null @@ -1,91 +0,0 @@ -From bc1a60a500731fdd144e0fc5e1d750103819a74f Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Wed, 22 Mar 2023 09:33:22 -0700 -Subject: [PATCH 2/6] [release-branch.go1.19] go/scanner: reject large line and - column numbers in //line directives - -Setting a large line or column number using a //line directive can cause -integer overflow even in small source files. - -Limit line and column numbers in //line directives to 2^30-1, which -is small enough to avoid int32 overflow on all reasonbly-sized files. - -Fixes CVE-2023-24537 -Fixes #59273 -For #59180 - -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802456 -Reviewed-by: Julie Qiu -Reviewed-by: Roland Shoemaker -Run-TryBot: Damien Neil -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802611 -Reviewed-by: Damien Neil -Change-Id: Ifdfa192d54f722d781a4d8c5f35b5fb72d122168 -Reviewed-on: https://go-review.googlesource.com/c/go/+/481986 -Reviewed-by: Matthew Dempsky -TryBot-Result: Gopher Robot -Run-TryBot: Michael Knyszek -Auto-Submit: Michael Knyszek ---- - src/go/parser/parser_test.go | 16 ++++++++++++++++ - src/go/scanner/scanner.go | 7 +++++-- - 2 files changed, 21 insertions(+), 2 deletions(-) - -diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go -index 1a46c878663..993df6315f1 100644 ---- a/src/go/parser/parser_test.go -+++ b/src/go/parser/parser_test.go -@@ -746,3 +746,19 @@ func TestScopeDepthLimit(t *testing.T) { - } - } - } -+ -+// TestIssue59180 tests that line number overflow doesn't cause an infinite loop. -+func TestIssue59180(t *testing.T) { -+ testcases := []string{ -+ "package p\n//line :9223372036854775806\n\n//", -+ "package p\n//line :1:9223372036854775806\n\n//", -+ "package p\n//line file:9223372036854775806\n\n//", -+ } -+ -+ for _, src := range testcases { -+ _, err := ParseFile(token.NewFileSet(), "", src, ParseComments) -+ if err == nil { -+ t.Errorf("ParseFile(%s) succeeded unexpectedly", src) -+ } -+ } -+} -diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go -index f08e28cdd6b..2276e070498 100644 ---- a/src/go/scanner/scanner.go -+++ b/src/go/scanner/scanner.go -@@ -251,13 +251,16 @@ func (s *Scanner) updateLineInfo(next, offs int, text []byte) { - return - } - -+ // Put a cap on the maximum size of line and column numbers. -+ // 30 bits allows for some additional space before wrapping an int32. -+ const maxLineCol = 1<<30 - 1 - var line, col int - i2, n2, ok2 := trailingDigits(text[:i-1]) - if ok2 { - //line filename:line:col - i, i2 = i2, i - line, col = n2, n -- if col == 0 { -+ if col == 0 || col > maxLineCol { - s.error(offs+i2, "invalid column number: "+string(text[i2:])) - return - } -@@ -267,7 +270,7 @@ func (s *Scanner) updateLineInfo(next, offs int, text []byte) { - line = n - } - -- if line == 0 { -+ if line == 0 || line > maxLineCol { - s.error(offs+i, "invalid line number: "+string(text[i:])) - return - } --- -2.33.0 - diff --git a/0036-release-branch.go1.19-html-template-disallow-actions.patch b/0036-release-branch.go1.19-html-template-disallow-actions.patch deleted file mode 100644 index 6bebd6a5a1036f8bb040e5dab4ef3f6080098cbf..0000000000000000000000000000000000000000 --- a/0036-release-branch.go1.19-html-template-disallow-actions.patch +++ /dev/null @@ -1,378 +0,0 @@ -From d406fb465e0f83d26c02d7ffd9e16b9a0a504ae0 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Mon, 20 Mar 2023 11:01:13 -0700 -Subject: [PATCH 3/6] [release-branch.go1.19] html/template: disallow actions - in JS template literals - -ECMAScript 6 introduced template literals[0][1] which are delimited with -backticks. These need to be escaped in a similar fashion to the -delimiters for other string literals. Additionally template literals can -contain special syntax for string interpolation. - -There is no clear way to allow safe insertion of actions within JS -template literals, as handling (JS) string interpolation inside of these -literals is rather complex. As such we've chosen to simply disallow -template actions within these template literals. - -A new error code is added for this parsing failure case, errJsTmplLit, -but it is unexported as it is not backwards compatible with other minor -release versions to introduce an API change in a minor release. We will -export this code in the next major release. - -The previous behavior (with the cavet that backticks are now escaped -properly) can be re-enabled with GODEBUG=jstmpllitinterp=1. - -This change subsumes CL471455. - -Thanks to Sohom Datta, Manipal Institute of Technology, for reporting -this issue. - -Fixes CVE-2023-24538 -For #59234 -Fixes #59271 - -[0] https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-template-literals -[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals - -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802457 -Reviewed-by: Damien Neil -Run-TryBot: Damien Neil -Reviewed-by: Julie Qiu -Reviewed-by: Roland Shoemaker -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802612 -Run-TryBot: Roland Shoemaker -Change-Id: Ic7f10595615f2b2740d9c85ad7ef40dc0e78c04c -Reviewed-on: https://go-review.googlesource.com/c/go/+/481987 -Auto-Submit: Michael Knyszek -TryBot-Result: Gopher Robot -Run-TryBot: Michael Knyszek -Reviewed-by: Matthew Dempsky ---- - src/html/template/context.go | 4 ++ - src/html/template/error.go | 13 ++++++ - src/html/template/escape.go | 11 ++++++ - src/html/template/escape_test.go | 66 +++++++++++++++++-------------- - src/html/template/js.go | 2 + - src/html/template/js_test.go | 2 +- - src/html/template/jsctx_string.go | 9 +++++ - src/html/template/state_string.go | 37 ++++++++++++++++- - src/html/template/transition.go | 7 +++- - 9 files changed, 118 insertions(+), 33 deletions(-) - -diff --git a/src/html/template/context.go b/src/html/template/context.go -index f7d4849928d..a67b5a78712 100644 ---- a/src/html/template/context.go -+++ b/src/html/template/context.go -@@ -116,6 +116,8 @@ const ( - stateJSDqStr - // stateJSSqStr occurs inside a JavaScript single quoted string. - stateJSSqStr -+ // stateJSBqStr occurs inside a JavaScript back quoted string. -+ stateJSBqStr - // stateJSRegexp occurs inside a JavaScript regexp literal. - stateJSRegexp - // stateJSBlockCmt occurs inside a JavaScript /* block comment */. -@@ -141,6 +143,8 @@ const ( - // stateError is an infectious error state outside any valid - // HTML/CSS/JS construct. - stateError -+ // stateDead marks unreachable code after a {{break}} or {{continue}}. -+ stateDead - ) - - // isComment is true for any state that contains content meant for template -diff --git a/src/html/template/error.go b/src/html/template/error.go -index 0e527063ea6..fd26b64b6e9 100644 ---- a/src/html/template/error.go -+++ b/src/html/template/error.go -@@ -211,6 +211,19 @@ const ( - // pipeline occurs in an unquoted attribute value context, "html" is - // disallowed. Avoid using "html" and "urlquery" entirely in new templates. - ErrPredefinedEscaper -+ -+ // errJSTmplLit: "... appears in a JS template literal" -+ // Example: -+ // -+ // Discussion: -+ // Package html/template does not support actions inside of JS template -+ // literals. -+ // -+ // TODO(rolandshoemaker): we cannot add this as an exported error in a minor -+ // release, since it is backwards incompatible with the other minor -+ // releases. As such we need to leave it unexported, and then we'll add it -+ // in the next major release. -+ errJSTmplLit - ) - - func (e *Error) Error() string { -diff --git a/src/html/template/escape.go b/src/html/template/escape.go -index 8739735cb7b..ca078f40ead 100644 ---- a/src/html/template/escape.go -+++ b/src/html/template/escape.go -@@ -8,6 +8,7 @@ import ( - "bytes" - "fmt" - "html" -+ "internal/godebug" - "io" - "text/template" - "text/template/parse" -@@ -205,6 +206,16 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { - c.jsCtx = jsCtxDivOp - case stateJSDqStr, stateJSSqStr: - s = append(s, "_html_template_jsstrescaper") -+ case stateJSBqStr: -+ debugAllowActionJSTmpl := godebug.Get("jstmpllitinterp") -+ if debugAllowActionJSTmpl == "1" { -+ s = append(s, "_html_template_jsstrescaper") -+ } else { -+ return context{ -+ state: stateError, -+ err: errorf(errJSTmplLit, n, n.Line, "%s appears in a JS template literal", n), -+ } -+ } - case stateJSRegexp: - s = append(s, "_html_template_jsregexpescaper") - case stateCSS: -diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go -index fbc84a75928..9d7749fc9ca 100644 ---- a/src/html/template/escape_test.go -+++ b/src/html/template/escape_test.go -@@ -681,35 +681,31 @@ func TestEscape(t *testing.T) { - } - - for _, test := range tests { -- tmpl := New(test.name) -- tmpl = Must(tmpl.Parse(test.input)) -- // Check for bug 6459: Tree field was not set in Parse. -- if tmpl.Tree != tmpl.text.Tree { -- t.Errorf("%s: tree not set properly", test.name) -- continue -- } -- b := new(bytes.Buffer) -- if err := tmpl.Execute(b, data); err != nil { -- t.Errorf("%s: template execution failed: %s", test.name, err) -- continue -- } -- if w, g := test.output, b.String(); w != g { -- t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) -- continue -- } -- b.Reset() -- if err := tmpl.Execute(b, pdata); err != nil { -- t.Errorf("%s: template execution failed for pointer: %s", test.name, err) -- continue -- } -- if w, g := test.output, b.String(); w != g { -- t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) -- continue -- } -- if tmpl.Tree != tmpl.text.Tree { -- t.Errorf("%s: tree mismatch", test.name) -- continue -- } -+ t.Run(test.name, func(t *testing.T) { -+ tmpl := New(test.name) -+ tmpl = Must(tmpl.Parse(test.input)) -+ // Check for bug 6459: Tree field was not set in Parse. -+ if tmpl.Tree != tmpl.text.Tree { -+ t.Fatalf("%s: tree not set properly", test.name) -+ } -+ b := new(strings.Builder) -+ if err := tmpl.Execute(b, data); err != nil { -+ t.Fatalf("%s: template execution failed: %s", test.name, err) -+ } -+ if w, g := test.output, b.String(); w != g { -+ t.Fatalf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) -+ } -+ b.Reset() -+ if err := tmpl.Execute(b, pdata); err != nil { -+ t.Fatalf("%s: template execution failed for pointer: %s", test.name, err) -+ } -+ if w, g := test.output, b.String(); w != g { -+ t.Fatalf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) -+ } -+ if tmpl.Tree != tmpl.text.Tree { -+ t.Fatalf("%s: tree mismatch", test.name) -+ } -+ }) - } - } - -@@ -920,6 +916,10 @@ func TestErrors(t *testing.T) { - "", - "", - }, -+ { -+ "`", -+ "", -+ }, - // Error cases. - { - "{{if .Cond}}var tmpl = `asd {{.}}`;", -+ `{{.}} appears in a JS template literal`, -+ }, - } - for _, test := range tests { - buf := new(bytes.Buffer) -@@ -1279,6 +1283,10 @@ func TestEscapeText(t *testing.T) { - `= state(len(_state_index)-1) { -diff --git a/src/html/template/transition.go b/src/html/template/transition.go -index 06df679330d..92eb3519063 100644 ---- a/src/html/template/transition.go -+++ b/src/html/template/transition.go -@@ -27,6 +27,7 @@ var transitionFunc = [...]func(context, []byte) (context, int){ - stateJS: tJS, - stateJSDqStr: tJSDelimited, - stateJSSqStr: tJSDelimited, -+ stateJSBqStr: tJSDelimited, - stateJSRegexp: tJSDelimited, - stateJSBlockCmt: tBlockCmt, - stateJSLineCmt: tLineCmt, -@@ -262,7 +263,7 @@ func tURL(c context, s []byte) (context, int) { - - // tJS is the context transition function for the JS state. - func tJS(c context, s []byte) (context, int) { -- i := bytes.IndexAny(s, `"'/`) -+ i := bytes.IndexAny(s, "\"`'/") - if i == -1 { - // Entire input is non string, comment, regexp tokens. - c.jsCtx = nextJSCtx(s, c.jsCtx) -@@ -274,6 +275,8 @@ func tJS(c context, s []byte) (context, int) { - c.state, c.jsCtx = stateJSDqStr, jsCtxRegexp - case '\'': - c.state, c.jsCtx = stateJSSqStr, jsCtxRegexp -+ case '`': -+ c.state, c.jsCtx = stateJSBqStr, jsCtxRegexp - case '/': - switch { - case i+1 < len(s) && s[i+1] == '/': -@@ -303,6 +306,8 @@ func tJSDelimited(c context, s []byte) (context, int) { - switch c.state { - case stateJSSqStr: - specials = `\'` -+ case stateJSBqStr: -+ specials = "`\\" - case stateJSRegexp: - specials = `\/[]` - } --- -2.33.0 - diff --git a/0037-release-branch.go1.19-mime-multipart-avoid-excessive.patch b/0037-release-branch.go1.19-mime-multipart-avoid-excessive.patch deleted file mode 100644 index eedca5026a8c87c629da6a8b5f61592d7b4a68b8..0000000000000000000000000000000000000000 --- a/0037-release-branch.go1.19-mime-multipart-avoid-excessive.patch +++ /dev/null @@ -1,133 +0,0 @@ -From 3c219fd3bda683ee4bc5b69800032ed876b053a9 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Thu, 16 Mar 2023 14:18:04 -0700 -Subject: [PATCH 4/6] [release-branch.go1.19] mime/multipart: avoid excessive - copy buffer allocations in ReadForm - -When copying form data to disk with io.Copy, -allocate only one copy buffer and reuse it rather than -creating two buffers per file (one from io.multiReader.WriteTo, -and a second one from os.File.ReadFrom). - -Thanks to Jakob Ackermann (@das7pad) for reporting this issue. - -For CVE-2023-24536 -For #59153 -For #59269 - -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802453 -Run-TryBot: Damien Neil -Reviewed-by: Julie Qiu -Reviewed-by: Roland Shoemaker -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802395 -Run-TryBot: Roland Shoemaker -Reviewed-by: Damien Neil -Change-Id: Ie405470c92abffed3356913b37d813e982c96c8b -Reviewed-on: https://go-review.googlesource.com/c/go/+/481983 -Run-TryBot: Michael Knyszek -TryBot-Result: Gopher Robot -Auto-Submit: Michael Knyszek -Reviewed-by: Matthew Dempsky ---- - src/mime/multipart/formdata.go | 15 +++++++-- - src/mime/multipart/formdata_test.go | 49 +++++++++++++++++++++++++++++ - 2 files changed, 61 insertions(+), 3 deletions(-) - -diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go -index a7d4ca97f04..975dcb6b26d 100644 ---- a/src/mime/multipart/formdata.go -+++ b/src/mime/multipart/formdata.go -@@ -84,6 +84,7 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - maxMemoryBytes = math.MaxInt64 - } - } -+ var copyBuf []byte - for { - p, err := r.nextPart(false, maxMemoryBytes) - if err == io.EOF { -@@ -147,14 +148,22 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - } - } - numDiskFiles++ -- size, err := io.Copy(file, io.MultiReader(&b, p)) -+ if _, err := file.Write(b.Bytes()); err != nil { -+ return nil, err -+ } -+ if copyBuf == nil { -+ copyBuf = make([]byte, 32*1024) // same buffer size as io.Copy uses -+ } -+ // os.File.ReadFrom will allocate its own copy buffer if we let io.Copy use it. -+ type writerOnly struct{ io.Writer } -+ remainingSize, err := io.CopyBuffer(writerOnly{file}, p, copyBuf) - if err != nil { - return nil, err - } - fh.tmpfile = file.Name() -- fh.Size = size -+ fh.Size = int64(b.Len()) + remainingSize - fh.tmpoff = fileOff -- fileOff += size -+ fileOff += fh.Size - if !combineFiles { - if err := file.Close(); err != nil { - return nil, err -diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go -index 5cded7170c6..f5b56083b23 100644 ---- a/src/mime/multipart/formdata_test.go -+++ b/src/mime/multipart/formdata_test.go -@@ -368,3 +368,52 @@ func testReadFormManyFiles(t *testing.T, distinct bool) { - t.Fatalf("temp dir contains %v files; want 0", len(names)) - } - } -+ -+func BenchmarkReadForm(b *testing.B) { -+ for _, test := range []struct { -+ name string -+ form func(fw *Writer, count int) -+ }{{ -+ name: "fields", -+ form: func(fw *Writer, count int) { -+ for i := 0; i < count; i++ { -+ w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i)) -+ fmt.Fprintf(w, "value %v", i) -+ } -+ }, -+ }, { -+ name: "files", -+ form: func(fw *Writer, count int) { -+ for i := 0; i < count; i++ { -+ w, _ := fw.CreateFormFile(fmt.Sprintf("field%v", i), fmt.Sprintf("file%v", i)) -+ fmt.Fprintf(w, "value %v", i) -+ } -+ }, -+ }} { -+ b.Run(test.name, func(b *testing.B) { -+ for _, maxMemory := range []int64{ -+ 0, -+ 1 << 20, -+ } { -+ var buf bytes.Buffer -+ fw := NewWriter(&buf) -+ test.form(fw, 10) -+ if err := fw.Close(); err != nil { -+ b.Fatal(err) -+ } -+ b.Run(fmt.Sprintf("maxMemory=%v", maxMemory), func(b *testing.B) { -+ b.ReportAllocs() -+ for i := 0; i < b.N; i++ { -+ fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary()) -+ form, err := fr.ReadForm(maxMemory) -+ if err != nil { -+ b.Fatal(err) -+ } -+ form.RemoveAll() -+ } -+ -+ }) -+ } -+ }) -+ } -+} --- -2.33.0 - diff --git a/0038-release-branch.go1.19-net-textproto-mime-multipart-i.patch b/0038-release-branch.go1.19-net-textproto-mime-multipart-i.patch deleted file mode 100644 index 1b7d6dcc1b5f627cf1d9cad516b86c815ccd00db..0000000000000000000000000000000000000000 --- a/0038-release-branch.go1.19-net-textproto-mime-multipart-i.patch +++ /dev/null @@ -1,183 +0,0 @@ -From add85fa4e76febeae7be4484a4d62bf647854244 Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Thu, 16 Mar 2023 16:56:12 -0700 -Subject: [PATCH 5/6] [release-branch.go1.19] net/textproto, mime/multipart: - improve accounting of non-file data - -For requests containing large numbers of small parts, -memory consumption of a parsed form could be about 250% -over the estimated size. - -When considering the size of parsed forms, account for the size of -FileHeader structs and increase the estimate of memory consumed by -map entries. - -Thanks to Jakob Ackermann (@das7pad) for reporting this issue. - -For CVE-2023-24536 -For #59153 -For #59269 - -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802454 -Run-TryBot: Damien Neil -Reviewed-by: Roland Shoemaker -Reviewed-by: Julie Qiu -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802396 -Run-TryBot: Roland Shoemaker -Reviewed-by: Damien Neil -Change-Id: I31bc50e9346b4eee6fbe51a18c3c57230cc066db -Reviewed-on: https://go-review.googlesource.com/c/go/+/481984 -Reviewed-by: Matthew Dempsky -Auto-Submit: Michael Knyszek -TryBot-Result: Gopher Robot -Run-TryBot: Michael Knyszek ---- - src/mime/multipart/formdata.go | 9 +++-- - src/mime/multipart/formdata_test.go | 55 ++++++++++++----------------- - src/net/textproto/reader.go | 8 ++++- - 3 files changed, 37 insertions(+), 35 deletions(-) - -diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go -index 975dcb6b26d..3f6ff697ca6 100644 ---- a/src/mime/multipart/formdata.go -+++ b/src/mime/multipart/formdata.go -@@ -103,8 +103,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - // Multiple values for the same key (one map entry, longer slice) are cheaper - // than the same number of values for different keys (many map entries), but - // using a consistent per-value cost for overhead is simpler. -+ const mapEntryOverhead = 200 - maxMemoryBytes -= int64(len(name)) -- maxMemoryBytes -= 100 // map overhead -+ maxMemoryBytes -= mapEntryOverhead - if maxMemoryBytes < 0 { - // We can't actually take this path, since nextPart would already have - // rejected the MIME headers for being too large. Check anyway. -@@ -128,7 +129,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - } - - // file, store in memory or on disk -+ const fileHeaderSize = 100 - maxMemoryBytes -= mimeHeaderSize(p.Header) -+ maxMemoryBytes -= mapEntryOverhead -+ maxMemoryBytes -= fileHeaderSize - if maxMemoryBytes < 0 { - return nil, ErrMessageTooLarge - } -@@ -183,9 +187,10 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - } - - func mimeHeaderSize(h textproto.MIMEHeader) (size int64) { -+ size = 400 - for k, vs := range h { - size += int64(len(k)) -- size += 100 // map entry overhead -+ size += 200 // map entry overhead - for _, v := range vs { - size += int64(len(v)) - } -diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go -index f5b56083b23..8ed26e0c340 100644 ---- a/src/mime/multipart/formdata_test.go -+++ b/src/mime/multipart/formdata_test.go -@@ -192,10 +192,10 @@ func (r *failOnReadAfterErrorReader) Read(p []byte) (n int, err error) { - // TestReadForm_NonFileMaxMemory asserts that the ReadForm maxMemory limit is applied - // while processing non-file form data as well as file form data. - func TestReadForm_NonFileMaxMemory(t *testing.T) { -- n := 10<<20 + 25 - if testing.Short() { -- n = 10<<10 + 25 -+ t.Skip("skipping in -short mode") - } -+ n := 10 << 20 - largeTextValue := strings.Repeat("1", n) - message := `--MyBoundary - Content-Disposition: form-data; name="largetext" -@@ -203,38 +203,29 @@ Content-Disposition: form-data; name="largetext" - ` + largeTextValue + ` - --MyBoundary-- - ` -- - testBody := strings.ReplaceAll(message, "\n", "\r\n") -- testCases := []struct { -- name string -- maxMemory int64 -- err error -- }{ -- {"smaller", 50 + int64(len("largetext")) + 100, nil}, -- {"exact-fit", 25 + int64(len("largetext")) + 100, nil}, -- {"too-large", 0, ErrMessageTooLarge}, -- } -- for _, tc := range testCases { -- t.Run(tc.name, func(t *testing.T) { -- if tc.maxMemory == 0 && testing.Short() { -- t.Skip("skipping in -short mode") -- } -- b := strings.NewReader(testBody) -- r := NewReader(b, boundary) -- f, err := r.ReadForm(tc.maxMemory) -- if err == nil { -- defer f.RemoveAll() -- } -- if tc.err != err { -- t.Fatalf("ReadForm error - got: %v; expected: %v", err, tc.err) -- } -- if err == nil { -- if g := f.Value["largetext"][0]; g != largeTextValue { -- t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) -- } -- } -- }) -+ // Try parsing the form with increasing maxMemory values. -+ // Changes in how we account for non-file form data may cause the exact point -+ // where we change from rejecting the form as too large to accepting it to vary, -+ // but we should see both successes and failures. -+ const failWhenMaxMemoryLessThan = 128 -+ for maxMemory := int64(0); maxMemory < failWhenMaxMemoryLessThan*2; maxMemory += 16 { -+ b := strings.NewReader(testBody) -+ r := NewReader(b, boundary) -+ f, err := r.ReadForm(maxMemory) -+ if err != nil { -+ continue -+ } -+ if g := f.Value["largetext"][0]; g != largeTextValue { -+ t.Errorf("largetext mismatch: got size: %v, expected size: %v", len(g), len(largeTextValue)) -+ } -+ f.RemoveAll() -+ if maxMemory < failWhenMaxMemoryLessThan { -+ t.Errorf("ReadForm(%v): no error, expect to hit memory limit when maxMemory < %v", maxMemory, failWhenMaxMemoryLessThan) -+ } -+ return - } -+ t.Errorf("ReadForm(x) failed for x < 1024, expect success") - } - - // TestReadForm_MetadataTooLarge verifies that we account for the size of field names, -diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go -index 98056b0de55..68b445083bf 100644 ---- a/src/net/textproto/reader.go -+++ b/src/net/textproto/reader.go -@@ -503,6 +503,12 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { - - m := make(MIMEHeader, hint) - -+ // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. -+ // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large -+ // MIMEHeaders average about 200 bytes per entry. -+ lim -= 400 -+ const mapEntryOverhead = 200 -+ - // The first line cannot start with a leading space. - if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { - line, err := r.readLineSlice() -@@ -542,7 +548,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { - vv := m[key] - if vv == nil { - lim -= int64(len(key)) -- lim -= 100 // map entry overhead -+ lim -= mapEntryOverhead - } - lim -= int64(len(value)) - if lim < 0 { --- -2.33.0 - diff --git a/0039-release-branch.go1.19-mime-multipart-limit-parsed-mi.patch b/0039-release-branch.go1.19-mime-multipart-limit-parsed-mi.patch deleted file mode 100644 index bfe9bc5e62f40305a3a945fd79123d9e63f9569a..0000000000000000000000000000000000000000 --- a/0039-release-branch.go1.19-mime-multipart-limit-parsed-mi.patch +++ /dev/null @@ -1,346 +0,0 @@ -From fd764bb32d4be31e497a3279977ca760305c501b Mon Sep 17 00:00:00 2001 -From: Damien Neil -Date: Mon, 20 Mar 2023 10:43:19 -0700 -Subject: [PATCH 6/6] [release-branch.go1.19] mime/multipart: limit parsed mime - message sizes - -The parsed forms of MIME headers and multipart forms can consume -substantially more memory than the size of the input data. -A malicious input containing a very large number of headers or -form parts can cause excessively large memory allocations. - -Set limits on the size of MIME data: - -Reader.NextPart and Reader.NextRawPart limit the the number -of headers in a part to 10000. - -Reader.ReadForm limits the total number of headers in all -FileHeaders to 10000. - -Both of these limits may be set with with -GODEBUG=multipartmaxheaders=. - -Reader.ReadForm limits the number of parts in a form to 1000. -This limit may be set with GODEBUG=multipartmaxparts=. - -Thanks for Jakob Ackermann (@das7pad) for reporting this issue. - -For CVE-2023-24536 -For #59153 -For #59269 - -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1802455 -Run-TryBot: Damien Neil -Reviewed-by: Roland Shoemaker -Reviewed-by: Julie Qiu -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1801087 -Reviewed-by: Damien Neil -Run-TryBot: Roland Shoemaker -Change-Id: If134890d75f0d95c681d67234daf191ba08e6424 -Reviewed-on: https://go-review.googlesource.com/c/go/+/481985 -Run-TryBot: Michael Knyszek -Auto-Submit: Michael Knyszek -TryBot-Result: Gopher Robot -Reviewed-by: Matthew Dempsky ---- - src/mime/multipart/formdata.go | 19 ++++++++- - src/mime/multipart/formdata_test.go | 61 ++++++++++++++++++++++++++++ - src/mime/multipart/multipart.go | 31 ++++++++++---- - src/mime/multipart/readmimeheader.go | 2 +- - src/net/textproto/reader.go | 19 +++++---- - 5 files changed, 115 insertions(+), 17 deletions(-) - -diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go -index 3f6ff697ca6..4f26aab2cf4 100644 ---- a/src/mime/multipart/formdata.go -+++ b/src/mime/multipart/formdata.go -@@ -12,6 +12,7 @@ import ( - "math" - "net/textproto" - "os" -+ "strconv" - ) - - // ErrMessageTooLarge is returned by ReadForm if the message form -@@ -41,6 +42,15 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - numDiskFiles := 0 - multipartFiles := godebug.Get("multipartfiles") - combineFiles := multipartFiles != "distinct" -+ maxParts := 1000 -+ multipartMaxParts := godebug.Get("multipartmaxparts") -+ if multipartMaxParts != "" { -+ if v, err := strconv.Atoi(multipartMaxParts); err == nil && v >= 0 { -+ maxParts = v -+ } -+ } -+ maxHeaders := maxMIMEHeaders() -+ - defer func() { - if file != nil { - if cerr := file.Close(); err == nil { -@@ -86,13 +96,17 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - } - var copyBuf []byte - for { -- p, err := r.nextPart(false, maxMemoryBytes) -+ p, err := r.nextPart(false, maxMemoryBytes, maxHeaders) - if err == io.EOF { - break - } - if err != nil { - return nil, err - } -+ if maxParts <= 0 { -+ return nil, ErrMessageTooLarge -+ } -+ maxParts-- - - name := p.FormName() - if name == "" { -@@ -136,6 +150,9 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { - if maxMemoryBytes < 0 { - return nil, ErrMessageTooLarge - } -+ for _, v := range p.Header { -+ maxHeaders -= int64(len(v)) -+ } - fh := &FileHeader{ - Filename: filename, - Header: p.Header, -diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go -index 8ed26e0c340..c78eeb7a12b 100644 ---- a/src/mime/multipart/formdata_test.go -+++ b/src/mime/multipart/formdata_test.go -@@ -360,6 +360,67 @@ func testReadFormManyFiles(t *testing.T, distinct bool) { - } - } - -+func TestReadFormLimits(t *testing.T) { -+ for _, test := range []struct { -+ values int -+ files int -+ extraKeysPerFile int -+ wantErr error -+ godebug string -+ }{ -+ {values: 1000}, -+ {values: 1001, wantErr: ErrMessageTooLarge}, -+ {values: 500, files: 500}, -+ {values: 501, files: 500, wantErr: ErrMessageTooLarge}, -+ {files: 1000}, -+ {files: 1001, wantErr: ErrMessageTooLarge}, -+ {files: 1, extraKeysPerFile: 9998}, // plus Content-Disposition and Content-Type -+ {files: 1, extraKeysPerFile: 10000, wantErr: ErrMessageTooLarge}, -+ {godebug: "multipartmaxparts=100", values: 100}, -+ {godebug: "multipartmaxparts=100", values: 101, wantErr: ErrMessageTooLarge}, -+ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 48}, -+ {godebug: "multipartmaxheaders=100", files: 2, extraKeysPerFile: 50, wantErr: ErrMessageTooLarge}, -+ } { -+ name := fmt.Sprintf("values=%v/files=%v/extraKeysPerFile=%v", test.values, test.files, test.extraKeysPerFile) -+ if test.godebug != "" { -+ name += fmt.Sprintf("/godebug=%v", test.godebug) -+ } -+ t.Run(name, func(t *testing.T) { -+ if test.godebug != "" { -+ t.Setenv("GODEBUG", test.godebug) -+ } -+ var buf bytes.Buffer -+ fw := NewWriter(&buf) -+ for i := 0; i < test.values; i++ { -+ w, _ := fw.CreateFormField(fmt.Sprintf("field%v", i)) -+ fmt.Fprintf(w, "value %v", i) -+ } -+ for i := 0; i < test.files; i++ { -+ h := make(textproto.MIMEHeader) -+ h.Set("Content-Disposition", -+ fmt.Sprintf(`form-data; name="file%v"; filename="file%v"`, i, i)) -+ h.Set("Content-Type", "application/octet-stream") -+ for j := 0; j < test.extraKeysPerFile; j++ { -+ h.Set(fmt.Sprintf("k%v", j), "v") -+ } -+ w, _ := fw.CreatePart(h) -+ fmt.Fprintf(w, "value %v", i) -+ } -+ if err := fw.Close(); err != nil { -+ t.Fatal(err) -+ } -+ fr := NewReader(bytes.NewReader(buf.Bytes()), fw.Boundary()) -+ form, err := fr.ReadForm(1 << 10) -+ if err == nil { -+ defer form.RemoveAll() -+ } -+ if err != test.wantErr { -+ t.Errorf("ReadForm = %v, want %v", err, test.wantErr) -+ } -+ }) -+ } -+} -+ - func BenchmarkReadForm(b *testing.B) { - for _, test := range []struct { - name string -diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go -index 465b376eaeb..bc5096f018f 100644 ---- a/src/mime/multipart/multipart.go -+++ b/src/mime/multipart/multipart.go -@@ -16,11 +16,13 @@ import ( - "bufio" - "bytes" - "fmt" -+ "internal/godebug" - "io" - "mime" - "mime/quotedprintable" - "net/textproto" - "path/filepath" -+ "strconv" - "strings" - ) - -@@ -128,12 +130,12 @@ func (r *stickyErrorReader) Read(p []byte) (n int, _ error) { - return n, r.err - } - --func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { -+func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) { - bp := &Part{ - Header: make(map[string][]string), - mr: mr, - } -- if err := bp.populateHeaders(maxMIMEHeaderSize); err != nil { -+ if err := bp.populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders); err != nil { - return nil, err - } - bp.r = partReader{bp} -@@ -149,9 +151,9 @@ func newPart(mr *Reader, rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { - return bp, nil - } - --func (p *Part) populateHeaders(maxMIMEHeaderSize int64) error { -+func (p *Part) populateHeaders(maxMIMEHeaderSize, maxMIMEHeaders int64) error { - r := textproto.NewReader(p.mr.bufReader) -- header, err := readMIMEHeader(r, maxMIMEHeaderSize) -+ header, err := readMIMEHeader(r, maxMIMEHeaderSize, maxMIMEHeaders) - if err == nil { - p.Header = header - } -@@ -313,6 +315,19 @@ type Reader struct { - // including header keys, values, and map overhead. - const maxMIMEHeaderSize = 10 << 20 - -+func maxMIMEHeaders() int64 { -+ // multipartMaxHeaders is the maximum number of header entries NextPart will return, -+ // as well as the maximum combined total of header entries Reader.ReadForm will return -+ // in FileHeaders. -+ multipartMaxHeaders := godebug.Get("multipartmaxheaders") -+ if multipartMaxHeaders != "" { -+ if v, err := strconv.ParseInt(multipartMaxHeaders, 10, 64); err == nil && v >= 0 { -+ return v -+ } -+ } -+ return 10000 -+} -+ - // NextPart returns the next part in the multipart or an error. - // When there are no more parts, the error io.EOF is returned. - // -@@ -320,7 +335,7 @@ const maxMIMEHeaderSize = 10 << 20 - // has a value of "quoted-printable", that header is instead - // hidden and the body is transparently decoded during Read calls. - func (r *Reader) NextPart() (*Part, error) { -- return r.nextPart(false, maxMIMEHeaderSize) -+ return r.nextPart(false, maxMIMEHeaderSize, maxMIMEHeaders()) - } - - // NextRawPart returns the next part in the multipart or an error. -@@ -329,10 +344,10 @@ func (r *Reader) NextPart() (*Part, error) { - // Unlike NextPart, it does not have special handling for - // "Content-Transfer-Encoding: quoted-printable". - func (r *Reader) NextRawPart() (*Part, error) { -- return r.nextPart(true, maxMIMEHeaderSize) -+ return r.nextPart(true, maxMIMEHeaderSize, maxMIMEHeaders()) - } - --func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) { -+func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize, maxMIMEHeaders int64) (*Part, error) { - if r.currentPart != nil { - r.currentPart.Close() - } -@@ -357,7 +372,7 @@ func (r *Reader) nextPart(rawPart bool, maxMIMEHeaderSize int64) (*Part, error) - - if r.isBoundaryDelimiterLine(line) { - r.partsRead++ -- bp, err := newPart(r, rawPart, maxMIMEHeaderSize) -+ bp, err := newPart(r, rawPart, maxMIMEHeaderSize, maxMIMEHeaders) - if err != nil { - return nil, err - } -diff --git a/src/mime/multipart/readmimeheader.go b/src/mime/multipart/readmimeheader.go -index 6836928c9e8..25aa6e20928 100644 ---- a/src/mime/multipart/readmimeheader.go -+++ b/src/mime/multipart/readmimeheader.go -@@ -11,4 +11,4 @@ import ( - // readMIMEHeader is defined in package net/textproto. - // - //go:linkname readMIMEHeader net/textproto.readMIMEHeader --func readMIMEHeader(r *textproto.Reader, lim int64) (textproto.MIMEHeader, error) -+func readMIMEHeader(r *textproto.Reader, maxMemory, maxHeaders int64) (textproto.MIMEHeader, error) -diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go -index 68b445083bf..4299608d5ae 100644 ---- a/src/net/textproto/reader.go -+++ b/src/net/textproto/reader.go -@@ -483,12 +483,12 @@ func (r *Reader) ReadDotLines() ([]string, error) { - // } - // - func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { -- return readMIMEHeader(r, math.MaxInt64) -+ return readMIMEHeader(r, math.MaxInt64, math.MaxInt64) - } - - // readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. - // It is called by the mime/multipart package. --func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { -+func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) { - // Avoid lots of small slice allocations later by allocating one - // large one ahead of time which we'll cut up into smaller - // slices. If this isn't big enough later, we allocate small ones. -@@ -506,7 +506,7 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { - // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. - // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large - // MIMEHeaders average about 200 bytes per entry. -- lim -= 400 -+ maxMemory -= 400 - const mapEntryOverhead = 200 - - // The first line cannot start with a leading space. -@@ -538,6 +538,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { - continue - } - -+ maxHeaders-- -+ if maxHeaders < 0 { -+ return nil, errors.New("message too large") -+ } -+ - // Skip initial spaces in value. - i++ // skip colon - for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') { -@@ -547,11 +552,11 @@ func readMIMEHeader(r *Reader, lim int64) (MIMEHeader, error) { - - vv := m[key] - if vv == nil { -- lim -= int64(len(key)) -- lim -= mapEntryOverhead -+ maxMemory -= int64(len(key)) -+ maxMemory -= mapEntryOverhead - } -- lim -= int64(len(value)) -- if lim < 0 { -+ maxMemory -= int64(len(value)) -+ if maxMemory < 0 { - // TODO: This should be a distinguishable error (ErrMessageTooLarge) - // to allow mime/multipart to detect it. - return m, errors.New("message too large") --- -2.33.0 - diff --git a/0040-Backport-html-template-emit-filterFailsafe-for-empty.patch b/0040-Backport-html-template-emit-filterFailsafe-for-empty.patch deleted file mode 100644 index a7a3516499777b18434100f9f39a9cffda14e31a..0000000000000000000000000000000000000000 --- a/0040-Backport-html-template-emit-filterFailsafe-for-empty.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 269ef3bb401deab32dcbce3ee24e0cf64e94b825 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Wed, 10 May 2023 16:33:50 +0800 -Subject: [PATCH 1/3] [Backport] html/template: emit filterFailsafe for empty - unquoted attr value - -Offering: Cloud Core Network -CVE: CVE-2023-29400 -Reference: https://go-review.googlesource.com/c/go/+/491357 - -An unquoted action used as an attribute value can result in unsafe -behavior if it is empty, as HTML normalization will result in unexpected -attributes, and may allow attribute injection. If executing a template -results in a empty unquoted attribute value, emit filterFailsafe -instead. - -Thanks to Juho Nurminen of Mattermost for reporting this issue. - -For #59722 -Fixes #59815 -Fixes CVE-2023-29400 - -Change-Id: Ia38d1b536ae2b4af5323a6c6d861e3c057c2570a -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1826631 -Reviewed-by: Julie Qiu -Run-TryBot: Roland Shoemaker -Reviewed-by: Damien Neil -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1851498 -Reviewed-by: Roland Shoemaker -Run-TryBot: Damien Neil -Reviewed-on: https://go-review.googlesource.com/c/go/+/491357 -Run-TryBot: Carlos Amedee -TryBot-Result: Gopher Robot -Reviewed-by: Dmitri Shuralyov - -Signed-off-by: Li Bi Chen libichen@huawei.com ---- - src/html/template/escape.go | 5 ++--- - src/html/template/escape_test.go | 15 +++++++++++++++ - src/html/template/html.go | 3 +++ - 3 files changed, 20 insertions(+), 3 deletions(-) - -diff --git a/src/html/template/escape.go b/src/html/template/escape.go -index ca078f40ea..bdccc65a57 100644 ---- a/src/html/template/escape.go -+++ b/src/html/template/escape.go -@@ -362,9 +362,8 @@ func normalizeEscFn(e string) string { - // for all x. - var redundantFuncs = map[string]map[string]bool{ - "_html_template_commentescaper": { -- "_html_template_attrescaper": true, -- "_html_template_nospaceescaper": true, -- "_html_template_htmlescaper": true, -+ "_html_template_attrescaper": true, -+ "_html_template_htmlescaper": true, - }, - "_html_template_cssescaper": { - "_html_template_attrescaper": true, -diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go -index 9d7749fc9c..3e17aee8f2 100644 ---- a/src/html/template/escape_test.go -+++ b/src/html/template/escape_test.go -@@ -678,6 +678,21 @@ func TestEscape(t *testing.T) { - ``, - ``, - }, -+ { -+ "unquoted empty attribute value (plaintext)", -+ "

", -+ "

", -+ }, -+ { -+ "unquoted empty attribute value (url)", -+ "

", -+ "

", -+ }, -+ { -+ "quoted empty attribute value", -+ "

", -+ "

", -+ }, - } - - for _, test := range tests { -diff --git a/src/html/template/html.go b/src/html/template/html.go -index 356b8298ae..636bc21069 100644 ---- a/src/html/template/html.go -+++ b/src/html/template/html.go -@@ -14,6 +14,9 @@ import ( - // htmlNospaceEscaper escapes for inclusion in unquoted attribute values. - func htmlNospaceEscaper(args ...interface{}) string { - s, t := stringify(args...) -+ if s == "" { -+ return filterFailsafe -+ } - if t == contentTypeHTML { - return htmlReplacer(stripTags(s), htmlNospaceNormReplacementTable, false) - } --- -2.33.0 - diff --git a/0041-Backport-html-template-handle-all-JS-whitespace-char.patch b/0041-Backport-html-template-handle-all-JS-whitespace-char.patch deleted file mode 100644 index 71e121b8704ee91cf039143767431e29d4556f72..0000000000000000000000000000000000000000 --- a/0041-Backport-html-template-handle-all-JS-whitespace-char.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 9b226a94a44d53ca8f740e9807f8236a8bb7dfc3 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Wed, 10 May 2023 16:37:48 +0800 -Subject: [PATCH 2/3] [Backport] html/template: handle all JS whitespace - characters -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Offering: Cloud Core Network -CVE: CVE-2023-24540 -Reference: https://go-review.googlesource.com/c/go/+/491355 - -Rather than just a small set. Character class as defined by \s [0]. - -Thanks to Juho Nurminen of Mattermost for reporting this. - -For #59721 -Fixes  #59813 -Fixes CVE-2023-24540 - -[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes - -Change-Id: I56d4fa1ef08125b417106ee7dbfb5b0923b901ba -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1821459 -Reviewed-by: Julie Qiu -Run-TryBot: Roland Shoemaker -Reviewed-by: Damien Neil -Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1851497 -Run-TryBot: Damien Neil -Reviewed-by: Roland Shoemaker -Reviewed-on: https://go-review.googlesource.com/c/go/+/491355 -Reviewed-by: Dmitri Shuralyov -Reviewed-by: Carlos Amedee -TryBot-Bypass: Carlos Amedee -Run-TryBot: Carlos Amedee - -Signed-off-by: Li Bi Chen libichen@huawei.com ---- - src/html/template/js.go | 8 +++++++- - src/html/template/js_test.go | 11 +++++++---- - 2 files changed, 14 insertions(+), 5 deletions(-) - -diff --git a/src/html/template/js.go b/src/html/template/js.go -index b888eaf8b7..35994f076e 100644 ---- a/src/html/template/js.go -+++ b/src/html/template/js.go -@@ -13,6 +13,11 @@ import ( - "unicode/utf8" - ) - -+// jsWhitespace contains all of the JS whitespace characters, as defined -+// by the \s character class. -+// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Character_classes. -+const jsWhitespace = "\f\n\r\t\v\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff" -+ - // nextJSCtx returns the context that determines whether a slash after the - // given run of tokens starts a regular expression instead of a division - // operator: / or /=. -@@ -26,7 +31,8 @@ import ( - // JavaScript 2.0 lexical grammar and requires one token of lookbehind: - // https://www.mozilla.org/js/language/js20-2000-07/rationale/syntax.html - func nextJSCtx(s []byte, preceding jsCtx) jsCtx { -- s = bytes.TrimRight(s, "\t\n\f\r \u2028\u2029") -+ // Trim all JS whitespace characters -+ s = bytes.TrimRight(s, jsWhitespace) - if len(s) == 0 { - return preceding - } -diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go -index 7d963ae6f1..de9ef28410 100644 ---- a/src/html/template/js_test.go -+++ b/src/html/template/js_test.go -@@ -81,14 +81,17 @@ func TestNextJsCtx(t *testing.T) { - {jsCtxDivOp, "0"}, - // Dots that are part of a number are div preceders. - {jsCtxDivOp, "0."}, -+ // Some JS interpreters treat NBSP as a normal space, so -+ // we must too in order to properly escape things. -+ {jsCtxRegexp, "=\u00A0"}, - } - - for _, test := range tests { -- if nextJSCtx([]byte(test.s), jsCtxRegexp) != test.jsCtx { -- t.Errorf("want %s got %q", test.jsCtx, test.s) -+ if ctx := nextJSCtx([]byte(test.s), jsCtxRegexp); ctx != test.jsCtx { -+ t.Errorf("%q: want %s got %s", test.s, test.jsCtx, ctx) - } -- if nextJSCtx([]byte(test.s), jsCtxDivOp) != test.jsCtx { -- t.Errorf("want %s got %q", test.jsCtx, test.s) -+ if ctx := nextJSCtx([]byte(test.s), jsCtxDivOp); ctx != test.jsCtx { -+ t.Errorf("%q: want %s got %s", test.s, test.jsCtx, ctx) - } - } - --- -2.33.0 - diff --git a/0042-Backport-html-template-disallow-angle-brackets-in-CS.patch b/0042-Backport-html-template-disallow-angle-brackets-in-CS.patch deleted file mode 100644 index dfc666c17d4a1096a9eff46ad01170b6a5a04884..0000000000000000000000000000000000000000 --- a/0042-Backport-html-template-disallow-angle-brackets-in-CS.patch +++ /dev/null @@ -1,69 +0,0 @@ -From be128e70a9a7f52f9ff33fceb2139b5769da0112 Mon Sep 17 00:00:00 2001 -From: Roland Shoemaker -Date: Wed, 10 May 2023 16:43:52 +0800 -Subject: [PATCH 3/3] [Backport] html/template: disallow angle brackets in CSS - values - -Offering: Cloud Core Network -CVE: CVE-2023-24539 -Reference: https://go-review.googlesource.com/c/go/+/491335 - -Angle brackets should not appear in CSS contexts, as they may affect -token boundaries (such as closing a