From 7a73f32725ff8b13a4cca703972fa76e598f4436 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9my=20Oudompheng?= Date: Thu, 30 Jan 2014 07:54:57 +0100 Subject: [PATCH] encoding/gob: fix two crashes on corrupted data. Fixes #6323. LGTM=r R=r CC=golang-codereviews https://golang.org/cl/56870043 --- src/pkg/encoding/gob/codec_test.go | 56 +++++++++++++++++++++++++--- src/pkg/encoding/gob/decode.go | 6 ++- src/pkg/encoding/gob/encoder_test.go | 2 + 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/pkg/encoding/gob/codec_test.go b/src/pkg/encoding/gob/codec_test.go index b40f78360c..fa57f3761d 100644 --- a/src/pkg/encoding/gob/codec_test.go +++ b/src/pkg/encoding/gob/codec_test.go @@ -1364,11 +1364,7 @@ type DT struct { S []string } -func TestDebugStruct(t *testing.T) { - if debugFunc == nil { - return - } - Register(OnTheFly{}) +func newDT() DT { var dt DT dt.A = 17 dt.B = "hello" @@ -1379,6 +1375,15 @@ func TestDebugStruct(t *testing.T) { dt.M = map[string]int{"one": 1, "two": 2} dt.T = [3]int{11, 22, 33} dt.S = []string{"hi", "joe"} + return dt +} + +func TestDebugStruct(t *testing.T) { + if debugFunc == nil { + return + } + Register(OnTheFly{}) + dt := newDT() b := new(bytes.Buffer) err := NewEncoder(b).Encode(dt) if err != nil { @@ -1458,3 +1463,44 @@ func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) { } } } + +// TestFuzzOneByte tries to decode corrupted input sequences +// and checks that no panic occurs. +func TestFuzzOneByte(t *testing.T) { + buf := new(bytes.Buffer) + Register(OnTheFly{}) + dt := newDT() + if err := NewEncoder(buf).Encode(dt); err != nil { + t.Fatal(err) + } + s := buf.String() + + indices := make([]int, 0, len(s)) + for i := 0; i < len(s); i++ { + switch i { + case 14, 167, 231, 265: // a slice length, corruptions are not handled yet. + continue + } + indices = append(indices, i) + } + if testing.Short() { + indices = []int{1, 111, 178} // known fixed panics + } + for _, i := range indices { + for j := 0; j < 256; j += 3 { + b := []byte(s) + b[i] ^= byte(j) + var e DT + func() { + defer func() { + if p := recover(); p != nil { + t.Errorf("crash for b[%d] ^= 0x%x", i, j) + panic(p) + } + }() + err := NewDecoder(bytes.NewReader(b)).Decode(&e) + _ = err + }() + } + } +} diff --git a/src/pkg/encoding/gob/decode.go b/src/pkg/encoding/gob/decode.go index 3037a581b3..aa186a582e 100644 --- a/src/pkg/encoding/gob/decode.go +++ b/src/pkg/encoding/gob/decode.go @@ -701,6 +701,9 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p un if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types errorf("invalid type name length %d", nr) } + if nr > uint64(state.b.Len()) { + errorf("invalid type name length %d: exceeds input size", nr) + } b := make([]byte, nr) state.b.Read(b) name := string(b) @@ -1237,7 +1240,8 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) { } engine := *enginePtr if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 { - if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 { + if engine.numInstr == 0 && st.NumField() > 0 && + dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 { name := base.Name() errorf("type mismatch: no fields matched compiling decoder for %s", name) } diff --git a/src/pkg/encoding/gob/encoder_test.go b/src/pkg/encoding/gob/encoder_test.go index 299a19914a..6445ce1002 100644 --- a/src/pkg/encoding/gob/encoder_test.go +++ b/src/pkg/encoding/gob/encoder_test.go @@ -129,6 +129,8 @@ func TestBadData(t *testing.T) { corruptDataCheck("", io.EOF, t) corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t) corruptDataCheck("\x03now is the time for all good men", errBadType, t) + // issue 6323. + corruptDataCheck("\x04\x24foo", errRange, t) } // Types not supported at top level by the Encoder. -- 2.48.1