diff --git a/docs/release-notes/release-notes-0.20.0.md b/docs/release-notes/release-notes-0.20.0.md index 94bcd18a6..85b5f7b7e 100644 --- a/docs/release-notes/release-notes-0.20.0.md +++ b/docs/release-notes/release-notes-0.20.0.md @@ -34,7 +34,8 @@ * Graph Store SQL implementation and migration project: * Introduce an [abstract graph store](https://github.com/lightningnetwork/lnd/pull/9791) interface. - + * Start [validating](https://github.com/lightningnetwork/lnd/pull/9787) that + byte blobs at the end of gossip messages are valid TLV streams. ## RPC Updates diff --git a/lnwire/channel_announcement.go b/lnwire/channel_announcement.go index 0a3989abb..05161cca8 100644 --- a/lnwire/channel_announcement.go +++ b/lnwire/channel_announcement.go @@ -70,8 +70,8 @@ var _ SizeableMessage = (*ChannelAnnouncement1)(nil) // io.Reader observing the specified protocol version. // // This is part of the lnwire.Message interface. -func (a *ChannelAnnouncement1) Decode(r io.Reader, pver uint32) error { - return ReadElements(r, +func (a *ChannelAnnouncement1) Decode(r io.Reader, _ uint32) error { + err := ReadElements(r, &a.NodeSig1, &a.NodeSig2, &a.BitcoinSig1, @@ -85,6 +85,11 @@ func (a *ChannelAnnouncement1) Decode(r io.Reader, pver uint32) error { &a.BitcoinKey2, &a.ExtraOpaqueData, ) + if err != nil { + return err + } + + return a.ExtraOpaqueData.ValidateTLV() } // Encode serializes the target ChannelAnnouncement into the passed io.Writer diff --git a/lnwire/channel_announcement_2.go b/lnwire/channel_announcement_2.go index 57b3a24b8..95af69eda 100644 --- a/lnwire/channel_announcement_2.go +++ b/lnwire/channel_announcement_2.go @@ -126,7 +126,7 @@ func (c *ChannelAnnouncement2) DecodeTLVRecords(r io.Reader) error { c.ExtraOpaqueData = tlvRecords } - return nil + return c.ExtraOpaqueData.ValidateTLV() } // Encode serializes the target AnnounceSignatures1 into the passed io.Writer diff --git a/lnwire/channel_update.go b/lnwire/channel_update.go index 88f981671..55d9d3181 100644 --- a/lnwire/channel_update.go +++ b/lnwire/channel_update.go @@ -132,7 +132,7 @@ var _ SizeableMessage = (*ChannelUpdate1)(nil) // io.Reader observing the specified protocol version. // // This is part of the lnwire.Message interface. -func (a *ChannelUpdate1) Decode(r io.Reader, pver uint32) error { +func (a *ChannelUpdate1) Decode(r io.Reader, _ uint32) error { err := ReadElements(r, &a.Signature, a.ChainHash[:], @@ -156,7 +156,12 @@ func (a *ChannelUpdate1) Decode(r io.Reader, pver uint32) error { } } - return a.ExtraOpaqueData.Decode(r) + err = a.ExtraOpaqueData.Decode(r) + if err != nil { + return err + } + + return a.ExtraOpaqueData.ValidateTLV() } // Encode serializes the target ChannelUpdate into the passed io.Writer diff --git a/lnwire/channel_update_2.go b/lnwire/channel_update_2.go index 56f7edf6b..343af6b1e 100644 --- a/lnwire/channel_update_2.go +++ b/lnwire/channel_update_2.go @@ -154,7 +154,7 @@ func (c *ChannelUpdate2) DecodeTLVRecords(r io.Reader) error { c.ExtraOpaqueData = tlvRecords } - return nil + return c.ExtraOpaqueData.ValidateTLV() } // Encode serializes the target ChannelUpdate2 into the passed io.Writer diff --git a/lnwire/extra_bytes.go b/lnwire/extra_bytes.go index 4681426cb..9530e06e8 100644 --- a/lnwire/extra_bytes.go +++ b/lnwire/extra_bytes.go @@ -63,6 +63,28 @@ func (e *ExtraOpaqueData) Decode(r io.Reader) error { return nil } +// ValidateTLV checks that the raw bytes that make up the ExtraOpaqueData +// instance are a valid TLV stream. +func (e *ExtraOpaqueData) ValidateTLV() error { + // There is nothing to validate if the ExtraOpaqueData is nil or empty. + if e == nil || len(*e) == 0 { + return nil + } + + tlvStream, err := tlv.NewStream() + if err != nil { + return err + } + + // Ensure that the TLV stream is valid by attempting to decode it. + _, err = tlvStream.DecodeWithParsedTypesP2P(bytes.NewReader(*e)) + if err != nil { + return fmt.Errorf("invalid TLV stream: %w: %v", err, *e) + } + + return nil +} + // PackRecords attempts to encode the set of tlv records into the target // ExtraOpaqueData instance. The records will be encoded as a raw TLV stream // and stored within the backing slice pointer. diff --git a/lnwire/node_announcement.go b/lnwire/node_announcement.go index 5ba2d7a1d..d3502a7d9 100644 --- a/lnwire/node_announcement.go +++ b/lnwire/node_announcement.go @@ -112,8 +112,8 @@ var _ SizeableMessage = (*NodeAnnouncement)(nil) // io.Reader observing the specified protocol version. // // This is part of the lnwire.Message interface. -func (a *NodeAnnouncement) Decode(r io.Reader, pver uint32) error { - return ReadElements(r, +func (a *NodeAnnouncement) Decode(r io.Reader, _ uint32) error { + err := ReadElements(r, &a.Signature, &a.Features, &a.Timestamp, @@ -123,6 +123,11 @@ func (a *NodeAnnouncement) Decode(r io.Reader, pver uint32) error { &a.Addresses, &a.ExtraOpaqueData, ) + if err != nil { + return err + } + + return a.ExtraOpaqueData.ValidateTLV() } // Encode serializes the target NodeAnnouncement into the passed io.Writer