From 57a0c2a15967069b4bc602f6657635bed8f47109 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 20 Feb 2024 11:18:05 +0100 Subject: [PATCH 1/2] chore: add client status check to verify membership rpc --- modules/core/02-client/keeper/grpc_query.go | 4 ++++ modules/core/02-client/keeper/grpc_query_test.go | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index cf2714b329e..a609461965f 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -371,6 +371,10 @@ func (k Keeper) VerifyMembership(c context.Context, req *types.QueryVerifyMember return nil, status.Error(codes.NotFound, errorsmod.Wrap(types.ErrClientNotFound, req.ClientId).Error()) } + if clientStatus := k.GetClientStatus(ctx, clientState, req.ClientId); clientStatus != exported.Active { + return nil, status.Errorf(codes.FailedPrecondition, errorsmod.Wrapf(types.ErrClientNotActive, "cannot verify membership using client (%s) with status %s", req.ClientId, clientStatus).Error()) + } + if err := clientState.VerifyMembership(cachedCtx, k.ClientStore(cachedCtx, req.ClientId), k.cdc, req.ProofHeight, req.TimeDelay, req.BlockDelay, req.Proof, req.MerklePath, req.Value); err != nil { k.Logger(ctx).Debug("proof verification failed", "key", req.MerklePath, "error", err) return &types.QueryVerifyMembershipResponse{ diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index 650bf6bcddd..65e84bb118d 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -882,6 +882,22 @@ func (suite *KeeperTestSuite) TestQueryVerifyMembershipProof() { }, types.ErrClientNotFound, }, + { + "client not active", + func() { + params := types.NewParams("") // disable all clients + suite.chainA.GetSimApp().GetIBCKeeper().ClientKeeper.SetParams(suite.chainA.GetContext(), params) + + req = &types.QueryVerifyMembershipRequest{ + ClientId: path.EndpointA.ClientID, + Proof: []byte{0x01}, + ProofHeight: types.NewHeight(1, 100), + MerklePath: commitmenttypes.NewMerklePath("/ibc", host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)), + Value: []byte{0x01}, + } + }, + types.ErrClientNotActive, + }, } for _, tc := range testCases { From e46a5c8d1cdd39e01a66bc32f86bbf8695b14a80 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 20 Feb 2024 11:57:30 +0100 Subject: [PATCH 2/2] imp: deny selected client types from VerifyMembership rpc --- modules/core/02-client/keeper/grpc_query.go | 11 +++++++++++ .../core/02-client/keeper/grpc_query_test.go | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index a609461965f..0d827c379ee 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "slices" "sort" "strings" @@ -341,6 +342,16 @@ func (k Keeper) VerifyMembership(c context.Context, req *types.QueryVerifyMember return nil, status.Error(codes.InvalidArgument, err.Error()) } + clientType, _, err := types.ParseClientIdentifier(req.ClientId) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + denyClients := []string{exported.Localhost, exported.Solomachine} + if slices.Contains(denyClients, clientType) { + return nil, status.Error(codes.InvalidArgument, errorsmod.Wrapf(types.ErrInvalidClientType, "verify membership is disabled for client types %s", denyClients).Error()) + } + if len(req.Proof) == 0 { return nil, status.Error(codes.InvalidArgument, "empty proof") } diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index 65e84bb118d..f15729cc0bd 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -825,6 +825,24 @@ func (suite *KeeperTestSuite) TestQueryVerifyMembershipProof() { }, host.ErrInvalidID, }, + { + "localhost client ID is denied", + func() { + req = &types.QueryVerifyMembershipRequest{ + ClientId: exported.LocalhostClientID, + } + }, + types.ErrInvalidClientType, + }, + { + "solomachine client ID is denied", + func() { + req = &types.QueryVerifyMembershipRequest{ + ClientId: types.FormatClientIdentifier(exported.Solomachine, 1), + } + }, + types.ErrInvalidClientType, + }, { "empty proof", func() {