Skip to content

Commit 2092294

Browse files
rolandshoemakergopherbot
authored andcommitted
[release-branch.go1.22] encoding/gob: cover missed cases when checking ignore depth
This change makes sure that we are properly checking the ignored field recursion depth in decIgnoreOpFor consistently. This prevents stack exhaustion when attempting to decode a message that contains an extremely deeply nested struct which is ignored. Thanks to Md Sakib Anwar of The Ohio State University ([email protected]) for reporting this issue. Updates #69139 Fixes #69144 Fixes CVE-2024-34156 Change-Id: Iacce06be95a5892b3064f1c40fcba2e2567862d6 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1440 Reviewed-by: Russ Cox <[email protected]> Reviewed-by: Damien Neil <[email protected]> (cherry picked from commit f0a11f9b3aaa362cb1d05e095e3c8d421d4f087f) Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1580 Reviewed-by: Tatiana Bradley <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/go/+/611182 TryBot-Bypass: Dmitri Shuralyov <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Auto-Submit: Dmitri Shuralyov <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent b232596 commit 2092294

File tree

3 files changed

+27
-8
lines changed

3 files changed

+27
-8
lines changed

src/encoding/gob/decode.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -911,8 +911,11 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
911911
var maxIgnoreNestingDepth = 10000
912912

913913
// decIgnoreOpFor returns the decoding op for a field that has no destination.
914-
func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp, depth int) *decOp {
915-
if depth > maxIgnoreNestingDepth {
914+
func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp {
915+
// Track how deep we've recursed trying to skip nested ignored fields.
916+
dec.ignoreDepth++
917+
defer func() { dec.ignoreDepth-- }()
918+
if dec.ignoreDepth > maxIgnoreNestingDepth {
916919
error_(errors.New("invalid nesting depth"))
917920
}
918921
// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
@@ -938,23 +941,23 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp,
938941
errorf("bad data: undefined type %s", wireId.string())
939942
case wire.ArrayT != nil:
940943
elemId := wire.ArrayT.Elem
941-
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
944+
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
942945
op = func(i *decInstr, state *decoderState, value reflect.Value) {
943946
state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len)
944947
}
945948

946949
case wire.MapT != nil:
947950
keyId := dec.wireType[wireId].MapT.Key
948951
elemId := dec.wireType[wireId].MapT.Elem
949-
keyOp := dec.decIgnoreOpFor(keyId, inProgress, depth+1)
950-
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
952+
keyOp := dec.decIgnoreOpFor(keyId, inProgress)
953+
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
951954
op = func(i *decInstr, state *decoderState, value reflect.Value) {
952955
state.dec.ignoreMap(state, *keyOp, *elemOp)
953956
}
954957

955958
case wire.SliceT != nil:
956959
elemId := wire.SliceT.Elem
957-
elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1)
960+
elemOp := dec.decIgnoreOpFor(elemId, inProgress)
958961
op = func(i *decInstr, state *decoderState, value reflect.Value) {
959962
state.dec.ignoreSlice(state, *elemOp)
960963
}
@@ -1115,7 +1118,7 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
11151118
func (dec *Decoder) compileIgnoreSingle(remoteId typeId) *decEngine {
11161119
engine := new(decEngine)
11171120
engine.instr = make([]decInstr, 1) // one item
1118-
op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp), 0)
1121+
op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp))
11191122
ovfl := overflow(dec.typeString(remoteId))
11201123
engine.instr[0] = decInstr{*op, 0, nil, ovfl}
11211124
engine.numInstr = 1
@@ -1160,7 +1163,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
11601163
localField, present := srt.FieldByName(wireField.Name)
11611164
// TODO(r): anonymous names
11621165
if !present || !isExported(wireField.Name) {
1163-
op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp), 0)
1166+
op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp))
11641167
engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl}
11651168
continue
11661169
}

src/encoding/gob/decoder.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ type Decoder struct {
3535
freeList *decoderState // list of free decoderStates; avoids reallocation
3636
countBuf []byte // used for decoding integers while parsing messages
3737
err error
38+
// ignoreDepth tracks the depth of recursively parsed ignored fields
39+
ignoreDepth int
3840
}
3941

4042
// NewDecoder returns a new decoder that reads from the [io.Reader].

src/encoding/gob/gobencdec_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,8 @@ func TestIgnoreDepthLimit(t *testing.T) {
806806
defer func() { maxIgnoreNestingDepth = oldNestingDepth }()
807807
b := new(bytes.Buffer)
808808
enc := NewEncoder(b)
809+
810+
// Nested slice
809811
typ := reflect.TypeFor[int]()
810812
nested := reflect.ArrayOf(1, typ)
811813
for i := 0; i < 100; i++ {
@@ -819,4 +821,16 @@ func TestIgnoreDepthLimit(t *testing.T) {
819821
if err := dec.Decode(&output); err == nil || err.Error() != expectedErr {
820822
t.Errorf("Decode didn't fail with depth limit of 100: want %q, got %q", expectedErr, err)
821823
}
824+
825+
// Nested struct
826+
nested = reflect.StructOf([]reflect.StructField{{Name: "F", Type: typ}})
827+
for i := 0; i < 100; i++ {
828+
nested = reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}})
829+
}
830+
badStruct = reflect.New(reflect.StructOf([]reflect.StructField{{Name: "F", Type: nested}}))
831+
enc.Encode(badStruct.Interface())
832+
dec = NewDecoder(b)
833+
if err := dec.Decode(&output); err == nil || err.Error() != expectedErr {
834+
t.Errorf("Decode didn't fail with depth limit of 100: want %q, got %q", expectedErr, err)
835+
}
822836
}

0 commit comments

Comments
 (0)