Skip to content

Commit 4b529a4

Browse files
Capability Fixes (#7918)
* add cap and name checks * Update x/capability/keeper/keeper.go * address reviews * fix missing trim Co-authored-by: Federico Kunze <[email protected]>
1 parent 15103b6 commit 4b529a4

File tree

6 files changed

+69
-14
lines changed

6 files changed

+69
-14
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ Ref: https://keepachangelog.com/en/1.0.0/
6565
* `server/types.AppExporter` requires extra argument: `AppOptions`.
6666
* `server.AddCommands` requires extra argument: `addStartFlags types.ModuleInitFlags`
6767
* `x/crisis.NewAppModule` has a new attribute: `skipGenesisInvariants`. [PR](https://github.com/cosmos/cosmos-sdk/pull/7764)
68+
* [#7918](https://github.com/cosmos/cosmos-sdk/pull/7918) Add x/capability safety checks:
69+
* All outward facing APIs will now check that capability is not nil and name is not empty before performing any state-machine changes
70+
* `SetIndex` has been renamed to `InitializeIndex`
6871

6972
### Features
7073

x/capability/genesis.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
// InitGenesis initializes the capability module's state from a provided genesis
1010
// state.
1111
func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
12-
if err := k.SetIndex(ctx, genState.Index); err != nil {
12+
if err := k.InitializeIndex(ctx, genState.Index); err != nil {
1313
panic(err)
1414
}
1515

x/capability/keeper/keeper.go

+39-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package keeper
22

33
import (
44
"fmt"
5+
"strings"
56

67
"github.com/tendermint/tendermint/libs/log"
78

@@ -49,6 +50,8 @@ type (
4950
}
5051
)
5152

53+
// NewKeeper constructs a new CapabilityKeeper instance and initializes maps
54+
// for capability map and scopedModules map.
5255
func NewKeeper(cdc codec.BinaryMarshaler, storeKey, memKey sdk.StoreKey) *Keeper {
5356
return &Keeper{
5457
cdc: cdc,
@@ -67,6 +70,9 @@ func (k *Keeper) ScopeToModule(moduleName string) ScopedKeeper {
6770
if k.sealed {
6871
panic("cannot scope to module via a sealed capability keeper")
6972
}
73+
if strings.TrimSpace(moduleName) == "" {
74+
panic("cannot scope to an empty module name")
75+
}
7076

7177
if _, ok := k.scopedModules[moduleName]; ok {
7278
panic(fmt.Sprintf("cannot create multiple scoped keepers for the same module name: %s", moduleName))
@@ -117,10 +123,10 @@ func (k *Keeper) InitializeAndSeal(ctx sdk.Context) {
117123
k.sealed = true
118124
}
119125

120-
// SetIndex sets the index to one (or greater) in InitChain according
126+
// InitializeIndex sets the index to one (or greater) in InitChain according
121127
// to the GenesisState. It must only be called once.
122128
// It will panic if the provided index is 0, or if the index is already set.
123-
func (k Keeper) SetIndex(ctx sdk.Context, index uint64) error {
129+
func (k Keeper) InitializeIndex(ctx sdk.Context, index uint64) error {
124130
if index == 0 {
125131
panic("SetIndex requires index > 0")
126132
}
@@ -200,6 +206,9 @@ func (k Keeper) InitializeCapability(ctx sdk.Context, index uint64, owners types
200206
// Note, namespacing is completely local, which is safe since records are prefixed
201207
// with the module name and no two ScopedKeeper can have the same module name.
202208
func (sk ScopedKeeper) NewCapability(ctx sdk.Context, name string) (*types.Capability, error) {
209+
if strings.TrimSpace(name) == "" {
210+
return nil, sdkerrors.Wrap(types.ErrInvalidCapabilityName, "capability name cannot be empty")
211+
}
203212
store := ctx.KVStore(sk.storeKey)
204213

205214
if _, ok := sk.GetCapability(ctx, name); ok {
@@ -247,6 +256,9 @@ func (sk ScopedKeeper) NewCapability(ctx sdk.Context, name string) (*types.Capab
247256
// Note, the capability's forward mapping is indexed by a string which should
248257
// contain its unique memory reference.
249258
func (sk ScopedKeeper) AuthenticateCapability(ctx sdk.Context, cap *types.Capability, name string) bool {
259+
if strings.TrimSpace(name) == "" || cap == nil {
260+
return false
261+
}
250262
return sk.GetCapabilityName(ctx, cap) == name
251263
}
252264

@@ -256,6 +268,12 @@ func (sk ScopedKeeper) AuthenticateCapability(ctx sdk.Context, cap *types.Capabi
256268
// index. If the owner already exists, it will return an error. Otherwise, it will
257269
// also set a forward and reverse index for the capability and capability name.
258270
func (sk ScopedKeeper) ClaimCapability(ctx sdk.Context, cap *types.Capability, name string) error {
271+
if cap == nil {
272+
return sdkerrors.Wrap(types.ErrNilCapability, "cannot claim nil capability")
273+
}
274+
if strings.TrimSpace(name) == "" {
275+
return sdkerrors.Wrap(types.ErrInvalidCapabilityName, "capability name cannot be empty")
276+
}
259277
// update capability owner set
260278
if err := sk.addOwner(ctx, cap, name); err != nil {
261279
return err
@@ -282,6 +300,9 @@ func (sk ScopedKeeper) ClaimCapability(ctx sdk.Context, cap *types.Capability, n
282300
// previously claimed or created. After releasing the capability, if no more
283301
// owners exist, the capability will be globally removed.
284302
func (sk ScopedKeeper) ReleaseCapability(ctx sdk.Context, cap *types.Capability) error {
303+
if cap == nil {
304+
return sdkerrors.Wrap(types.ErrNilCapability, "cannot release nil capability")
305+
}
285306
name := sk.GetCapabilityName(ctx, cap)
286307
if len(name) == 0 {
287308
return sdkerrors.Wrap(types.ErrCapabilityNotOwned, sk.module)
@@ -321,6 +342,9 @@ func (sk ScopedKeeper) ReleaseCapability(ctx sdk.Context, cap *types.Capability)
321342
// by name. The module is not allowed to retrieve capabilities which it does not
322343
// own.
323344
func (sk ScopedKeeper) GetCapability(ctx sdk.Context, name string) (*types.Capability, bool) {
345+
if strings.TrimSpace(name) == "" {
346+
return nil, false
347+
}
324348
memStore := ctx.KVStore(sk.memKey)
325349

326350
key := types.RevCapabilityKey(sk.module, name)
@@ -332,15 +356,14 @@ func (sk ScopedKeeper) GetCapability(ctx sdk.Context, name string) (*types.Capab
332356
// to still have the capability in the go map since changes to
333357
// go map do not automatically get reverted on tx failure,
334358
// so we delete here to remove unnecessary values in map
335-
delete(sk.capMap, index)
359+
// TODO: Delete index correctly from capMap by storing some reverse lookup
360+
// in-memory map. Issue: https://github.com/cosmos/cosmos-sdk/issues/7805
336361
return nil, false
337362
}
338363

339364
cap := sk.capMap[index]
340365
if cap == nil {
341-
// delete key from store to remove unnecessary mapping
342-
memStore.Delete(key)
343-
return nil, false
366+
panic("capability found in memstore is missing from map")
344367
}
345368

346369
return cap, true
@@ -349,14 +372,20 @@ func (sk ScopedKeeper) GetCapability(ctx sdk.Context, name string) (*types.Capab
349372
// GetCapabilityName allows a module to retrieve the name under which it stored a given
350373
// capability given the capability
351374
func (sk ScopedKeeper) GetCapabilityName(ctx sdk.Context, cap *types.Capability) string {
375+
if cap == nil {
376+
return ""
377+
}
352378
memStore := ctx.KVStore(sk.memKey)
353379

354380
return string(memStore.Get(types.FwdCapabilityKey(sk.module, cap)))
355381
}
356382

357-
// Get all the Owners that own the capability associated with the name this ScopedKeeper uses
383+
// GetOwners all the Owners that own the capability associated with the name this ScopedKeeper uses
358384
// to refer to the capability
359385
func (sk ScopedKeeper) GetOwners(ctx sdk.Context, name string) (*types.CapabilityOwners, bool) {
386+
if strings.TrimSpace(name) == "" {
387+
return nil, false
388+
}
360389
cap, ok := sk.GetCapability(ctx, name)
361390
if !ok {
362391
return nil, false
@@ -382,6 +411,9 @@ func (sk ScopedKeeper) GetOwners(ctx sdk.Context, name string) (*types.Capabilit
382411
// The method returns an error if either the capability or the owners cannot be
383412
// retreived from the memstore.
384413
func (sk ScopedKeeper) LookupModules(ctx sdk.Context, name string) ([]string, *types.Capability, error) {
414+
if strings.TrimSpace(name) == "" {
415+
return nil, nil, sdkerrors.Wrap(types.ErrInvalidCapabilityName, "cannot lookup modules with empty capability name")
416+
}
385417
cap, ok := sk.GetCapability(ctx, name)
386418
if !ok {
387419
return nil, nil, sdkerrors.Wrap(types.ErrCapabilityNotFound, name)

x/capability/keeper/keeper_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ func (suite *KeeperTestSuite) SetupTest() {
3838

3939
func (suite *KeeperTestSuite) TestInitializeAndSeal() {
4040
sk := suite.keeper.ScopeToModule(banktypes.ModuleName)
41+
suite.Require().Panics(func() {
42+
suite.keeper.ScopeToModule(" ")
43+
})
4144

4245
caps := make([]*types.Capability, 5)
4346
// Get Latest Index before creating new ones to sychronize indices correctly
@@ -105,6 +108,10 @@ func (suite *KeeperTestSuite) TestNewCapability() {
105108
suite.Require().True(ok)
106109
suite.Require().Equal(cap, got)
107110
suite.Require().True(cap == got, "expected memory addresses to be equal")
111+
112+
cap, err = sk.NewCapability(suite.ctx, " ")
113+
suite.Require().Error(err)
114+
suite.Require().Nil(cap)
108115
}
109116

110117
func (suite *KeeperTestSuite) TestOriginalCapabilityKeeper() {
@@ -151,11 +158,15 @@ func (suite *KeeperTestSuite) TestAuthenticateCapability() {
151158
badCap := types.NewCapability(100)
152159
suite.Require().False(sk1.AuthenticateCapability(suite.ctx, badCap, "transfer"))
153160
suite.Require().False(sk2.AuthenticateCapability(suite.ctx, badCap, "bond"))
161+
162+
suite.Require().False(sk1.AuthenticateCapability(suite.ctx, cap1, " "))
163+
suite.Require().False(sk1.AuthenticateCapability(suite.ctx, nil, "transfer"))
154164
}
155165

156166
func (suite *KeeperTestSuite) TestClaimCapability() {
157167
sk1 := suite.keeper.ScopeToModule(banktypes.ModuleName)
158168
sk2 := suite.keeper.ScopeToModule(stakingtypes.ModuleName)
169+
sk3 := suite.keeper.ScopeToModule("foo")
159170

160171
cap, err := sk1.NewCapability(suite.ctx, "transfer")
161172
suite.Require().NoError(err)
@@ -171,6 +182,9 @@ func (suite *KeeperTestSuite) TestClaimCapability() {
171182
got, ok = sk2.GetCapability(suite.ctx, "transfer")
172183
suite.Require().True(ok)
173184
suite.Require().Equal(cap, got)
185+
186+
suite.Require().Error(sk3.ClaimCapability(suite.ctx, cap, " "))
187+
suite.Require().Error(sk3.ClaimCapability(suite.ctx, nil, "transfer"))
174188
}
175189

176190
func (suite *KeeperTestSuite) TestGetOwners() {
@@ -237,6 +251,8 @@ func (suite *KeeperTestSuite) TestGetOwners() {
237251
}
238252
}
239253

254+
_, ok := sk1.GetOwners(suite.ctx, " ")
255+
suite.Require().False(ok, "got owners from empty capability name")
240256
}
241257

242258
func (suite *KeeperTestSuite) TestReleaseCapability() {
@@ -264,6 +280,8 @@ func (suite *KeeperTestSuite) TestReleaseCapability() {
264280
got, ok = sk1.GetCapability(suite.ctx, "transfer")
265281
suite.Require().False(ok)
266282
suite.Require().Nil(got)
283+
284+
suite.Require().Error(sk1.ReleaseCapability(suite.ctx, nil))
267285
}
268286

269287
func (suite KeeperTestSuite) TestRevertCapability() {

x/capability/types/errors.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import (
88

99
// x/capability module sentinel errors
1010
var (
11-
ErrCapabilityTaken = sdkerrors.Register(ModuleName, 2, "capability name already taken")
12-
ErrOwnerClaimed = sdkerrors.Register(ModuleName, 3, "given owner already claimed capability")
13-
ErrCapabilityNotOwned = sdkerrors.Register(ModuleName, 4, "capability not owned by module")
14-
ErrCapabilityNotFound = sdkerrors.Register(ModuleName, 5, "capability not found")
15-
ErrCapabilityOwnersNotFound = sdkerrors.Register(ModuleName, 6, "owners not found for capability")
11+
ErrInvalidCapabilityName = sdkerrors.Register(ModuleName, 2, "capability name not valid")
12+
ErrNilCapability = sdkerrors.Register(ModuleName, 3, "provided capability is nil")
13+
ErrCapabilityTaken = sdkerrors.Register(ModuleName, 4, "capability name already taken")
14+
ErrOwnerClaimed = sdkerrors.Register(ModuleName, 5, "given owner already claimed capability")
15+
ErrCapabilityNotOwned = sdkerrors.Register(ModuleName, 6, "capability not owned by module")
16+
ErrCapabilityNotFound = sdkerrors.Register(ModuleName, 7, "capability not found")
17+
ErrCapabilityOwnersNotFound = sdkerrors.Register(ModuleName, 8, "owners not found for capability")
1618
)

x/ibc/light-clients/07-tendermint/types/misbehaviour_handle.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func checkMisbehaviourHeader(
108108
chainID, _ = clienttypes.SetVersionNumber(chainID, header.GetHeight().GetVersionNumber())
109109
}
110110

111-
// - ValidatorSet must have 2/3 similarity with trusted FromValidatorSet
111+
// - ValidatorSet must have TrustLevel similarity with trusted FromValidatorSet
112112
// - ValidatorSets on both headers are valid given the last trusted ValidatorSet
113113
if err := tmTrustedValset.VerifyCommitLightTrusting(
114114
chainID, tmCommit, clientState.TrustLevel.ToTendermint(),

0 commit comments

Comments
 (0)