diff --git a/tlv/stream.go b/tlv/stream.go index 4df70af4..159301fd 100644 --- a/tlv/stream.go +++ b/tlv/stream.go @@ -6,10 +6,14 @@ import ( "io" "io/ioutil" "math" - - "github.com/lightningnetwork/lnd/lnwire" ) +// MaxRecordSize is the maximum size of a particular record that will be parsed +// by a stream decoder. This value is currently chosen to the be equal to the +// maximum message size permitted by BOLT 1, as no record should be bigger than +// an entire message. +const MaxRecordSize = 65535 // 65KB + // ErrStreamNotCanonical signals that a decoded stream does not contain records // sorting by monotonically-increasing type. var ErrStreamNotCanonical = errors.New("tlv stream is not canonical") @@ -189,7 +193,11 @@ func (s *Stream) Decode(r io.Reader) error { return err } - if length > lnwire.MaxMessagePayload { + // Place a soft limit on the size of a sane record, which + // prevents malicious encoders from causing us to allocate an + // unbounded amount of memory when decoding variable-sized + // fields. + if length > MaxRecordSize { return ErrRecordTooLarge } diff --git a/tlv/tlv_test.go b/tlv/tlv_test.go index c3b996fe..13ef2468 100644 --- a/tlv/tlv_test.go +++ b/tlv/tlv_test.go @@ -49,6 +49,8 @@ type N1 struct { nodeAmts nodeAmts cltvDelta uint16 + alias []byte + stream *tlv.Stream } @@ -66,6 +68,7 @@ func NewN1() *N1 { tlv.MakePrimitiveRecord(2, &n.scid), tlv.MakeStaticRecord(3, &n.nodeAmts, 49, ENodeAmts, DNodeAmts), tlv.MakePrimitiveRecord(254, &n.cltvDelta), + tlv.MakePrimitiveRecord(401, &n.alias), ) return n @@ -396,6 +399,12 @@ var tlvDecodingFailureTests = []struct { bytes: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00}, expErr: tlv.ErrStreamNotCanonical, }, + { + name: "absurd record length", + bytes: []byte{0xfd, 0x01, 0x91, 0xfe, 0xff, 0xff, 0xff, 0xff}, + expErr: tlv.ErrRecordTooLarge, + skipN2: true, + }, } // TestTLVDecodingSuccess asserts that the TLV parser fails to decode invalid