Skip to content

Commit e0a01fd

Browse files
committed
Add more bounds checking based on fuzzing results
1 parent f6c93ff commit e0a01fd

File tree

2 files changed

+55
-19
lines changed

2 files changed

+55
-19
lines changed

decoder.go

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,34 +34,43 @@ const (
3434
)
3535

3636
func (d *decoder) decode(offset uint, result reflect.Value) (uint, error) {
37-
typeNum, size, newOffset := d.decodeCtrlData(offset)
37+
typeNum, size, newOffset, err := d.decodeCtrlData(offset)
38+
if err != nil {
39+
return 0, err
40+
}
3841

3942
if typeNum != _Pointer && result.Kind() == reflect.Uintptr {
4043
result.Set(reflect.ValueOf(uintptr(offset)))
41-
return d.nextValueOffset(offset, 1), nil
44+
return d.nextValueOffset(offset, 1)
4245
}
4346
return d.decodeFromType(typeNum, size, newOffset, result)
4447
}
4548

46-
func (d *decoder) decodeCtrlData(offset uint) (dataType, uint, uint) {
49+
func (d *decoder) decodeCtrlData(offset uint) (dataType, uint, uint, error) {
4750
newOffset := offset + 1
51+
if offset >= uint(len(d.buffer)) {
52+
return 0, 0, 0, newOffsetError()
53+
}
4854
ctrlByte := d.buffer[offset]
4955

5056
typeNum := dataType(ctrlByte >> 5)
5157
if typeNum == _Extended {
58+
if newOffset >= uint(len(d.buffer)) {
59+
return 0, 0, 0, newOffsetError()
60+
}
5261
typeNum = dataType(d.buffer[newOffset] + 7)
5362
newOffset++
5463
}
5564

5665
var size uint
57-
size, newOffset = d.sizeFromCtrlByte(ctrlByte, newOffset, typeNum)
58-
return typeNum, size, newOffset
66+
size, newOffset, err := d.sizeFromCtrlByte(ctrlByte, newOffset, typeNum)
67+
return typeNum, size, newOffset, err
5968
}
6069

61-
func (d *decoder) sizeFromCtrlByte(ctrlByte byte, offset uint, typeNum dataType) (uint, uint) {
70+
func (d *decoder) sizeFromCtrlByte(ctrlByte byte, offset uint, typeNum dataType) (uint, uint, error) {
6271
size := uint(ctrlByte & 0x1f)
6372
if typeNum == _Extended {
64-
return size, offset
73+
return size, offset, nil
6574
}
6675

6776
var bytesToRead uint
@@ -70,6 +79,9 @@ func (d *decoder) sizeFromCtrlByte(ctrlByte byte, offset uint, typeNum dataType)
7079
}
7180

7281
newOffset := offset + bytesToRead
82+
if newOffset > uint(len(d.buffer)) {
83+
return 0, 0, newOffsetError()
84+
}
7385
sizeBytes := d.buffer[offset:newOffset]
7486

7587
switch {
@@ -80,15 +92,29 @@ func (d *decoder) sizeFromCtrlByte(ctrlByte byte, offset uint, typeNum dataType)
8092
case size > 30:
8193
size = uint(uintFromBytes(0, sizeBytes)) + 65821
8294
}
83-
return size, newOffset
95+
return size, newOffset, nil
8496
}
8597

8698
func (d *decoder) decodeFromType(dtype dataType, size uint, offset uint, result reflect.Value) (uint, error) {
8799
result = d.indirect(result)
88100

101+
// For these types, size has a special meaning
89102
switch dtype {
90103
case _Bool:
91104
return d.unmarshalBool(size, offset, result)
105+
case _Map:
106+
return d.unmarshalMap(size, offset, result)
107+
case _Pointer:
108+
return d.unmarshalPointer(size, offset, result)
109+
case _Slice:
110+
return d.unmarshalSlice(size, offset, result)
111+
}
112+
113+
// For the remaining types, size is the byte size
114+
if offset+size > uint(len(d.buffer)) {
115+
return 0, newOffsetError()
116+
}
117+
switch dtype {
92118
case _Bytes:
93119
return d.unmarshalBytes(size, offset, result)
94120
case _Float32:
@@ -97,12 +123,6 @@ func (d *decoder) decodeFromType(dtype dataType, size uint, offset uint, result
97123
return d.unmarshalFloat64(size, offset, result)
98124
case _Int32:
99125
return d.unmarshalInt32(size, offset, result)
100-
case _Map:
101-
return d.unmarshalMap(size, offset, result)
102-
case _Pointer:
103-
return d.unmarshalPointer(size, offset, result)
104-
case _Slice:
105-
return d.unmarshalSlice(size, offset, result)
106126
case _String:
107127
return d.unmarshalString(size, offset, result)
108128
case _Uint16:
@@ -544,7 +564,10 @@ func (d *decoder) decodeStruct(size uint, offset uint, result reflect.Value) (ui
544564
// optimization: https://github.com/golang/go/issues/3512
545565
j, ok := fields.namedFields[string(key)]
546566
if !ok {
547-
offset = d.nextValueOffset(offset, 1)
567+
offset, err = d.nextValueOffset(offset, 1)
568+
if err != nil {
569+
return 0, err
570+
}
548571
continue
549572
}
550573

@@ -584,7 +607,10 @@ func uintFromBytes(prefix uint64, uintBytes []byte) uint64 {
584607
// copying the bytes when decoding a struct. Previously, we achieved this by
585608
// using unsafe.
586609
func (d *decoder) decodeKey(offset uint) ([]byte, uint, error) {
587-
typeNum, size, dataOffset := d.decodeCtrlData(offset)
610+
typeNum, size, dataOffset, err := d.decodeCtrlData(offset)
611+
if err != nil {
612+
return nil, 0, err
613+
}
588614
if typeNum == _Pointer {
589615
pointer, ptrOffset := d.decodePointer(size, dataOffset)
590616
key, _, err := d.decodeKey(pointer)
@@ -594,17 +620,23 @@ func (d *decoder) decodeKey(offset uint) ([]byte, uint, error) {
594620
return nil, 0, newInvalidDatabaseError("unexpected type when decoding string: %v", typeNum)
595621
}
596622
newOffset := dataOffset + size
623+
if newOffset > uint(len(d.buffer)) {
624+
return nil, 0, newOffsetError()
625+
}
597626
return d.buffer[dataOffset:newOffset], newOffset, nil
598627
}
599628

600629
// This function is used to skip ahead to the next value without decoding
601630
// the one at the offset passed in. The size bits have different meanings for
602631
// different data types
603-
func (d *decoder) nextValueOffset(offset uint, numberToSkip uint) uint {
632+
func (d *decoder) nextValueOffset(offset uint, numberToSkip uint) (uint, error) {
604633
if numberToSkip == 0 {
605-
return offset
634+
return offset, nil
635+
}
636+
typeNum, size, offset, err := d.decodeCtrlData(offset)
637+
if err != nil {
638+
return 0, err
606639
}
607-
typeNum, size, offset := d.decodeCtrlData(offset)
608640
switch typeNum {
609641
case _Pointer:
610642
_, offset = d.decodePointer(size, offset)

errors.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ type InvalidDatabaseError struct {
1111
message string
1212
}
1313

14+
func newOffsetError() InvalidDatabaseError {
15+
return InvalidDatabaseError{"unexpected end of database"}
16+
}
17+
1418
func newInvalidDatabaseError(format string, args ...interface{}) InvalidDatabaseError {
1519
return InvalidDatabaseError{fmt.Sprintf(format, args...)}
1620
}

0 commit comments

Comments
 (0)