golang: upgrade to golang1.19.4
This commit is contained in:
parent
b15ef57675
commit
bf9ade514f
@ -1,60 +0,0 @@
|
|||||||
From ad33fdc8f4bce612842d922ca701c3062fe4d4c6 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Filippo Valsorda <filippo@golang.org>
|
|
||||||
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 <filippo@golang.org>
|
|
||||||
Reviewed-by: Julie Qiu <julie@golang.org>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,291 +0,0 @@
|
|||||||
From baaaf3ce29bf98efc00c2f06c531f2b0186b027b Mon Sep 17 00:00:00 2001
|
|
||||||
From: Julie Qiu <julie@golang.org>
|
|
||||||
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 <dneil@google.com>
|
|
||||||
Reviewed-by: Filippo Valsorda <valsorda@google.com>
|
|
||||||
(cherry picked from commit 794ea5e828010e8b68493b2fc6d2963263195a02)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/399816
|
|
||||||
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
|
|
||||||
Reviewed-by: Cherry Mui <cherryyz@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
From e7aab832069d06d77e04a585803dfdb04453253a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Russ Cox <rsc@golang.org>
|
|
||||||
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 <iant@google.com>
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/370534
|
|
||||||
Trust: Filippo Valsorda <filippo@golang.org>
|
|
||||||
Run-TryBot: Filippo Valsorda <filippo@golang.org>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Reviewed-by: Alex Rakoczy <alex@golang.org>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
From c872b0594f716a2a0799b07d7226a45f02c005f1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Cherry Mui <cherryyz@google.com>
|
|
||||||
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 <cherryyz@google.com>
|
|
||||||
Run-TryBot: Cherry Mui <cherryyz@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Reviewed-by: Than McIntosh <thanm@google.com>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
From 67bff2eb995a098f838fa4b799c0b8261292e6e7 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Damien Neil <dneil@google.com>
|
|
||||||
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 <iant@google.com>
|
|
||||||
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
|
|
||||||
(cherry picked from commit b2cc0fecc2ccd80e6d5d16542cc684f97b3a9c8a)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/415221
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Run-TryBot: Michael Knyszek <mknyszek@google.com>
|
|
||||||
Run-TryBot: Heschi Kreinick <heschi@google.com>
|
|
||||||
Reviewed-by: Michael Knyszek <mknyszek@google.com>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,421 +0,0 @@
|
|||||||
From b78e521644334294019da243a5ff57436f70cd72 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roland Shoemaker <bracewell@google.com>
|
|
||||||
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 <rsc@google.com>
|
|
||||||
Reviewed-by: Damien Neil <dneil@google.com>
|
|
||||||
(cherry picked from commit 6a856f08d58e4b6705c0c337d461c540c1235c83)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/417070
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Run-TryBot: Michael Knyszek <mknyszek@google.com>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
From 4ad62aecaf57ca3adc11a04bd2113bdbee6249c3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Damien Neil <dneil@google.com>
|
|
||||||
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 <roland@golang.org>
|
|
||||||
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
|
|
||||||
(cherry picked from commit e5017a93fcde94f09836200bca55324af037ee5f)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/415217
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
|
|
||||||
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,168 +0,0 @@
|
|||||||
From 106c859f68c3137cfa05c433a9b90494db386fda Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roland Shoemaker <roland@golang.org>
|
|
||||||
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 <dneil@google.com>
|
|
||||||
Reviewed-by: Julie Qiu <julieqiu@google.com>
|
|
||||||
(cherry picked from commit ebee00a55e28931b2cad0e76207a73712b000432)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/417069
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
Run-TryBot: Michael Knyszek <mknyszek@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
|
|
||||||
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("<a>"), 17_000_000), &example)
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+func TestCVE202228131(t *testing.T) {
|
|
||||||
+ type nested struct {
|
|
||||||
+ Parent *nested `xml:",any"`
|
|
||||||
+ }
|
|
||||||
+ var n nested
|
|
||||||
+ err := Unmarshal(bytes.Repeat([]byte("<a>"), 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
|
|
||||||
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
From 8747af9a1098e8fa497441be4c4a79a23de31a98 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roland Shoemaker <bracewell@google.com>
|
|
||||||
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 <dneil@google.com>
|
|
||||||
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
|
|
||||||
(cherry picked from commit 55e8f938d22bfec29cc9dc9671044c5a41d1ea9c)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/417074
|
|
||||||
Run-TryBot: Heschi Kreinick <heschi@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
From a8d44d0477f2182563e279da115cbc164d639f33 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Julie Qiu <julieqiu@google.com>
|
|
||||||
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 <bracewell@google.com>
|
|
||||||
(cherry picked from commit fdccc5d7bd0f276d0a8de3a818ca844f0bed5d97)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/417072
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Run-TryBot: Michael Knyszek <mknyszek@google.com>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,85 +0,0 @@
|
|||||||
From 7b98bf3a8711126c532033ca89647f3b743b58ec Mon Sep 17 00:00:00 2001
|
|
||||||
From: Julie Qiu <julieqiu@google.com>
|
|
||||||
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 <bracewell@google.com>
|
|
||||||
(cherry picked from commit d182a6d1217fd0d04c9babfa9a7ccd3515435c39)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/417073
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Run-TryBot: Michael Knyszek <mknyszek@google.com>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
From cedbe8f7a1f0d174636e70de68d85499d8025000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roland Shoemaker <roland@golang.org>
|
|
||||||
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 <julieqiu@google.com>
|
|
||||||
Reviewed-by: Damien Neil <dneil@google.com>
|
|
||||||
(cherry picked from commit 9278cb78443d2b4deb24cbb5b61c9ba5ac688d49)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/417068
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
Run-TryBot: Michael Knyszek <mknyszek@google.com>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,133 +0,0 @@
|
|||||||
From 8a445abc7f7e2ed41112f176a169b97859c8d425 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
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 <bracewell@google.com>
|
|
||||||
Reviewed-by: Julie Qiu <julieqiu@google.com>
|
|
||||||
(cherry picked from commit cf498969c8a0bae9d7a24b98fc1f66c824a4775d)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/417071
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
Run-TryBot: Michael Knyszek <mknyszek@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,69 +0,0 @@
|
|||||||
From b2815a72bef3f829c5ac7735feddb034f5501cc0 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
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 <tatiana@golang.org>
|
|
||||||
Reviewed-by: Roland Shoemaker <roland@golang.org>
|
|
||||||
Run-TryBot: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
(cherry picked from commit fe4de36198794c447fbd9d7cc2d7199a506c76a5)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/408574
|
|
||||||
Run-TryBot: Roland Shoemaker <roland@golang.org>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,246 +0,0 @@
|
|||||||
From 07a30769186210c1b1e25943824743355c4e50f5 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roland Shoemaker <roland@golang.org>
|
|
||||||
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 <roland@golang.org>
|
|
||||||
Reviewed-by: Filippo Valsorda <filippo@golang.org>
|
|
||||||
Reviewed-by: Filippo Valsorda <valsorda@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
(cherry picked from commit bb1f4416180511231de6d17a1f2f55c82aafc863)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/406635
|
|
||||||
Reviewed-by: Damien Neil <dneil@google.com>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,125 +0,0 @@
|
|||||||
From dc903a8196a831d23e9b6504239e09a9e6bcd98a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Roland Shoemaker <roland@golang.org>
|
|
||||||
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 <gobot@golang.org>
|
|
||||||
Reviewed-by: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
Run-TryBot: Roland Shoemaker <roland@golang.org>
|
|
||||||
(cherry picked from commit 055113ef364337607e3e72ed7d48df67fde6fc66)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/419814
|
|
||||||
Reviewed-by: Julie Qiu <julieqiu@google.com>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
From e903e474f9632a151fff2df3dd3e891395f1a8f1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
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 <iant@google.com>
|
|
||||||
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
|
|
||||||
Run-TryBot: Ian Lance Taylor <iant@google.com>
|
|
||||||
Reviewed-by: Ian Lance Taylor <iant@google.com>
|
|
||||||
Reviewed-by: Damien Neil <dneil@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
From 66cff0cda766c1533373fabf3bc26fc3397e55d5 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Damien Neil <dneil@google.com>
|
|
||||||
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 <iant@google.com>
|
|
||||||
Run-TryBot: Ian Lance Taylor <iant@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
(cherry picked from commit f66925e854e71e0c54b581885380a490d7afa30c)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/401078
|
|
||||||
Auto-Submit: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
Run-TryBot: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
Run-TryBot: Damien Neil <dneil@google.com>
|
|
||||||
Auto-Submit: Damien Neil <dneil@google.com>
|
|
||||||
Reviewed-by: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
From b2058191785138021b635f609de3d5f651ec02cd Mon Sep 17 00:00:00 2001
|
|
||||||
From: Damien Neil <dneil@google.com>
|
|
||||||
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 <bracewell@google.com>
|
|
||||||
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/428635
|
|
||||||
Reviewed-by: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
Run-TryBot: Michael Knyszek <mknyszek@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Reviewed-by: Carlos Amedee <carlos@golang.org>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,386 +0,0 @@
|
|||||||
From 8b3a5d153b7b255bafd1a82d61505088356d0458 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Russ Cox <rsc@golang.org>
|
|
||||||
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 <security-trybots@go-security-trybots.iam.gserviceaccount.com>
|
|
||||||
Reviewed-by: Damien Neil <dneil@google.com>
|
|
||||||
Run-TryBot: Roland Shoemaker <bracewell@google.com>
|
|
||||||
Reviewed-by: Julie Qiu <julieqiu@google.com>
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/438501
|
|
||||||
Run-TryBot: Carlos Amedee <carlos@golang.org>
|
|
||||||
Reviewed-by: Carlos Amedee <carlos@golang.org>
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,174 +0,0 @@
|
|||||||
From 51a477dc4f1130d53e66cd2003de0bac40e5e2be Mon Sep 17 00:00:00 2001
|
|
||||||
From: Damien Neil <dneil@google.com>
|
|
||||||
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 <roland@golang.org>
|
|
||||||
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Run-TryBot: Damien Neil <dneil@google.com>
|
|
||||||
(cherry picked from commit 7c84234142149bd24a4096c6cab691d3593f3431)
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/433695
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,186 +0,0 @@
|
|||||||
From 7dd44b287830fbb2256aceac4a36756b955c0279 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Damien Neil <dneil@google.com>
|
|
||||||
Date: Fri, 2 Sep 2022 20:45:18 -0700
|
|
||||||
Subject: [PATCH] archive/tar: limit size of headers
|
|
||||||
|
|
||||||
Set a 1MiB limit on special file blocks (PAX headers, GNU long names,
|
|
||||||
GNU link names), to avoid reading arbitrarily large amounts of data
|
|
||||||
into memory.
|
|
||||||
|
|
||||||
Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting
|
|
||||||
this issue.
|
|
||||||
|
|
||||||
Fixes CVE-2022-2879
|
|
||||||
Updates #54853
|
|
||||||
Fixes #55925
|
|
||||||
|
|
||||||
Change-Id: I85136d6ff1e0af101a112190e027987ab4335680
|
|
||||||
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1565555
|
|
||||||
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
|
|
||||||
Run-TryBot: Roland Shoemaker <bracewell@google.com>
|
|
||||||
Reviewed-by: Roland Shoemaker <bracewell@google.com>
|
|
||||||
(cherry picked from commit 6ee768cef6b82adf7a90dcf367a1699ef694f3b2)
|
|
||||||
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1590622
|
|
||||||
Reviewed-by: Damien Neil <dneil@google.com>
|
|
||||||
Reviewed-by: Julie Qiu <julieqiu@google.com>
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/438500
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
|
|
||||||
Reviewed-by: Carlos Amedee <carlos@golang.org>
|
|
||||||
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
|
|
||||||
Run-TryBot: Carlos Amedee <carlos@golang.org>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,248 +0,0 @@
|
|||||||
From 0c539fa7a4a9d29252523e41e073198195ba6691 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Damien Neil <dneil@google.com>
|
|
||||||
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 <dneil@google.com>
|
|
||||||
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
|
|
||||||
Reviewed-by: Roland Shoemaker <bracewell@google.com>
|
|
||||||
TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
|
|
||||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/446916
|
|
||||||
Reviewed-by: Tatiana Bradley <tatiana@golang.org>
|
|
||||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
|
||||||
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
|
|
||||||
Reviewed-by: Heschi Kreinick <heschi@google.com>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
@ -1,434 +0,0 @@
|
|||||||
From 719a248de7215aeb2ca38e71c0056a777712f1e2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Russ Cox <rsc@golang.org>
|
|
||||||
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 <rsc@golang.org>
|
|
||||||
Run-TryBot: Russ Cox <rsc@golang.org>
|
|
||||||
TryBot-Result: Go Bot <gobot@golang.org>
|
|
||||||
Reviewed-by: Ian Lance Taylor <iant@golang.org>
|
|
||||||
---
|
|
||||||
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
|
|
||||||
|
|
||||||
Binary file not shown.
116
golang.spec
116
golang.spec
@ -2,8 +2,8 @@
|
|||||||
%global _binaries_in_noarch_packages_terminate_build 0
|
%global _binaries_in_noarch_packages_terminate_build 0
|
||||||
%global golibdir %{_libdir}/golang
|
%global golibdir %{_libdir}/golang
|
||||||
%global goroot /usr/lib/%{name}
|
%global goroot /usr/lib/%{name}
|
||||||
%global go_api 1.17
|
%global go_api 1.19
|
||||||
%global go_version 1.17
|
%global go_version 1.19
|
||||||
%global __spec_install_post /usr/lib/rpm/check-rpaths /usr/lib/rpm/check-buildroot /usr/lib/rpm/brp-compress
|
%global __spec_install_post /usr/lib/rpm/check-rpaths /usr/lib/rpm/check-buildroot /usr/lib/rpm/brp-compress
|
||||||
%global __requires_exclude_from ^(%{_datadir}|/usr/lib)/%{name}/(doc|src)/.*$
|
%global __requires_exclude_from ^(%{_datadir}|/usr/lib)/%{name}/(doc|src)/.*$
|
||||||
%global __strip /bin/true
|
%global __strip /bin/true
|
||||||
@ -60,14 +60,13 @@
|
|||||||
%global gohostarch riscv64
|
%global gohostarch riscv64
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
|
||||||
Name: golang
|
Name: golang
|
||||||
Version: 1.17.3
|
Version: 1.19.4
|
||||||
Release: 13
|
Release: 1
|
||||||
Summary: The Go Programming Language
|
Summary: The Go Programming Language
|
||||||
License: BSD and Public Domain
|
License: BSD and Public Domain
|
||||||
URL: https://golang.org/
|
URL: https://golang.org/
|
||||||
Source0: https://dl.google.com/go/go1.17.3.src.tar.gz
|
Source0: https://dl.google.com/go/go1.19.4.src.tar.gz
|
||||||
|
|
||||||
%if !%{golang_bootstrap}
|
%if !%{golang_bootstrap}
|
||||||
BuildRequires: gcc-go >= 5
|
BuildRequires: gcc-go >= 5
|
||||||
@ -94,7 +93,6 @@ Requires(post): %{_sbindir}/update-alternatives
|
|||||||
Requires(postun): %{_sbindir}/update-alternatives
|
Requires(postun): %{_sbindir}/update-alternatives
|
||||||
Recommends: glibc gcc git subversion
|
Recommends: glibc gcc git subversion
|
||||||
|
|
||||||
|
|
||||||
# generated by:
|
# generated by:
|
||||||
# go list -f {{.ImportPath}} ./src/vendor/... | sed "s:_$PWD/src/vendor/::g;s:_:.:;s:.*:Provides\: bundled(golang(&)):" && go list -f {{.ImportPath}} ./src/cmd/vendor/... | sed "s:_$PWD/src/cmd/vendor/::g;s:_:.:;s:.*:Provides\: bundled(golang(&)):"
|
# go list -f {{.ImportPath}} ./src/vendor/... | sed "s:_$PWD/src/vendor/::g;s:_:.:;s:.*:Provides\: bundled(golang(&)):" && go list -f {{.ImportPath}} ./src/cmd/vendor/... | sed "s:_$PWD/src/cmd/vendor/::g;s:_:.:;s:.*:Provides\: bundled(golang(&)):"
|
||||||
Provides: bundled(golang(golang.org/x/crypto/chacha20poly1305))
|
Provides: bundled(golang(golang.org/x/crypto/chacha20poly1305))
|
||||||
@ -150,30 +148,7 @@ Obsoletes: %{name}-vim < 1.4
|
|||||||
Obsoletes: emacs-%{name} < 1.4
|
Obsoletes: emacs-%{name} < 1.4
|
||||||
Requires: %{vendor}-rpm-config
|
Requires: %{vendor}-rpm-config
|
||||||
|
|
||||||
Patch6001: 0001-release-branch.go1.17-crypto-elliptic-tolerate-zero-.patch
|
#Patch6001: 0001-release-branch.go1.17-crypto-elliptic-tolerate-zero-.patch
|
||||||
Patch6002: 0002-release-branch.go1.17-encoding-pem-fix-stack-overflo.patch
|
|
||||||
Patch6003: 0003-release-branch.go1.17-syscall-fix-ForkLock-spurious-.patch
|
|
||||||
Patch6004: 0004-backport-cmd-link-mark-unexported-methods-for-plugins.patch
|
|
||||||
Patch6005: 0005-release-branch.go1.17-net-http-preserve-nil-values-i.patch
|
|
||||||
Patch6006: 0006-release-branch.go1.17-go-parser-limit-recursion-dept.patch
|
|
||||||
Patch6007: 0007-release-branch.go1.17-net-http-don-t-strip-whitespac.patch
|
|
||||||
Patch6008: 0008-release-branch.go1.17-encoding-xml-limit-depth-of-ne.patch
|
|
||||||
Patch6009: 0009-release-branch.go1.17-encoding-gob-add-a-depth-limit.patch
|
|
||||||
Patch6010: 0010-release-branch.go1.17-io-fs-fix-stack-exhaustion-in-.patch
|
|
||||||
Patch6011: 0011-release-branch.go1.17-path-filepath-fix-stack-exhaus.patch
|
|
||||||
Patch6012: 0012-release-branch.go1.17-encoding-xml-use-iterative-Ski.patch
|
|
||||||
Patch6013: 0013-release-branch.go1.17-compress-gzip-fix-stack-exhaus.patch
|
|
||||||
Patch6014: 0014-release-branch.go1.17-crypto-tls-randomly-generate-t.patch
|
|
||||||
Patch6015: 0015-release-branch.go1.17-crypto-rand-properly-handle-la.patch
|
|
||||||
Patch6016: 0016-release-branch.go1.17-math-big-check-buffer-lengths-.patch
|
|
||||||
Patch6017: 0017-path-filepath-do-not-remove-prefix-.-when-following-.patch
|
|
||||||
Patch6018: 0018-release-branch.go1.17-syscall-check-correct-group-in.patch
|
|
||||||
Patch6019: 0019-release-branch.go1.18-net-http-update-bundled-golang.patch
|
|
||||||
Patch6020: 0020-release-branch.go1.18-regexp-limit-size-of-parsed-re.patch
|
|
||||||
Patch6021: 0021-release-branch.go1.18-net-http-httputil-avoid-query-.patch
|
|
||||||
Patch6022: 0022-release-branch.go1.18-archive-tar-limit-size-of-head.patch
|
|
||||||
Patch6023: 0023-syscall-os-exec-reject-environment-variables-contain.patch
|
|
||||||
Patch6024: 0024-release-branch.go1.18-add-definition-byte-string-cut.patch
|
|
||||||
|
|
||||||
ExclusiveArch: %{golang_arches}
|
ExclusiveArch: %{golang_arches}
|
||||||
|
|
||||||
@ -387,7 +362,7 @@ fi
|
|||||||
%files -f go-pkg.list
|
%files -f go-pkg.list
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%doc AUTHORS CONTRIBUTORS LICENSE PATENTS
|
%doc LICENSE PATENTS
|
||||||
%doc %{goroot}/VERSION
|
%doc %{goroot}/VERSION
|
||||||
%dir %{goroot}/doc
|
%dir %{goroot}/doc
|
||||||
%doc %{goroot}/doc/*
|
%doc %{goroot}/doc/*
|
||||||
@ -412,79 +387,6 @@ fi
|
|||||||
%files devel -f go-tests.list -f go-misc.list -f go-src.list
|
%files devel -f go-tests.list -f go-misc.list -f go-src.list
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Sat Dec 17 2022 wanglimin<wanglimin@xfusion.com> - 1.17.3-13
|
|
||||||
- Add string cut
|
|
||||||
|
|
||||||
* Fri Oct 11 2022 hanchao <hanchao47@huawei.com> - 1.17.3-12
|
* Tue Jan 10 2023 hanchao <hanchao47@huawei.com> - 1.19.4-1
|
||||||
- Type:CVE
|
- upgrade to 1.19.4
|
||||||
- CVE:CVE-2022-41716
|
|
||||||
- SUG:NA
|
|
||||||
- DESC: remove hard code and strong dependency of git, subversion and mercurial
|
|
||||||
|
|
||||||
* Fri Oct 11 2022 hanchao <hanchao47@huawei.com> - 1.17.3-11
|
|
||||||
- Type:CVE
|
|
||||||
- CVE:CVE-2022-41716
|
|
||||||
- SUG:NA
|
|
||||||
- DESC: fix CVE-2022-41716
|
|
||||||
|
|
||||||
* Mon Oct 10 2022 hanchao <hanchao47@huawei.com> - 1.17.3-10
|
|
||||||
- Type:CVE
|
|
||||||
- CVE:CVE-2022-41715,CVE-2022-2880,CVE-2022-2879
|
|
||||||
- SUG:NA
|
|
||||||
- DESC: fix CVE-2022-41715,CVE-2022-2880,CVE-2022-2879
|
|
||||||
|
|
||||||
* Thu Sep 15 2022 hanchao <hanchao47@huawei.com> - 1.17.3-9
|
|
||||||
- Type:CVE
|
|
||||||
- CVE:CVE-2022-27664
|
|
||||||
- SUG:NA
|
|
||||||
- DESC: fix CVE-2022-27664
|
|
||||||
|
|
||||||
* Thu Sep 8 2022 hanchao<hanchao47@huawei.com> - 1.17.3-8
|
|
||||||
- Type:bugfix
|
|
||||||
- CVE:NA
|
|
||||||
- SUG:NA
|
|
||||||
- DESC: golang: modify the golang.spec to remove unnecessary files
|
|
||||||
from golang-help package
|
|
||||||
|
|
||||||
* Thu Aug 18 2022 hanchao <hanchao47@huawei.com> - 1.17.3-7
|
|
||||||
- Type:CVE
|
|
||||||
- CVE:CVE-2022-29804,CVE-2022-29526
|
|
||||||
- SUG:NA
|
|
||||||
- DESC: fix CVE-2022-29804,CVE-2022-29526
|
|
||||||
|
|
||||||
* Mon Aug 8 2022 hanchao <hanchao47@huawei.com> - 1.17.3-6
|
|
||||||
- Type:CVE
|
|
||||||
- CVE:NA
|
|
||||||
- SUG:NA
|
|
||||||
- DESC: fix CVE-2022-32189
|
|
||||||
|
|
||||||
* Tue Jul 26 2022 hanchao <hanchao47@huawei.com> - 1.17.3-5
|
|
||||||
- Type:CVE
|
|
||||||
- CVE:NA
|
|
||||||
- SUG:NA
|
|
||||||
- DESC: fix CVE-2022-32148,CVE-2022-1962,CVE-2022-1705,CVE-2022-30633,
|
|
||||||
CVE-2022-30635,CVE-2022-30630,CVE-2022-30632,CVE-2022-28131,
|
|
||||||
CVE-2022-30631,CVE-2022-30629,CVE-2022-30634
|
|
||||||
|
|
||||||
* Tue Jun 28 2022 Bin Hu <hubin73@huawei.com> - 1.17.3-4
|
|
||||||
- Type:bugfix
|
|
||||||
- CVE:NA
|
|
||||||
- SUG:NA
|
|
||||||
- DESC:backport patch to fix bug of golang plugin mode
|
|
||||||
|
|
||||||
* Fri May 6 2022 hanchao <hanchao47@huawei.com> - 1.17.3-3
|
|
||||||
- Type:CVE
|
|
||||||
- CVE:CVE-2021-44717
|
|
||||||
- SUG:NA
|
|
||||||
- DESC:fix CVE-2021-44717
|
|
||||||
- fix CVE-2021-44717
|
|
||||||
|
|
||||||
* Fri May 6 2022 hanchao <hanchao47@huawei.com> - 1.17.3-2
|
|
||||||
- Type:CVE
|
|
||||||
- CVE:CVE-2022-28327,CVE-2022-24675
|
|
||||||
- SUG:NA
|
|
||||||
- DESC:fix CVE-2022-28327,CVE-2022-24675
|
|
||||||
- fix CVE-2022-28327 CVE-2022-24675
|
|
||||||
|
|
||||||
* Mon Nov 29 2021 chenjiankun <chenjiankun1@huawei.com> - 1.17.3-1
|
|
||||||
- upgrade to 1.17.3
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user