Skip to content

Commit

Permalink
encoding/xml: use iterative Skip, rather than recursive
Browse files Browse the repository at this point in the history
Prevents exhausting the stack limit in _incredibly_ deeply nested
structures.

Fixes golang#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 <[email protected]>
Reviewed-by: Damien Neil <[email protected]>
Reviewed-on: https://go-review.googlesource.com/c/go/+/417062
Run-TryBot: Michael Knyszek <[email protected]>
Reviewed-by: Heschi Kreinick <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
rolandshoemaker authored and mknyszek committed Jul 12, 2022
1 parent c4c1993 commit 08c46ed
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
15 changes: 8 additions & 7 deletions src/encoding/xml/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -747,24 +747,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--
}
}
}
17 changes: 17 additions & 0 deletions src/encoding/xml/read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"io"
"reflect"
"runtime"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -1109,3 +1110,19 @@ func TestCVE202228131(t *testing.T) {
t.Fatalf("Unmarshal unexpected error: got %q, want %q", err, errExeceededMaxUnmarshalDepth)
}
}

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)
}

0 comments on commit 08c46ed

Please sign in to comment.