diff options
author | Michael Anthony Knyszek <mknyszek@google.com> | 2022-07-13 15:35:44 +0000 |
---|---|---|
committer | Michael Anthony Knyszek <mknyszek@google.com> | 2022-07-13 15:35:44 +0000 |
commit | 7d5078e3bf2d865526e8ec2d211f61b2fac2936f (patch) | |
tree | 8f434be7d8e2ec1e3e5783f57deacdec41d454d9 /src/encoding/xml/read.go | |
parent | 4658e6e324a85b0076f66acdab77799ffa9ac7bb (diff) | |
parent | 1ed3c127daceaffb9aadc806ba60f0b51b47421b (diff) | |
download | go-7d5078e3bf2d865526e8ec2d211f61b2fac2936f.tar.gz go-7d5078e3bf2d865526e8ec2d211f61b2fac2936f.zip |
[dev.boringcrypto.go1.17] all: merge go1.17.12 into dev.boringcrypto.go1.17
Change-Id: I652dbbb5721fa0c7be09be34b9ac1a987c331f6d
Diffstat (limited to 'src/encoding/xml/read.go')
-rw-r--r-- | src/encoding/xml/read.go | 42 |
1 files changed, 27 insertions, 15 deletions
diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go index ef5df3f7f6..c77579880c 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 } @@ -732,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 { @@ -745,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-- } } } |