Skip to content

Commit f01a588

Browse files
committedMar 5, 2024·
encoding/protojson, internal/encoding/json: handle missing object values
In internal/encoding/json, report an error when encountering a } when we are expecting an object field value. For example, the input `{"":}` now correctly results in an error at the closing } token. In encoding/protojson, check for an unexpected EOF token in skipJSONValue. This is redundant with the check in internal/encoding/json, but adds a bit more defense against any other similar bugs that might exist. Fixes CVE-2024-24786 Change-Id: I03d52512acb5091c8549e31ca74541d57e56c99d Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/569356 TryBot-Bypass: Damien Neil <dneil@google.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Commit-Queue: Damien Neil <dneil@google.com>
1 parent 235ef28 commit f01a588

File tree

4 files changed

+37
-1
lines changed

4 files changed

+37
-1
lines changed
 

‎encoding/protojson/decode_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -2770,6 +2770,23 @@ func TestUnmarshal(t *testing.T) {
27702770
inputText: `{"foo":{"bar":[{"baz":[{}]]}}`,
27712771
umo: protojson.UnmarshalOptions{RecursionLimit: 5, DiscardUnknown: true},
27722772
wantErr: "exceeded max recursion depth",
2773+
}, {
2774+
desc: "Object missing value: no DiscardUnknown",
2775+
inputMessage: &testpb.TestAllTypes{},
2776+
inputText: `{"":}`,
2777+
umo: protojson.UnmarshalOptions{RecursionLimit: 5, DiscardUnknown: false},
2778+
wantErr: `(line 1:2): unknown field ""`,
2779+
}, {
2780+
desc: "Object missing value: DiscardUnknown",
2781+
inputMessage: &testpb.TestAllTypes{},
2782+
inputText: `{"":}`,
2783+
umo: protojson.UnmarshalOptions{RecursionLimit: 5, DiscardUnknown: true},
2784+
wantErr: `(line 1:5): unexpected token`,
2785+
}, {
2786+
desc: "Object missing value: Any",
2787+
inputMessage: &anypb.Any{},
2788+
inputText: `{"":}`,
2789+
wantErr: `(line 1:5): unexpected token`,
27732790
}}
27742791

27752792
for _, tt := range tests {

‎encoding/protojson/well_known_types.go

+4
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ func (d decoder) skipJSONValue() error {
322322
if open > d.opts.RecursionLimit {
323323
return errors.New("exceeded max recursion depth")
324324
}
325+
case json.EOF:
326+
// This can only happen if there's a bug in Decoder.Read.
327+
// Avoid an infinite loop if this does happen.
328+
return errors.New("unexpected EOF")
325329
}
326330
if open == 0 {
327331
return nil

‎internal/encoding/json/decode.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ func (d *Decoder) Read() (Token, error) {
121121

122122
case ObjectClose:
123123
if len(d.openStack) == 0 ||
124-
d.lastToken.kind == comma ||
124+
d.lastToken.kind&(Name|comma) != 0 ||
125125
d.openStack[len(d.openStack)-1] != ObjectOpen {
126126
return Token{}, d.newSyntaxError(tok.pos, unexpectedFmt, tok.RawString())
127127
}

‎internal/encoding/json/decode_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,21 @@ func TestDecoder(t *testing.T) {
11931193
{E: errEOF},
11941194
},
11951195
},
1196+
{
1197+
in: `{""`,
1198+
want: []R{
1199+
{V: ObjectOpen},
1200+
{E: errEOF},
1201+
},
1202+
},
1203+
{
1204+
in: `{"":`,
1205+
want: []R{
1206+
{V: ObjectOpen},
1207+
{V: Name{""}},
1208+
{E: errEOF},
1209+
},
1210+
},
11961211
{
11971212
in: `{"34":"89",}`,
11981213
want: []R{

0 commit comments

Comments
 (0)
Please sign in to comment.