From 2784da13f8230c3383abb91fb35c041fcaf20107 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 8 Nov 2024 14:57:13 -0600 Subject: [PATCH 1/4] lnwire: add fuzz targets for gossip 1.75 messages Add simple decode/encode targets for AnnouncementSignatures2, ChannelAnnouncement2, and ChannelUpdate2. --- lnwire/fuzz_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index d6ec3b61b..f2c4acd1b 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -114,6 +114,17 @@ func FuzzAnnounceSignatures(f *testing.F) { }) } +func FuzzAnnounceSignatures2(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + // Prefix with MsgAnnounceSignatures2. + data = prefixWithMsgType(data, MsgAnnounceSignatures2) + + // Pass the message into our general fuzz harness for wire + // messages! + harness(t, data) + }) +} + func FuzzChannelAnnouncement(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { // Prefix with MsgChannelAnnouncement. @@ -125,6 +136,51 @@ func FuzzChannelAnnouncement(f *testing.F) { }) } +func FuzzChannelAnnouncement2(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + // Prefix with MsgChannelAnnouncement2. + data = prefixWithMsgType(data, MsgChannelAnnouncement2) + + // Because require.Equal considers nil maps and empty maps + // to be non-equal, we must manually compare Features field + // rather than using the harness. + + if len(data) > MaxSliceLength { + return + } + + r := bytes.NewReader(data) + msg, err := ReadMessage(r, 0) + if err != nil { + return + } + + // We will serialize the message into a new bytes buffer. + var b bytes.Buffer + _, err = WriteMessage(&b, msg, 0) + require.NoError(t, err) + + // Deserialize the message from the serialized bytes buffer, and + // then assert that the original message is equal to the newly + // deserialized message. + newMsg, err := ReadMessage(&b, 0) + require.NoError(t, err) + + require.IsType(t, &ChannelAnnouncement2{}, msg) + first, _ := msg.(*ChannelAnnouncement2) + require.IsType(t, &ChannelAnnouncement2{}, newMsg) + second, _ := newMsg.(*ChannelAnnouncement2) + + // We can't use require.Equal for Features, since we consider + // the empty map and nil to be equivalent. + require.True(t, first.Features.Val.Equals(&second.Features.Val)) + first.Features.Val = *NewRawFeatureVector() + second.Features.Val = *NewRawFeatureVector() + + require.Equal(t, first, second) + }) +} + func FuzzChannelReestablish(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { // Prefix with MsgChannelReestablish. @@ -147,6 +203,17 @@ func FuzzChannelUpdate(f *testing.F) { }) } +func FuzzChannelUpdate2(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + // Prefix with MsgChannelUpdate2. + data = prefixWithMsgType(data, MsgChannelUpdate2) + + // Pass the message into our general fuzz harness for wire + // messages! + harness(t, data) + }) +} + func FuzzClosingSigned(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { // Prefix with MsgClosingSigned. From b82ae51a0beb054157d25050f3b72e647232c160 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 8 Nov 2024 15:00:06 -0600 Subject: [PATCH 2/4] lnwire: add fuzz target for route blinding message Add a simple decode/encode target for the FailInvalidBlinding message. --- lnwire/fuzz_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index f2c4acd1b..75140fe59 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -995,6 +995,12 @@ func FuzzInvalidOnionPayload(f *testing.F) { }) } +func FuzzFailInvalidBlinding(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + onionFailureHarness(t, data, CodeInvalidBlinding) + }) +} + func FuzzClosingSig(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { // Prefix with ClosingSig. From f1b7d52308460da1396ec65b08041b340f7e68b2 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 8 Nov 2024 15:01:48 -0600 Subject: [PATCH 3/4] lnwire: add fuzz target for Schnorr sig conversion Analogous to FuzzConvertFixedSignature but for Schnorr signatures. --- lnwire/fuzz_test.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index 75140fe59..5809a7e16 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -797,6 +797,37 @@ func FuzzConvertFixedSignature(f *testing.F) { }) } +// FuzzConvertFixedSchnorrSignature tests that conversion of fixed 64-byte +// Schnorr signatures to and from the btcec format does not panic or mutate the +// signatures. +func FuzzConvertFixedSchnorrSignature(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + var sig Sig + if len(data) > len(sig.bytes[:]) { + return + } + copy(sig.bytes[:], data) + sig.ForceSchnorr() + + btcecSig, err := sig.ToSignature() + if err != nil { + return + } + + sig2, err := NewSigFromSignature(btcecSig) + require.NoError(t, err, "failed to parse signature") + + btcecSig2, err := sig2.ToSignature() + require.NoError( + t, err, "failed to reconvert signature to btcec format", + ) + + btcecBytes := btcecSig.Serialize() + btcecBytes2 := btcecSig2.Serialize() + require.Equal(t, btcecBytes, btcecBytes2, "signature mismatch") + }) +} + // prefixWithFailCode adds a failure code prefix to data. func prefixWithFailCode(data []byte, code FailCode) []byte { var codeBytes [2]byte From 4f7267ecea27f3a94c3445b9c96de9bcbf80ce33 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Fri, 8 Nov 2024 15:03:30 -0600 Subject: [PATCH 4/4] lnwire: add fuzz target for Fee TLV The new Fee TLV is not included in any other messages within the lnwire package, so it currently has no fuzzing coverage. This fuzz target directly tests the encoding/decoding of the TLV to get some coverage. --- lnwire/fuzz_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index 5809a7e16..58f790aaf 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -1053,3 +1053,30 @@ func FuzzClosingComplete(f *testing.F) { harness(t, data) }) } + +// FuzzFee tests that decoding and re-encoding a Fee TLV does not mutate it. +func FuzzFee(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + if len(data) > 8 { + return + } + + var fee Fee + var buf [8]byte + r := bytes.NewReader(data) + + if err := feeDecoder(r, &fee, &buf, 8); err != nil { + return + } + + var b bytes.Buffer + require.NoError(t, feeEncoder(&b, &fee, &buf)) + + // Use bytes.Equal instead of require.Equal so that nil and + // empty slices are considered equal. + require.True( + t, bytes.Equal(data, b.Bytes()), "%v != %v", data, + b.Bytes(), + ) + }) +}