Commit 1052d678 authored by Luke Champine's avatar Luke Champine

enforce maximum object size

parent f1430fb4
......@@ -13,12 +13,14 @@ import (
)
const (
MaxDecodeSize = 12e6 // 12 MB
MaxObjectSize = 12e6 // 12 MB
MaxSliceSize = 5e6 // 5 MB
)
var (
errBadPointer = errors.New("cannot decode into invalid pointer")
errBadPointer = errors.New("cannot decode into invalid pointer")
ErrObjectTooLarge = errors.New("encoded object exceeds size limit")
ErrSliceTooLarge = errors.New("encoded slice is too large")
)
type (
......@@ -185,8 +187,8 @@ type Decoder struct {
func (d *Decoder) Read(p []byte) (int, error) {
n, err := d.r.Read(p)
// enforce an absolute maximum size limit
if d.n += n; d.n > MaxDecodeSize {
panic("encoded type exceeds size limit")
if d.n += n; d.n > MaxObjectSize {
panic(ErrObjectTooLarge)
}
return n, err
}
......@@ -233,8 +235,8 @@ func (d *Decoder) readN(n int) []byte {
if len(b) != n {
panic(io.ErrUnexpectedEOF)
}
if d.n += n; d.n > MaxDecodeSize {
panic("encoded type exceeds size limit")
if d.n += n; d.n > MaxObjectSize {
panic(ErrObjectTooLarge)
}
return b
}
......@@ -297,7 +299,7 @@ func (d *Decoder) decode(val reflect.Value) {
// sanity-check the sliceLen, otherwise you can crash a peer by making
// them allocate a massive slice
if sliceLen > 1<<31-1 || sliceLen*uint64(val.Type().Elem().Size()) > MaxSliceSize {
panic("slice is too large")
panic(ErrSliceTooLarge)
} else if sliceLen == 0 {
return
}
......
......@@ -146,22 +146,22 @@ func TestDecode(t *testing.T) {
t.Error("expected unknown type error, got", err)
}
// big slice (larger than maxSliceLen)
err = Unmarshal(EncUint64(maxSliceLen+1), new([]byte))
if err == nil || err.Error() != "could not decode type []uint8: slice is too large" {
// big slice (larger than MaxSliceSize)
err = Unmarshal(EncUint64(MaxSliceSize+1), new([]byte))
if err == nil || err.Error() != "could not decode type []uint8: encoded slice is too large" {
t.Error("expected large slice error, got", err)
}
// massive slice (larger than MaxInt32)
err = Unmarshal(EncUint64(1<<32), new([]byte))
if err == nil || err.Error() != "could not decode type []uint8: slice is too large" {
if err == nil || err.Error() != "could not decode type []uint8: encoded slice is too large" {
t.Error("expected large slice error, got", err)
}
// many small slices (total larger than maxDecodeLen)
bigSlice := strings.Split(strings.Repeat("0123456789abcdefghijklmnopqrstuvwxyz", (maxSliceLen/16)-1), "0")
bigSlice := strings.Split(strings.Repeat("0123456789abcdefghijklmnopqrstuvwxyz", (MaxSliceSize/16)-1), "0")
err = Unmarshal(Marshal(bigSlice), new([]string))
if err == nil || err.Error() != "could not decode type []string: encoded type exceeds size limit" {
if err == nil || err.Error() != "could not decode type []string: encoded object exceeds size limit" {
t.Error("expected size limit error, got", err)
}
......
......@@ -4,7 +4,6 @@ import (
"bytes"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
......@@ -37,6 +36,7 @@ type decHelper struct {
io.Reader
buf [8]byte
err error
n int // total number of bytes read
}
// Read implements the io.Reader interface.
......@@ -48,7 +48,11 @@ func (d *decHelper) Read(p []byte) (int, error) {
if d.err == nil {
d.err = err
}
return n, err
d.n += n
if d.n > encoding.MaxObjectSize {
d.err = encoding.ErrObjectTooLarge
}
return n, d.err
}
// ReadFull is shorthand for io.ReadFull(d, p).
......@@ -86,8 +90,8 @@ func (d *decHelper) NextUint64() uint64 {
// encoding.MaxSliceSize, NextPrefix returns 0 and sets d.Err().
func (d *decHelper) NextPrefix(elemSize uintptr) uint64 {
n := d.NextUint64()
if n > sliceLen > 1<<31-1 || n*uint64(elemSize) > encoding.MaxSliceSize {
d.err = errors.New("slice is too large")
if n > 1<<31-1 || n*uint64(elemSize) > encoding.MaxSliceSize {
d.err = encoding.ErrSliceTooLarge
return 0
}
return n
......
......@@ -139,6 +139,9 @@ func TestBlockEncoding(t *testing.T) {
// TestTooLargeDecoder tests that the decoder catches allocations that are too
// large.
func TestTooLargeDecoder(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
enc := encoding.Marshal(Block{})
// change number of transactions to large number
copy(enc[len(enc)-8:], encoding.EncUint64(^uint64(0)))
......@@ -147,6 +150,19 @@ func TestTooLargeDecoder(t *testing.T) {
if err == nil {
t.Fatal("expected error, got nil")
}
var arb [][]byte
for i := 0; i < 4; i++ {
arb = append(arb, make([]byte, encoding.MaxSliceSize-1))
}
block.Transactions = []Transaction{{
ArbitraryData: arb,
}}
enc = encoding.Marshal(block)
err = encoding.Unmarshal(enc, &block)
if err == nil {
t.Fatal("expected error, got nil")
}
}
// TestCurrencyMarshalJSON probes the MarshalJSON and UnmarshalJSON functions
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment