From 7774ca0179db35802641e6637d07aafdf5897973 Mon Sep 17 00:00:00 2001 From: gammazero Date: Wed, 23 Aug 2023 15:36:40 -0700 Subject: [PATCH] Add sequence number DoS test --- chain/sub/incoming.go | 1 - chain/sub/incoming_test.go | 122 +++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index 6afd48c39..3a11f7c98 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -529,7 +529,6 @@ func (v *IndexerMessageValidator) Validate(ctx context.Context, pid peer.ID, msg msgCid := idxrMsg.Cid - var msgInfo *peerMsgInfo msgInfo, cached := v.peerCache.Get(minerAddr) if !cached { msgInfo = &peerMsgInfo{} diff --git a/chain/sub/incoming_test.go b/chain/sub/incoming_test.go index f54e09049..c3bafa7a6 100644 --- a/chain/sub/incoming_test.go +++ b/chain/sub/incoming_test.go @@ -6,12 +6,14 @@ import ( "context" "testing" + "github.com/filecoin-project/lotus/api" "github.com/golang/mock/gomock" blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "github.com/ipni/go-libipni/announce/message" pubsub "github.com/libp2p/go-libp2p-pubsub" pb "github.com/libp2p/go-libp2p-pubsub/pb" + "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" "github.com/filecoin-project/go-address" @@ -134,3 +136,123 @@ func TestIndexerMessageValidator_Validate(t *testing.T) { }) } } + +func TestIdxValidator(t *testing.T) { + validCid, err := cid.Decode("QmbpDgg5kRLDgMxS8vPKNFXEcA6D5MC4CkuUdSWDVtHPGK") + if err != nil { + t.Fatal(err) + } + + addr, err := address.NewFromString("f01024") + if err != nil { + t.Fatal(err) + } + + buf1, err := addr.MarshalBinary() + if err != nil { + t.Fatal(err) + } + + selfPID := "12D3KooWQiCbqEStCkdqUvr69gQsrp9urYJZUCkzsQXia7mbqbFW" + senderPID := "12D3KooWE8yt84RVwW3sFcd6WMjbUdWrZer2YtT4dmtj3dHdahSZ" + extraData := buf1 + + mc := gomock.NewController(t) + node := mocks.NewMockFullNode(mc) + node.EXPECT().ChainHead(gomock.Any()).Return(nil, nil).AnyTimes() + + subject := NewIndexerMessageValidator(peer.ID(selfPID), node, node) + message := message.Message{ + Cid: validCid, + Addrs: nil, + ExtraData: extraData, + } + buf := bytes.NewBuffer(nil) + if err := message.MarshalCBOR(buf); err != nil { + t.Fatal(err) + } + + topic := "topic" + + privk, _, err := crypto.GenerateKeyPair(crypto.RSA, 2048) + if err != nil { + t.Fatal(err) + } + id, err := peer.IDFromPublicKey(privk.GetPublic()) + if err != nil { + t.Fatal(err) + } + + node.EXPECT().StateMinerInfo(gomock.Any(), gomock.Any(), gomock.Any()).Return(api.MinerInfo{PeerId: &id}, nil).AnyTimes() + + pbm := &pb.Message{ + Data: buf.Bytes(), + Topic: &topic, + From: []byte(id), + Seqno: []byte{1, 1, 1, 1, 2, 2, 2, 2}, + } + validate := subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{ + Message: pbm, + ReceivedFrom: peer.ID("f01024"), // peer.ID(senderPID), + ValidatorData: nil, + }) + if validate != pubsub.ValidationAccept { + t.Error("Expected to receive ValidationAccept") + } + msgInfo, cached := subject.peerCache.Get(addr) + if !cached { + t.Fatal("Message info should be in cache") + } + seqno := msgInfo.lastSeqno + msgInfo.rateLimit = nil // prevent interference from rate limiting + + t.Log("Sending DoS msg") + privk, _, err = crypto.GenerateKeyPair(crypto.RSA, 2048) + if err != nil { + t.Fatal(err) + } + id2, err := peer.IDFromPublicKey(privk.GetPublic()) + if err != nil { + t.Fatal(err) + } + pbm = &pb.Message{ + Data: buf.Bytes(), + Topic: &topic, + From: []byte(id2), + Seqno: []byte{255, 255, 255, 255, 255, 255, 255, 255}, + } + validate = subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{ + Message: pbm, + ReceivedFrom: peer.ID(senderPID), + ValidatorData: nil, + }) + if validate != pubsub.ValidationReject { + t.Error("Expected to get ValidationReject") + } + msgInfo, cached = subject.peerCache.Get(addr) + if !cached { + t.Fatal("Message info should be in cache") + } + msgInfo.rateLimit = nil // prevent interference from rate limiting + + // Check if DoS is possible. + if msgInfo.lastSeqno != seqno { + t.Fatal("Sequence number should not have been updated") + } + + t.Log("Sending another valid message from miner...") + pbm = &pb.Message{ + Data: buf.Bytes(), + Topic: &topic, + From: []byte(id), + Seqno: []byte{1, 1, 1, 1, 2, 2, 2, 3}, + } + validate = subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{ + Message: pbm, + ReceivedFrom: peer.ID("f01024"), // peer.ID(senderPID), + ValidatorData: nil, + }) + if validate != pubsub.ValidationAccept { + t.Fatal("Did not receive ValidationAccept") + } +}