]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.17] encoding/xml: use iterative Skip, rather than recursive
authorRoland Shoemaker <roland@golang.org>
Tue, 29 Mar 2022 01:41:26 +0000 (18:41 -0700)
committerMichael Knyszek <mknyszek@google.com>
Tue, 12 Jul 2022 15:20:21 +0000 (15:20 +0000)
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>

src/encoding/xml/read.go
src/encoding/xml/read_test.go

index ef5df3f7f6aecca09302cb07050711d8b79b51da..e9f9d2efa9cc2ba23a3addf3564c7f253d35e2bf 100644 (file)
@@ -732,12 +732,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 {
@@ -745,11 +745,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--
                }
        }
 }
index 8c2e70fa22ee68e06956dae82a3fafa1c2b779a1..4ccab3d0106ebc4b4df62fc3010c9747ad303955 100644 (file)
@@ -5,8 +5,10 @@
 package xml
 
 import (
+       "bytes"
        "io"
        "reflect"
+       "runtime"
        "strings"
        "testing"
        "time"
@@ -1079,3 +1081,19 @@ 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)
+}