From 40cba14b2608da2a4fc8d64c5e8412e9670f38e2 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Wed, 5 Feb 2020 10:12:40 -0800 Subject: [PATCH] internal/impl: fix for lazy decoding of groups Bit of a weird case in why this wasn't caught by tests: When validating extension groups, we were validating an empty buffer rather than the message content. For groups, this validation always fails due to a lack of a group end tag. We'd then skip lazy decoding of the extension field and proceed with eager decoding, which would behave correctly. Change extension validation to report an error immediately on an invalid result from the validator, which is both safe (assuming we trust the validator) and would have caught this problem (by failing to decode the extension field, rather than silently failing to eager decoding). Change-Id: Id6c2d21fb687062bc74d9eb93760a1c24a6fe883 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/217767 Reviewed-by: Joe Tsai --- internal/impl/decode.go | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/internal/impl/decode.go b/internal/impl/decode.go index 3155bc58..0fffad34 100644 --- a/internal/impl/decode.go +++ b/internal/impl/decode.go @@ -196,10 +196,17 @@ func (mi *MessageInfo) unmarshalExtension(b []byte, num wire.Number, wtyp wire.T } if flags.LazyUnmarshalExtensions { if opts.IsDefault() && x.canLazy(xt) { - if out, ok := skipExtension(b, xi, num, wtyp, opts); ok && out.initialized { - x.appendLazyBytes(xt, xi, num, wtyp, b[:out.n]) - exts[int32(num)] = x - return out, nil + out, valid := skipExtension(b, xi, num, wtyp, opts) + switch valid { + case ValidationValid: + if out.initialized { + x.appendLazyBytes(xt, xi, num, wtyp, b[:out.n]) + exts[int32(num)] = x + return out, nil + } + case ValidationInvalid: + return out, errors.New("invalid wire format") + case ValidationUnknown: } } } @@ -222,31 +229,30 @@ func (mi *MessageInfo) unmarshalExtension(b []byte, num wire.Number, wtyp wire.T return out, nil } -func skipExtension(b []byte, xi *extensionFieldInfo, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (out unmarshalOutput, ok bool) { +func skipExtension(b []byte, xi *extensionFieldInfo, num wire.Number, wtyp wire.Type, opts unmarshalOptions) (out unmarshalOutput, _ ValidationStatus) { if xi.validation.mi == nil { - return out, false + return out, ValidationUnknown } xi.validation.mi.init() - var v []byte switch xi.validation.typ { case validationTypeMessage: if wtyp != wire.BytesType { - return out, false + return out, ValidationUnknown } v, n := wire.ConsumeBytes(b) if n < 0 { - return out, false + return out, ValidationUnknown } out, st := xi.validation.mi.validate(v, 0, opts) out.n = n - return out, st == ValidationValid + return out, st case validationTypeGroup: if wtyp != wire.StartGroupType { - return out, false + return out, ValidationUnknown } - out, st := xi.validation.mi.validate(v, num, opts) - return out, st == ValidationValid + out, st := xi.validation.mi.validate(b, num, opts) + return out, st default: - return out, false + return out, ValidationUnknown } }