Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch for go1.18.3 #28

Open
wants to merge 8 commits into
base: origin-go1.18.3-1733517364
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/cmd/internal/moddeps/moddeps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
60 changes: 29 additions & 31 deletions src/compress/gzip/gunzip.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
16 changes: 16 additions & 0 deletions src/compress/gzip/gunzip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
19 changes: 12 additions & 7 deletions src/encoding/gob/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -896,23 +901,23 @@ 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)
}

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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
24 changes: 24 additions & 0 deletions src/encoding/gob/gobencdec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"fmt"
"io"
"net"
"reflect"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -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)
}
}
42 changes: 27 additions & 15 deletions src/encoding/xml/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func (d *Decoder) DecodeElement(v any, start *StartElement) error {
if val.Kind() != reflect.Pointer {
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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -732,24 +743,25 @@ 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 {
return err
}
switch tok.(type) {
case StartElement:
if err := d.Skip(); err != nil {
return err
}
depth++
case EndElement:
return nil
if depth == 0 {
return nil
}
depth--
}
}
}
32 changes: 32 additions & 0 deletions src/encoding/xml/read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
package xml

import (
"bytes"
"errors"
"io"
"reflect"
"runtime"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -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)
}
}
10 changes: 8 additions & 2 deletions src/go/parser/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,11 @@ func ParseFile(fset *token.FileSet, filename string, src any, mode Mode) (f *ast
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)
}
}

Expand Down Expand Up @@ -203,8 +206,11 @@ func ParseExprFrom(fset *token.FileSet, filename string, src any, mode Mode) (ex
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()
Expand Down
Loading