From 31d06b58fa2448c8e98ac78a97cc9a52dc2aa035 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 7 Sep 2022 16:36:41 -0700 Subject: [release-branch.go1.18] all: upgrade golang.org/x/net to v0.0.0-20220907013725-0a43f88f7ef0 Restore vendoring after go1.18.6 security release. For #53977 Change-Id: Ifff04582aa3d5fce40606265db42af3415c3c0b4 Reviewed-on: https://go-review.googlesource.com/c/go/+/429316 Reviewed-by: Carlos Amedee Run-TryBot: Damien Neil TryBot-Result: Gopher Robot --- src/cmd/internal/moddeps/moddeps_test.go | 2 -- src/go.mod | 2 +- src/go.sum | 4 ++-- src/net/http/h2_bundle.go | 13 ++++++------- src/vendor/modules.txt | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 3306e29431..56c3b2585c 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -34,8 +34,6 @@ 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/go.mod b/src/go.mod index 8ca3c5fb70..4613bb6825 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 - golang.org/x/net v0.0.0-20211209124913-491a49abca63 + golang.org/x/net v0.0.0-20220907013725-0a43f88f7ef0 ) require ( diff --git a/src/go.sum b/src/go.sum index 7c93a59725..07cb8d82d5 100644 --- a/src/go.sum +++ b/src/go.sum @@ -1,7 +1,7 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220907013725-0a43f88f7ef0 h1:XXaSUSplyi6wsRNJGB7vUBvDjbxc8UPYBsf9ukBQ3KA= +golang.org/x/net v0.0.0-20220907013725-0a43f88f7ef0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y= diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go index 1e78f6cdb9..292dded28d 100644 --- a/src/net/http/h2_bundle.go +++ b/src/net/http/h2_bundle.go @@ -3384,11 +3384,10 @@ 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 @@ -3579,8 +3578,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. diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt index 4714b1d386..109a99e44a 100644 --- a/src/vendor/modules.txt +++ b/src/vendor/modules.txt @@ -9,7 +9,7 @@ golang.org/x/crypto/curve25519/internal/field golang.org/x/crypto/hkdf golang.org/x/crypto/internal/poly1305 golang.org/x/crypto/internal/subtle -# golang.org/x/net v0.0.0-20211209124913-491a49abca63 +# golang.org/x/net v0.0.0-20220907013725-0a43f88f7ef0 ## explicit; go 1.17 golang.org/x/net/dns/dnsmessage golang.org/x/net/http/httpguts -- cgit v1.2.3-54-g00ecf From d5a5db3b41e45a1c5ec39a1a8f91d863e9e7770d Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Mon, 8 Aug 2022 12:31:33 -0700 Subject: [release-branch.go1.18] cmd/compile/internal/inline: fix latent CalleeEffects issue ir.ClosureExpr implements ir.InitNode, so ir.InitExpr can prepend init statements to it. However, CalleeEffects wasn't aware of this and could cause the init statements to get dropped when inlining a call to a closure. This isn't an issue today, because we don't create closures with init statements. But I ran into this within unified IR. Easy and robust solution: just take advantage that ir.TakeInit can handle any node. Fixes #54918. Change-Id: Ica05fbf6a8c5be4b11927daf84491a1140da5431 Reviewed-on: https://go-review.googlesource.com/c/go/+/422196 Reviewed-by: Than McIntosh Run-TryBot: Matthew Dempsky TryBot-Result: Gopher Robot Reviewed-by: Cuong Manh Le Reviewed-on: https://go-review.googlesource.com/c/go/+/429897 Reviewed-by: Michael Knyszek --- src/cmd/compile/internal/inline/inl.go | 4 ++-- test/typeparam/issue54911.go | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 test/typeparam/issue54911.go diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 716a7fbcd9..bc7ec5cf20 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -771,18 +771,18 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b // CalleeEffects appends any side effects from evaluating callee to init. func CalleeEffects(init *ir.Nodes, callee ir.Node) { for { + init.Append(ir.TakeInit(callee)...) + switch callee.Op() { case ir.ONAME, ir.OCLOSURE, ir.OMETHEXPR: return // done case ir.OCONVNOP: conv := callee.(*ir.ConvExpr) - init.Append(ir.TakeInit(conv)...) callee = conv.X case ir.OINLCALL: ic := callee.(*ir.InlinedCallExpr) - init.Append(ir.TakeInit(ic)...) init.Append(ic.Body.Take()...) callee = ic.SingleResult() diff --git a/test/typeparam/issue54911.go b/test/typeparam/issue54911.go new file mode 100644 index 0000000000..0df2b99563 --- /dev/null +++ b/test/typeparam/issue54911.go @@ -0,0 +1,21 @@ +// compile -G=3 + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +type Set[T comparable] map[T]struct{} + +func (s Set[T]) Add() Set[T] { + return s +} + +func (s Set[T]) Copy() Set[T] { + return Set[T].Add(s) +} + +func main() { + _ = Set[int]{42: {}} +} -- cgit v1.2.3-54-g00ecf From e0a364b061060aa0e0ed14df5cdce284e878d605 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sat, 17 Sep 2022 18:52:35 -0400 Subject: [release-branch.go1.18] cmd/compile: avoid using destination pointer base type in memmove optimization The type of the source and destination of a memmove call isn't always accurate. It will always be a pointer (or an unsafe.Pointer), but the base type might not be accurate. This comes about because multiple copies of a pointer with different base types are coalesced into a single value. In the failing example, the IData selector of the input argument is a *[32]byte in one branch of the type switch, and a *[]byte in the other branch. During the expand_calls pass both IDatas become just copies of the input register. Those copies are deduped and an arbitrary one wins (in this case, *[]byte is the unfortunate winner). Generally an op v can rely on v.Type during rewrite rules. But relying on v.Args[i].Type is discouraged. Fixes #55151 Change-Id: I348fd9accf2058a87cd191eec01d39cda612f120 Reviewed-on: https://go-review.googlesource.com/c/go/+/431496 TryBot-Result: Gopher Robot Reviewed-by: Cherry Mui Run-TryBot: Keith Randall Reviewed-by: Cuong Manh Le Reviewed-by: Keith Randall (cherry picked from commit e283473ebbebf4a80db166e7e852d03c5cff1a61) Reviewed-on: https://go-review.googlesource.com/c/go/+/431918 --- src/cmd/compile/internal/ssa/gen/generic.rules | 17 +++++---- src/cmd/compile/internal/ssa/rewritegeneric.go | 50 +++++++++++++------------- test/fixedbugs/issue55122.go | 42 ++++++++++++++++++++++ test/fixedbugs/issue55122b.go | 43 ++++++++++++++++++++++ 4 files changed, 119 insertions(+), 33 deletions(-) create mode 100644 test/fixedbugs/issue55122.go create mode 100644 test/fixedbugs/issue55122b.go diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 6dbe9b47d0..b78d2aac3c 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -2082,7 +2082,13 @@ // Inline small or disjoint runtime.memmove calls with constant length. // See the comment in op Move in genericOps.go for discussion of the type. - +// +// Note that we've lost any knowledge of the type and alignment requirements +// of the source and destination. We only know the size, and that the type +// contains no pointers. +// The type of the move is not necessarily v.Args[0].Type().Elem()! +// See issue 55122 for details. +// // Because expand calls runs after prove, constants useful to this pattern may not appear. // Both versions need to exist; the memory and register variants. // @@ -2090,31 +2096,28 @@ (SelectN [0] call:(StaticCall {sym} s1:(Store _ (Const(64|32) [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))) && sz >= 0 && isSameCall(sym, "runtime.memmove") - && t.IsPtr() // avoids TUNSAFEPTR, see issue 30061 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call) - => (Move {t.Elem()} [int64(sz)] dst src mem) + => (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) // Match post-expansion calls, register version. (SelectN [0] call:(StaticCall {sym} dst src (Const(64|32) [sz]) mem)) && sz >= 0 && call.Uses == 1 // this will exclude all calls with results && isSameCall(sym, "runtime.memmove") - && dst.Type.IsPtr() // avoids TUNSAFEPTR, see issue 30061 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) - => (Move {dst.Type.Elem()} [int64(sz)] dst src mem) + => (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) // Match pre-expansion calls. (SelectN [0] call:(StaticLECall {sym} dst src (Const(64|32) [sz]) mem)) && sz >= 0 && call.Uses == 1 // this will exclude all calls with results && isSameCall(sym, "runtime.memmove") - && dst.Type.IsPtr() // avoids TUNSAFEPTR, see issue 30061 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) - => (Move {dst.Type.Elem()} [int64(sz)] dst src mem) + => (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) // De-virtualize late-expanded interface calls into late-expanded static calls. // Note that (ITab (IMake)) doesn't get rewritten until after the first opt pass, diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index fbf227562a..434402b55d 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -21053,8 +21053,8 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { return true } // match: (SelectN [0] call:(StaticCall {sym} s1:(Store _ (Const64 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))) - // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call) - // result: (Move {t.Elem()} [int64(sz)] dst src mem) + // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call) + // result: (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) for { if auxIntToInt64(v.AuxInt) != 0 { break @@ -21084,21 +21084,20 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { if s3.Op != OpStore { break } - t := auxToType(s3.Aux) mem := s3.Args[2] dst := s3.Args[1] - if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call)) { + if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call)) { break } v.reset(OpMove) v.AuxInt = int64ToAuxInt(int64(sz)) - v.Aux = typeToAux(t.Elem()) + v.Aux = typeToAux(types.Types[types.TUINT8]) v.AddArg3(dst, src, mem) return true } // match: (SelectN [0] call:(StaticCall {sym} s1:(Store _ (Const32 [sz]) s2:(Store _ src s3:(Store {t} _ dst mem))))) - // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call) - // result: (Move {t.Elem()} [int64(sz)] dst src mem) + // cond: sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call) + // result: (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) for { if auxIntToInt64(v.AuxInt) != 0 { break @@ -21128,21 +21127,20 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { if s3.Op != OpStore { break } - t := auxToType(s3.Aux) mem := s3.Args[2] dst := s3.Args[1] - if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && t.IsPtr() && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call)) { + if !(sz >= 0 && isSameCall(sym, "runtime.memmove") && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && isInlinableMemmove(dst, src, int64(sz), config) && clobber(s1, s2, s3, call)) { break } v.reset(OpMove) v.AuxInt = int64ToAuxInt(int64(sz)) - v.Aux = typeToAux(t.Elem()) + v.Aux = typeToAux(types.Types[types.TUINT8]) v.AddArg3(dst, src, mem) return true } // match: (SelectN [0] call:(StaticCall {sym} dst src (Const64 [sz]) mem)) - // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) - // result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem) + // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) + // result: (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) for { if auxIntToInt64(v.AuxInt) != 0 { break @@ -21160,18 +21158,18 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { break } sz := auxIntToInt64(call_2.AuxInt) - if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) { + if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) { break } v.reset(OpMove) v.AuxInt = int64ToAuxInt(int64(sz)) - v.Aux = typeToAux(dst.Type.Elem()) + v.Aux = typeToAux(types.Types[types.TUINT8]) v.AddArg3(dst, src, mem) return true } // match: (SelectN [0] call:(StaticCall {sym} dst src (Const32 [sz]) mem)) - // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) - // result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem) + // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) + // result: (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) for { if auxIntToInt64(v.AuxInt) != 0 { break @@ -21189,18 +21187,18 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { break } sz := auxIntToInt32(call_2.AuxInt) - if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) { + if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) { break } v.reset(OpMove) v.AuxInt = int64ToAuxInt(int64(sz)) - v.Aux = typeToAux(dst.Type.Elem()) + v.Aux = typeToAux(types.Types[types.TUINT8]) v.AddArg3(dst, src, mem) return true } // match: (SelectN [0] call:(StaticLECall {sym} dst src (Const64 [sz]) mem)) - // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) - // result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem) + // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) + // result: (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) for { if auxIntToInt64(v.AuxInt) != 0 { break @@ -21218,18 +21216,18 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { break } sz := auxIntToInt64(call_2.AuxInt) - if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) { + if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) { break } v.reset(OpMove) v.AuxInt = int64ToAuxInt(int64(sz)) - v.Aux = typeToAux(dst.Type.Elem()) + v.Aux = typeToAux(types.Types[types.TUINT8]) v.AddArg3(dst, src, mem) return true } // match: (SelectN [0] call:(StaticLECall {sym} dst src (Const32 [sz]) mem)) - // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) - // result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem) + // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call) + // result: (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem) for { if auxIntToInt64(v.AuxInt) != 0 { break @@ -21247,12 +21245,12 @@ func rewriteValuegeneric_OpSelectN(v *Value) bool { break } sz := auxIntToInt32(call_2.AuxInt) - if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) { + if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) { break } v.reset(OpMove) v.AuxInt = int64ToAuxInt(int64(sz)) - v.Aux = typeToAux(dst.Type.Elem()) + v.Aux = typeToAux(types.Types[types.TUINT8]) v.AddArg3(dst, src, mem) return true } diff --git a/test/fixedbugs/issue55122.go b/test/fixedbugs/issue55122.go new file mode 100644 index 0000000000..24da89dcb6 --- /dev/null +++ b/test/fixedbugs/issue55122.go @@ -0,0 +1,42 @@ +// run + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + for i := 0; i < 10000; i++ { + h(i) + sink = make([]byte, 1024) // generate some garbage + } +} + +func h(iter int) { + var x [32]byte + for i := 0; i < 32; i++ { + x[i] = 99 + } + g(&x) + if x == ([32]byte{}) { + return + } + for i := 0; i < 32; i++ { + println(x[i]) + } + panic(iter) +} + +//go:noinline +func g(x interface{}) { + switch e := x.(type) { + case *[32]byte: + var c [32]byte + *e = c + case *[]byte: + *e = nil + } +} + +var sink []byte diff --git a/test/fixedbugs/issue55122b.go b/test/fixedbugs/issue55122b.go new file mode 100644 index 0000000000..a911a9f1b6 --- /dev/null +++ b/test/fixedbugs/issue55122b.go @@ -0,0 +1,43 @@ +// run + +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func main() { + for i := 0; i < 10000; i++ { + h(i) + sink = make([]byte, 1024) // generate some garbage + } +} + +func h(iter int) { + var x [32]byte + for i := 0; i < 32; i++ { + x[i] = 99 + } + g(&x) + if x == ([32]byte{}) { + return + } + for i := 0; i < 32; i++ { + println(x[i]) + } + panic(iter) +} + +//go:noinline +func g(x interface{}) { + switch e := x.(type) { + case *[32]byte: + var c [32]byte + *e = c + case *[3]*byte: + var c [3]*byte + *e = c + } +} + +var sink []byte -- cgit v1.2.3-54-g00ecf From e40a130cc02cca954ff8e33aa9f5950ecab99e3b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 12 Sep 2022 15:51:32 -0700 Subject: [release-branch.go1.18] go/types, types2: allow (string...) signature with NewSignatureType Includes cases where the core type of the variadic parameter is a slice or bytestring. Permits a client to create the signature for various instantiations of append. Fixes #55148. Change-Id: I0f4983eb00c088cbe1d87954ee0b2df0ccc3bc49 Reviewed-on: https://go-review.googlesource.com/c/go/+/430455 TryBot-Result: Gopher Robot Reviewed-by: Robert Findley Auto-Submit: Robert Griesemer Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer Reviewed-on: https://go-review.googlesource.com/c/go/+/431915 --- src/cmd/compile/internal/types2/issues_test.go | 37 ++++++++++++++++++++++++++ src/cmd/compile/internal/types2/signature.go | 15 +++++++---- src/go/types/issues_test.go | 37 ++++++++++++++++++++++++++ src/go/types/signature.go | 11 +++++--- 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go index 697a73525c..fc4aeb1634 100644 --- a/src/cmd/compile/internal/types2/issues_test.go +++ b/src/cmd/compile/internal/types2/issues_test.go @@ -637,3 +637,40 @@ func TestIssue50646(t *testing.T) { t.Errorf("comparable not assignable to any") } } + +func TestIssue55030(t *testing.T) { + // makeSig makes the signature func(typ...) + makeSig := func(typ Type) { + par := NewVar(nopos, nil, "", typ) + params := NewTuple(par) + NewSignatureType(nil, nil, nil, params, nil, true) + } + + // makeSig must not panic for the following (example) types: + // []int + makeSig(NewSlice(Typ[Int])) + + // string + makeSig(Typ[String]) + + // P where P's core type is string + { + P := NewTypeName(nopos, nil, "P", nil) // [P string] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{Typ[String]}))) + } + + // P where P's core type is an (unnamed) slice + { + P := NewTypeName(nopos, nil, "P", nil) // [P []int] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{NewSlice(Typ[Int])}))) + } + + // P where P's core type is bytestring (i.e., string or []byte) + { + t1 := NewTerm(true, Typ[String]) // ~string + t2 := NewTerm(false, NewSlice(Typ[Byte])) // []byte + u := NewUnion([]*Term{t1, t2}) // ~string | []byte + P := NewTypeName(nopos, nil, "P", nil) // [P ~string | []byte] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{u}))) + } +} diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index c98024f924..f52f3e25b2 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -4,7 +4,10 @@ package types2 -import "cmd/compile/internal/syntax" +import ( + "cmd/compile/internal/syntax" + "fmt" +) // ---------------------------------------------------------------------------- // API @@ -28,16 +31,18 @@ type Signature struct { // NewSignatureType creates a new function type for the given receiver, // receiver type parameters, type parameters, parameters, and results. If // variadic is set, params must hold at least one parameter and the last -// parameter must be of unnamed slice type. If recv is non-nil, typeParams must -// be empty. If recvTypeParams is non-empty, recv must be non-nil. +// parameter's core type must be of unnamed slice or bytestring type. +// If recv is non-nil, typeParams must be empty. If recvTypeParams is +// non-empty, recv must be non-nil. func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params, results *Tuple, variadic bool) *Signature { if variadic { n := params.Len() if n == 0 { panic("variadic function must have at least one parameter") } - if _, ok := params.At(n - 1).typ.(*Slice); !ok { - panic("variadic parameter must be of unnamed slice type") + core := coreString(params.At(n - 1).typ) + if _, ok := core.(*Slice); !ok && !isString(core) { + panic(fmt.Sprintf("got %s, want variadic parameter with unnamed slice type or string as core type", core.String())) } } sig := &Signature{recv: recv, params: params, results: results, variadic: variadic} diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go index bd98f48177..2892aab38e 100644 --- a/src/go/types/issues_test.go +++ b/src/go/types/issues_test.go @@ -664,3 +664,40 @@ func TestIssue50646(t *testing.T) { t.Errorf("comparable not assignable to any") } } + +func TestIssue55030(t *testing.T) { + // makeSig makes the signature func(typ...) + makeSig := func(typ Type) { + par := NewVar(token.NoPos, nil, "", typ) + params := NewTuple(par) + NewSignatureType(nil, nil, nil, params, nil, true) + } + + // makeSig must not panic for the following (example) types: + // []int + makeSig(NewSlice(Typ[Int])) + + // string + makeSig(Typ[String]) + + // P where P's core type is string + { + P := NewTypeName(token.NoPos, nil, "P", nil) // [P string] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{Typ[String]}))) + } + + // P where P's core type is an (unnamed) slice + { + P := NewTypeName(token.NoPos, nil, "P", nil) // [P []int] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{NewSlice(Typ[Int])}))) + } + + // P where P's core type is bytestring (i.e., string or []byte) + { + t1 := NewTerm(true, Typ[String]) // ~string + t2 := NewTerm(false, NewSlice(Typ[Byte])) // []byte + u := NewUnion([]*Term{t1, t2}) // ~string | []byte + P := NewTypeName(token.NoPos, nil, "P", nil) // [P ~string | []byte] + makeSig(NewTypeParam(P, NewInterfaceType(nil, []Type{u}))) + } +} diff --git a/src/go/types/signature.go b/src/go/types/signature.go index a340ac701e..d22646d7a8 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -5,6 +5,7 @@ package types import ( + "fmt" "go/ast" "go/token" ) @@ -41,16 +42,18 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { // NewSignatureType creates a new function type for the given receiver, // receiver type parameters, type parameters, parameters, and results. If // variadic is set, params must hold at least one parameter and the last -// parameter must be of unnamed slice type. If recv is non-nil, typeParams must -// be empty. If recvTypeParams is non-empty, recv must be non-nil. +// parameter's core type must be of unnamed slice or bytestring type. +// If recv is non-nil, typeParams must be empty. If recvTypeParams is +// non-empty, recv must be non-nil. func NewSignatureType(recv *Var, recvTypeParams, typeParams []*TypeParam, params, results *Tuple, variadic bool) *Signature { if variadic { n := params.Len() if n == 0 { panic("variadic function must have at least one parameter") } - if _, ok := params.At(n - 1).typ.(*Slice); !ok { - panic("variadic parameter must be of unnamed slice type") + core := coreString(params.At(n - 1).typ) + if _, ok := core.(*Slice); !ok && !isString(core) { + panic(fmt.Sprintf("got %s, want variadic parameter with unnamed slice type or string as core type", core.String())) } } sig := &Signature{recv: recv, params: params, results: results, variadic: variadic} -- cgit v1.2.3-54-g00ecf From c8e1cf49d187e9749e4dfbed5bd81d8b9b3c3307 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 14 Sep 2022 19:50:00 -0400 Subject: [release-branch.go1.18] cmd/link: stop passing -pagezero_size to darwin linker We added -pagezero_size in CL 72730, where it was intented for iOS. The current code passes it only on macOS/AMD64 instead. It is not really necessary there. Also, the new darwin linker starts to emit a warning about deprecation of the flag. Stop passing it. For #55113 Updates #54482, #55112. Change-Id: If9db7a1645c37d4284e48f075856912df8d8c1a0 Reviewed-on: https://go-review.googlesource.com/c/go/+/430936 TryBot-Result: Gopher Robot Reviewed-by: Than McIntosh Run-TryBot: Cherry Mui (cherry picked from commit 5231ba2f054f2ecb1387bad00b8745d6fe532ea4) Reviewed-on: https://go-review.googlesource.com/c/go/+/431516 Reviewed-by: Austin Clements --- src/cmd/link/internal/ld/lib.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index f1a37e955e..5fb0b3d21f 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1324,7 +1324,6 @@ func (ctxt *Link) hostlink() { if ctxt.HeadType == objabi.Hdarwin { if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() { argv = append(argv, "-Wl,-no_pie") - argv = append(argv, "-Wl,-pagezero_size,4000000") } } case BuildModePIE: -- cgit v1.2.3-54-g00ecf From 2b9596cb9b2726efa3c5fb0717f117ae10e8b9f6 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Wed, 14 Sep 2022 21:01:04 -0400 Subject: [release-branch.go1.18] cmd/link: suppress -no_pie deprecation warning on darwin Apparently the new darwin linker starts to emit a warning about -no_pie deprecation. Maybe we want to switch to PIE by default. For now, suppress the warning. This also makes it easier for backporting to previous releases. Fixes #55113. Updates #55112, #54482. Change-Id: I1a3b74c237a9d00ec3b030fc3a9940a31e5cd37e Reviewed-on: https://go-review.googlesource.com/c/go/+/430937 Run-TryBot: Cherry Mui Reviewed-by: Than McIntosh TryBot-Result: Gopher Robot (cherry picked from commit 706d84fca2b36fdf670a0d921e6a8a3b481eaa05) Reviewed-on: https://go-review.googlesource.com/c/go/+/431518 Reviewed-by: Austin Clements --- src/cmd/link/internal/ld/lib.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 5fb0b3d21f..239e2dd4ef 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1659,6 +1659,13 @@ func (ctxt *Link) hostlink() { if len(out) > 0 { // always print external output even if the command is successful, so that we don't // swallow linker warnings (see https://golang.org/issue/17935). + if ctxt.IsDarwin() && ctxt.IsAMD64() { + const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n" + if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 { + // swallow -no_pie deprecation warning, issue 54482 + out = append(out[:i], out[i+len(noPieWarning):]...) + } + } ctxt.Logf("%s", out) } -- cgit v1.2.3-54-g00ecf From 9d2c73a9fd69e45876509bb3bdb2af99bf77da1e Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Thu, 22 Sep 2022 13:32:00 -0700 Subject: [release-branch.go1.18] net/http/httputil: avoid query parameter smuggling Query parameter smuggling occurs when a proxy's interpretation of query parameters differs from that of a downstream server. Change ReverseProxy to avoid forwarding ignored query parameters. Remove unparsable query parameters from the outbound request * if req.Form != nil after calling ReverseProxy.Director; and * before calling ReverseProxy.Rewrite. This change preserves the existing behavior of forwarding the raw query untouched if a Director hook does not parse the query by calling Request.ParseForm (possibly indirectly). Fixes #55842 For #54663 For CVE-2022-2880 Change-Id: If1621f6b0e73a49d79059dae9e6b256e0ff18ca9 Reviewed-on: https://go-review.googlesource.com/c/go/+/432976 Reviewed-by: Roland Shoemaker Reviewed-by: Brad Fitzpatrick TryBot-Result: Gopher Robot Run-TryBot: Damien Neil (cherry picked from commit 7c84234142149bd24a4096c6cab691d3593f3431) Reviewed-on: https://go-review.googlesource.com/c/go/+/433695 Reviewed-by: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov --- src/net/http/httputil/reverseproxy.go | 36 +++++++++++++++ src/net/http/httputil/reverseproxy_test.go | 74 ++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index 319e2a3f3f..0abc32b833 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -250,6 +250,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) @@ -629,3 +632,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 90e8903e9c..33b1adea3a 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -1537,3 +1537,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) + } + } +} -- cgit v1.2.3-54-g00ecf From 0a723816cd205576945fa57fbdde7e6532d59d08 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Fri, 2 Sep 2022 20:45:18 -0700 Subject: [release-branch.go1.18] archive/tar: limit size of headers Set a 1MiB limit on special file blocks (PAX headers, GNU long names, GNU link names), to avoid reading arbitrarily large amounts of data into memory. Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting this issue. Fixes CVE-2022-2879 Updates #54853 Fixes #55925 Change-Id: I85136d6ff1e0af101a112190e027987ab4335680 Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1565555 Reviewed-by: Tatiana Bradley Run-TryBot: Roland Shoemaker Reviewed-by: Roland Shoemaker (cherry picked from commit 6ee768cef6b82adf7a90dcf367a1699ef694f3b2) Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1590622 Reviewed-by: Damien Neil Reviewed-by: Julie Qiu Reviewed-on: https://go-review.googlesource.com/c/go/+/438500 Reviewed-by: Dmitri Shuralyov Reviewed-by: Carlos Amedee Reviewed-by: Dmitri Shuralyov Run-TryBot: Carlos Amedee TryBot-Result: Gopher Robot --- src/archive/tar/format.go | 4 +++ src/archive/tar/reader.go | 14 +++++++++-- src/archive/tar/reader_test.go | 11 ++++++++- src/archive/tar/testdata/pax-bad-hdr-large.tar.bz2 | Bin 0 -> 156 bytes src/archive/tar/writer.go | 3 +++ src/archive/tar/writer_test.go | 27 +++++++++++++++++++++ 6 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/archive/tar/testdata/pax-bad-hdr-large.tar.bz2 diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go index 21b9d9d4db..8898c438b5 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 4b11909bc9..e609c15f27 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 } @@ -828,6 +828,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 f21a6065b4..140c736429 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/testdata/pax-bad-hdr-large.tar.bz2 b/src/archive/tar/testdata/pax-bad-hdr-large.tar.bz2 new file mode 100644 index 0000000000..06bf710d3a Binary files /dev/null and b/src/archive/tar/testdata/pax-bad-hdr-large.tar.bz2 differ diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go index 3729f7e82c..9b2e3e25d4 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 da3fb89e65..640264984a 100644 --- a/src/archive/tar/writer_test.go +++ b/src/archive/tar/writer_test.go @@ -1004,6 +1004,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 } -- cgit v1.2.3-54-g00ecf From e9017c2416ad0ef642f5e0c2eab2dbf3cba4d997 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 28 Sep 2022 11:18:51 -0400 Subject: [release-branch.go1.18] regexp: limit size of parsed regexps Set a 128 MB limit on the amount of space used by []syntax.Inst in the compiled form corresponding to a given regexp. Also set a 128 MB limit on the rune storage in the *syntax.Regexp tree itself. Thanks to Adam Korczynski (ADA Logics) and OSS-Fuzz for reporting this issue. Fixes CVE-2022-41715. Updates #55949. Fixes #55950. Change-Id: Ia656baed81564436368cf950e1c5409752f28e1b Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/1592136 TryBot-Result: Security TryBots Reviewed-by: Damien Neil Run-TryBot: Roland Shoemaker Reviewed-by: Julie Qiu Reviewed-on: https://go-review.googlesource.com/c/go/+/438501 Run-TryBot: Carlos Amedee Reviewed-by: Carlos Amedee Reviewed-by: Dmitri Shuralyov TryBot-Result: Gopher Robot Reviewed-by: Dmitri Shuralyov --- src/regexp/syntax/parse.go | 145 ++++++++++++++++++++++++++++++++++++++-- src/regexp/syntax/parse_test.go | 13 ++-- 2 files changed, 148 insertions(+), 10 deletions(-) diff --git a/src/regexp/syntax/parse.go b/src/regexp/syntax/parse.go index 0f6587ab27..df839800c4 100644 --- a/src/regexp/syntax/parse.go +++ b/src/regexp/syntax/parse.go @@ -90,15 +90,49 @@ const ( // 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 - numRegexp int // number of regexps allocated - height map[*Regexp]int // regexp height for height limit check + 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 { @@ -122,6 +156,104 @@ func (p *parser) reuse(re *Regexp) { 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 @@ -158,6 +290,7 @@ func (p *parser) calcHeight(re *Regexp, force bool) int { // 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) { @@ -189,7 +322,7 @@ func (p *parser) push(re *Regexp) *Regexp { } p.stack = append(p.stack, re) - p.checkHeight(re) + p.checkLimits(re) return re } @@ -299,7 +432,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.checkHeight(re) + p.checkLimits(re) if op == OpRepeat && (min >= 2 || max >= 2) && !repeatIsValid(re, 1000) { return "", &Error{ErrInvalidRepeatSize, before[:len(before)-len(after)]} @@ -503,6 +636,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 @@ -560,6 +694,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 diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go index 1ef6d8a3fe..67e3c5622a 100644 --- a/src/regexp/syntax/parse_test.go +++ b/src/regexp/syntax/parse_test.go @@ -484,12 +484,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})", - strings.Repeat("(", 1000) + strings.Repeat(")", 1000), - strings.Repeat("(?:", 1000) + strings.Repeat(")*", 1000), `\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{ -- cgit v1.2.3-54-g00ecf From 947091d31ccda14b0a362adff37b6e037f0f59f3 Mon Sep 17 00:00:00 2001 From: Gopher Robot Date: Tue, 4 Oct 2022 17:10:23 +0000 Subject: [release-branch.go1.18] go1.18.7 Change-Id: I0636d7335381c25ce39fd44c8cf758fb84737551 Reviewed-on: https://go-review.googlesource.com/c/go/+/438597 Reviewed-by: Carlos Amedee Run-TryBot: Gopher Robot Reviewed-by: Dmitri Shuralyov Auto-Submit: Gopher Robot TryBot-Result: Gopher Robot --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9fe64993ca..d5bd5caf57 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.18.6 \ No newline at end of file +go1.18.7 \ No newline at end of file -- cgit v1.2.3-54-g00ecf