Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(audit): resolve more audit findings #217

Merged
merged 12 commits into from
Oct 18, 2024
67 changes: 47 additions & 20 deletions app/ante/cosmos/sigverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,26 +495,9 @@ func ConsumeMultisignatureVerificationGas(
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
params types.Params, accSeq uint64,
) error {
size := sig.BitArray.Count()
sigIndex := 0

for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
continue
}
sigV2 := signing.SignatureV2{
PubKey: pubkey.GetPubKeys()[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++
}

return nil
return ConsumeMultisignatureVerificationGasWithVerifier(
meter, sig, pubkey, params, accSeq, DefaultSigVerificationGasConsumer,
)
}

// GetSignerAcc returns an account for a given address that is expected to sign
Expand Down Expand Up @@ -580,3 +563,47 @@ func signatureDataToBz(data signing.SignatureData) ([][]byte, error) {
return nil, sdkerrors.ErrInvalidType.Wrapf("unexpected signature data type %T", data)
}
}

// ConsumeMultisignatureVerificationGasWithVerifier consumes gas from a GasMeter for verifying
// a multisig pubkey signature. It uses the provided verifier function to verify each signature
// and consume gas accordingly.
func ConsumeMultisignatureVerificationGasWithVerifier(
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
params types.Params, accSeq uint64, verifier authante.SignatureVerificationGasConsumer,
) error {
pubkeys := pubkey.GetPubKeys()
size := sig.BitArray.Count()
if size != len(pubkeys) {
return sdkerrors.ErrInvalidPubKey.Wrap(
"bitarray length doesn't match the number of public keys",
)
}
if len(sig.Signatures) != sig.BitArray.NumTrueBitsBefore(size) {
return sdkerrors.ErrTooManySignatures.Wrap(
"number of signatures doesn't equal the number of true bits in bitarray",
)
}
// we have verified that size == len(pubkeys)
// and that the number of signatures == number of true bits in the bitarray
// so we can safely iterate over the pubkeys and signatures
sigIndex := 0

for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
// not signed
continue
}
sigV2 := signing.SignatureV2{
PubKey: pubkeys[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := verifier(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++
}

return nil
}
35 changes: 4 additions & 31 deletions app/ante/sigverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

errorsmod "cosmossdk.io/errors"
cosmosante "github.com/ExocoreNetwork/exocore/app/ante/cosmos"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -64,35 +65,7 @@ func ConsumeMultisignatureVerificationGas(
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
params authtypes.Params, accSeq uint64,
) error {
pubkeys := pubkey.GetPubKeys()
size := sig.BitArray.Count()
if size != len(pubkeys) {
return errorsmod.Wrapf(errortypes.ErrInvalidPubKey, "bitarray length doesn't match the number of public keys")
}
if len(sig.Signatures) != sig.BitArray.NumTrueBitsBefore(size) {
return errorsmod.Wrapf(errortypes.ErrTooManySignatures, "number of signatures exceeds number of bits in bitarray")
}
// we have verified that size == len(pubkeys)
// and that the number of signatures == number of true bits in the bitarray
// so we can safely iterate over the pubkeys and signatures
sigIndex := 0

for i := 0; i < size; i++ {
if !sig.BitArray.GetIndex(i) {
// not signed
continue
}
sigV2 := signing.SignatureV2{
PubKey: pubkeys[i],
Data: sig.Signatures[sigIndex],
Sequence: accSeq,
}
err := SigVerificationGasConsumer(meter, sigV2, params)
if err != nil {
return err
}
sigIndex++
}

return nil
return cosmosante.ConsumeMultisignatureVerificationGasWithVerifier(
meter, sig, pubkey, params, accSeq, SigVerificationGasConsumer,
)
}
12 changes: 7 additions & 5 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,10 @@ func NewExocoreApp(
)

// asset and client chain registry.
app.AssetsKeeper = assetsKeeper.NewKeeper(keys[assetsTypes.StoreKey], appCodec, &app.OracleKeeper, app.BankKeeper, &app.DelegationKeeper)
app.AssetsKeeper = assetsKeeper.NewKeeper(
keys[assetsTypes.StoreKey], appCodec, &app.OracleKeeper,
app.BankKeeper, &app.DelegationKeeper, authAddrString,
)

// handles delegations by stakers, and must know if the delegatee operator is registered.
app.DelegationKeeper = delegationKeeper.NewKeeper(
Expand Down Expand Up @@ -574,18 +577,17 @@ func NewExocoreApp(
// these two modules aren't finalized yet.
app.RewardKeeper = rewardKeeper.NewKeeper(
appCodec, keys[rewardTypes.StoreKey], app.AssetsKeeper,
app.AVSManagerKeeper,
app.AVSManagerKeeper, authAddrString,
)
app.ExoSlashKeeper = slashKeeper.NewKeeper(
appCodec, keys[exoslashTypes.StoreKey], app.AssetsKeeper,
appCodec, keys[exoslashTypes.StoreKey], app.AssetsKeeper, authAddrString,
)

// x/oracle is not fully integrated (or enabled) but allows for exchange rates to be added.
app.OracleKeeper = oracleKeeper.NewKeeper(
appCodec, keys[oracleTypes.StoreKey], memKeys[oracleTypes.MemStoreKey],
app.GetSubspace(oracleTypes.ModuleName), app.StakingKeeper,
&app.DelegationKeeper,
&app.AssetsKeeper,
&app.DelegationKeeper, &app.AssetsKeeper, authAddrString,
)

// the SDK slashing module is used to slash validators in the case of downtime. it tracks
Expand Down
4 changes: 3 additions & 1 deletion precompiles/reward/reward_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ func (s *RewardPrecompileTestSuite) TestRunRewardThroughClientChain() {
s.Require().NoError(err, "failed to pack input")
return s.Address, input
}
successRet, err := s.precompile.Methods[reward.MethodReward].Outputs.Pack(true, new(big.Int).Add(depositAmount, withdrawAmount))
// successRet, err := s.precompile.Methods[reward.MethodReward].Outputs.Pack(true, new(big.Int).Add(depositAmount, withdrawAmount))
// TODO: reward precompile is disabled, so it always errors and returns fail
successRet, err := s.precompile.Methods[reward.MethodReward].Outputs.Pack(false, new(big.Int))
s.Require().NoError(err)
testcases := []struct {
name string
Expand Down
3 changes: 3 additions & 0 deletions testutil/keeper/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"github.com/cosmos/cosmos-sdk/store"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
typesparams "github.com/cosmos/cosmos-sdk/x/params/types"

assetskeeper "github.com/ExocoreNetwork/exocore/x/assets/keeper"
Expand Down Expand Up @@ -49,6 +51,7 @@ func OracleKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
dogfoodkeeper.Keeper{},
delegationkeeper.Keeper{},
assetskeeper.Keeper{},
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

ctx := sdk.NewContext(stateStore, tmproto.Header{
Expand Down
13 changes: 11 additions & 2 deletions x/assets/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package keeper

import (
"fmt"

assetstype "github.com/ExocoreNetwork/exocore/x/assets/types"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
Expand All @@ -13,8 +15,9 @@ type Keeper struct {
storeKey storetypes.StoreKey
cdc codec.BinaryCodec
assetstype.OracleKeeper
bk assetstype.BankKeeper
dk delegationKeeper
bk assetstype.BankKeeper
dk delegationKeeper
authority string
}

func NewKeeper(
Expand All @@ -23,13 +26,19 @@ func NewKeeper(
oracleKeeper assetstype.OracleKeeper,
bk assetstype.BankKeeper,
dk delegationKeeper,
authority string,
) Keeper {
// ensure authority is a valid bech32 address
if _, err := sdk.AccAddressFromBech32(authority); err != nil {
panic(fmt.Sprintf("authority address %s is invalid: %s", authority, err))
}
return Keeper{
storeKey: storeKey,
cdc: cdc,
OracleKeeper: oracleKeeper,
bk: bk,
dk: dk,
authority: authority,
}
}

Expand Down
13 changes: 13 additions & 0 deletions x/assets/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,28 @@ package keeper
import (
"context"

"github.com/ExocoreNetwork/exocore/utils"
assetstype "github.com/ExocoreNetwork/exocore/x/assets/types"
sdk "github.com/cosmos/cosmos-sdk/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
)

var _ assetstype.MsgServer = &Keeper{}

// UpdateParams This function should be triggered by the governance in the future
func (k Keeper) UpdateParams(ctx context.Context, params *assetstype.MsgUpdateParams) (*assetstype.MsgUpdateParamsResponse, error) {
c := sdk.UnwrapSDKContext(ctx)
if utils.IsMainnet(c.ChainID()) && k.authority != params.Authority {
return nil, govtypes.ErrInvalidSigner.Wrapf(
"invalid authority; expected %s, got %s",
k.authority, params.Authority,
)
}
c.Logger().Info(
"UpdateParams request",
"authority", k.authority,
"params.AUthority", params.Authority,
)
err := k.SetParams(c, &params.Params)
if err != nil {
return nil, err
Expand Down
11 changes: 10 additions & 1 deletion x/dogfood/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ type (
)

// NewKeeper creates a new dogfood keeper.
func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, epochsKeeper types.EpochsKeeper, operatorKeeper types.OperatorKeeper, delegationKeeper keeper.Keeper, restakingKeeper types.AssetsKeeper, avsKeeper types.AVSKeeper, authority string) Keeper {
func NewKeeper(
cdc codec.BinaryCodec, storeKey storetypes.StoreKey,
epochsKeeper types.EpochsKeeper, operatorKeeper types.OperatorKeeper,
delegationKeeper keeper.Keeper, restakingKeeper types.AssetsKeeper,
avsKeeper types.AVSKeeper, authority string,
) Keeper {
k := Keeper{
cdc: cdc,
storeKey: storeKey,
Expand Down Expand Up @@ -113,6 +118,10 @@ func (k Keeper) mustValidateFields() {
types.PanicIfNil(k.delegationKeeper, "delegationKeeper")
types.PanicIfNil(k.restakingKeeper, "restakingKeeper")
types.PanicIfNil(k.avsKeeper, "avsKeeper")
// ensure authority is a valid bech32 address
if _, err := sdk.AccAddressFromBech32(k.authority); err != nil {
panic(fmt.Sprintf("authority address %s is invalid: %s", k.authority, err))
}
}

// Add the function to get detail information through the operatorKeeper within the dogfood
Expand Down
23 changes: 14 additions & 9 deletions x/dogfood/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import (
"strings"

"cosmossdk.io/errors"
"github.com/ExocoreNetwork/exocore/utils"
avskeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper"
avstypes "github.com/ExocoreNetwork/exocore/x/avs/types"

"github.com/ExocoreNetwork/exocore/x/dogfood/types"
epochstypes "github.com/ExocoreNetwork/exocore/x/epochs/types"
sdk "github.com/cosmos/cosmos-sdk/types"
epochstypes "github.com/evmos/evmos/v16/x/epochs/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
)

type msgServer struct {
Expand All @@ -31,13 +32,17 @@ func (k Keeper) UpdateParams(
ctx context.Context, msg *types.MsgUpdateParams,
) (*types.MsgUpdateParamsResponse, error) {
c := sdk.UnwrapSDKContext(ctx)
// if k.authority != msg.Authority {
// return nil, errorsmod.Wrapf(
// govtypes.ErrInvalidSigner,
// "invalid authority; expected %s, got %s",
// k.authority, msg.Authority,
// )
// }
if utils.IsMainnet(c.ChainID()) && k.authority != msg.Authority {
return nil, govtypes.ErrInvalidSigner.Wrapf(
"invalid authority; expected %s, got %s",
k.authority, msg.Authority,
)
}
k.Logger(c).Info(
"UpdateParams request",
"authority", k.authority,
"params.Authority", msg.Authority,
)
prevParams := k.GetDogfoodParams(c)
nextParams := msg.Params
logger := k.Logger(c)
Expand Down
4 changes: 4 additions & 0 deletions x/exomint/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ func NewKeeper(
if addr := ak.GetModuleAddress(types.ModuleName); addr == nil {
panic(fmt.Sprintf("the x/%s module account has not been set", types.ModuleName))
}
// ensure authority is a valid bech32 address
if _, err := sdk.AccAddressFromBech32(authority); err != nil {
panic(fmt.Sprintf("authority address %s is invalid: %s", authority, err))
}

return Keeper{
cdc: cdc,
Expand Down
21 changes: 13 additions & 8 deletions x/exomint/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import (
"context"

errorsmod "cosmossdk.io/errors"

"github.com/ExocoreNetwork/exocore/utils"
"github.com/ExocoreNetwork/exocore/x/exomint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
)

type msgServer struct {
Expand All @@ -27,13 +28,17 @@ func (k Keeper) UpdateParams(
ctx context.Context, msg *types.MsgUpdateParams,
) (*types.MsgUpdateParamsResponse, error) {
c := sdk.UnwrapSDKContext(ctx)
// if k.authority != msg.Authority {
// return nil, errorsmod.Wrapf(
// govtypes.ErrInvalidSigner,
// "invalid authority; expected %s, got %s",
// k.authority, msg.Authority,
// )
// }
if utils.IsMainnet(c.ChainID()) && k.authority != msg.Authority {
return nil, govtypes.ErrInvalidSigner.Wrapf(
"invalid authority; expected %s, got %s",
k.authority, msg.Authority,
)
}
k.Logger(c).Info(
"UpdateParams request",
"authority", k.authority,
"params.Authority", msg.Authority,
)
prevParams := k.GetParams(c)
nextParams := msg.Params
// stateless validations
Expand Down
Loading
Loading