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: check store keys length before accessing #9639

Merged
merged 18 commits into from
Jul 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Bug Fixes

* [\#9639](https://github.com/cosmos/cosmos-sdk/pull/9639) Check store keys length before accessing them by making sure that `key` is of length `m+1` (for `key[n:m]`)
* (types) [\#9627](https://github.com/cosmos/cosmos-sdk/pull/9627) Fix nil pointer panic on `NewBigIntFromInt`
* (x/genutil) [\#9574](https://github.com/cosmos/cosmos-sdk/pull/9575) Actually use the `gentx` client tx flags (like `--keyring-dir`)
* (x/distribution) [\#9599](https://github.com/cosmos/cosmos-sdk/pull/9599) Withdraw rewards event now includes a value attribute even if there are 0 rewards (due to situations like 100% commission).
Expand Down
17 changes: 17 additions & 0 deletions types/kv/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package kv

import "fmt"

// AssertKeyAtLeastLength panics when store key length is less than the given length.
func AssertKeyAtLeastLength(bz []byte, length int) {
likhita-809 marked this conversation as resolved.
Show resolved Hide resolved
if len(bz) < length {
panic(fmt.Sprintf("expected key of length at least %d, got %d", length, len(bz)))
}
}

// AssertKeyLength panics when store key length is not equal to the given length.
func AssertKeyLength(bz []byte, length int) {
if len(bz) != length {
panic(fmt.Sprintf("unexpected key length; got: %d, expected: %d", len(bz), length))
}
}
4 changes: 4 additions & 0 deletions x/authz/keeper/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/cosmos/cosmos-sdk/internal/conv"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/authz"
)

Expand Down Expand Up @@ -38,9 +39,12 @@ func grantStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType strin
func addressesFromGrantStoreKey(key []byte) (granterAddr, granteeAddr sdk.AccAddress) {
// key is of format:
// 0x01<granterAddressLen (1 Byte)><granterAddress_Bytes><granteeAddressLen (1 Byte)><granteeAddress_Bytes><msgType_Bytes>
kv.AssertKeyAtLeastLength(key, 2)
granterAddrLen := key[1] // remove prefix key
kv.AssertKeyAtLeastLength(key, int(3+granterAddrLen))
likhita-809 marked this conversation as resolved.
Show resolved Hide resolved
granterAddr = sdk.AccAddress(key[2 : 2+granterAddrLen])
granteeAddrLen := int(key[2+granterAddrLen])
kv.AssertKeyAtLeastLength(key, 4+int(granterAddrLen+byte(granteeAddrLen)))
granteeAddr = sdk.AccAddress(key[3+granterAddrLen : 3+granterAddrLen+byte(granteeAddrLen)])

return granterAddr, granteeAddr
Expand Down
9 changes: 3 additions & 6 deletions x/bank/migrations/v040/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
package v040

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/kv"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/migrations/v040"
)

Expand Down Expand Up @@ -40,10 +39,8 @@ func DenomMetadataKey(denom string) []byte {
// store. The key must not contain the perfix BalancesPrefix as the prefix store
// iterator discards the actual prefix.
func AddressFromBalancesStore(key []byte) sdk.AccAddress {
kv.AssertKeyAtLeastLength(key, 1+v040auth.AddrLen)
addr := key[:v040auth.AddrLen]
if len(addr) != v040auth.AddrLen {
panic(fmt.Sprintf("unexpected account address key length; got: %d, expected: %d", len(addr), v040auth.AddrLen))
}

kv.AssertKeyLength(addr, v040auth.AddrLen)
return sdk.AccAddress(addr)
}
2 changes: 2 additions & 0 deletions x/bank/types/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
"github.com/cosmos/cosmos-sdk/types/kv"
)

const (
Expand Down Expand Up @@ -43,6 +44,7 @@ func AddressFromBalancesStore(key []byte) (sdk.AccAddress, error) {
if len(key) == 0 {
return nil, ErrInvalidKey
}
kv.AssertKeyAtLeastLength(key, 1)
addrLen := key[0]
bound := int(addrLen)
if len(key)-1 < bound {
Expand Down
45 changes: 18 additions & 27 deletions x/distribution/migrations/v040/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/binary"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/kv"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/migrations/v040"
)

Expand Down Expand Up @@ -58,78 +59,68 @@ var (

// gets an address from a validator's outstanding rewards key
func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) {
kv.AssertKeyAtLeastLength(key, 2)
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, v040auth.AddrLen)
return sdk.ValAddress(addr)
}

// gets an address from a delegator's withdraw info key
func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) {
kv.AssertKeyAtLeastLength(key, 2)
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, v040auth.AddrLen)
return sdk.AccAddress(addr)
}

// gets the addresses from a delegator starting info key
func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) {
kv.AssertKeyAtLeastLength(key, 2+v040auth.AddrLen)
addr := key[1 : 1+v040auth.AddrLen]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, v040auth.AddrLen)
valAddr = sdk.ValAddress(addr)
addr = key[1+v040auth.AddrLen:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, v040auth.AddrLen)
delAddr = sdk.AccAddress(addr)
return
}

// gets the address & period from a validator's historical rewards key
func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) {
kv.AssertKeyAtLeastLength(key, 2+v040auth.AddrLen)
addr := key[1 : 1+v040auth.AddrLen]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, v040auth.AddrLen)
valAddr = sdk.ValAddress(addr)
b := key[1+v040auth.AddrLen:]
if len(b) != 8 {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, 8)
period = binary.LittleEndian.Uint64(b)
return
}

// gets the address from a validator's current rewards key
func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) {
kv.AssertKeyAtLeastLength(key, 2)
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, v040auth.AddrLen)
return sdk.ValAddress(addr)
}

// gets the address from a validator's accumulated commission key
func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) {
kv.AssertKeyAtLeastLength(key, 2)
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, v040auth.AddrLen)
return sdk.ValAddress(addr)
}

// gets the height from a validator's slash event key
func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) {
kv.AssertKeyAtLeastLength(key, 2+v040auth.AddrLen)
addr := key[1 : 1+v040auth.AddrLen]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, v040auth.AddrLen)
valAddr = sdk.ValAddress(addr)
startB := 1 + v040auth.AddrLen
kv.AssertKeyAtLeastLength(key, startB+9)
b := key[startB : startB+8] // the next 8 bytes represent the height
height = binary.BigEndian.Uint64(b)
return
Expand Down
37 changes: 19 additions & 18 deletions x/distribution/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
"github.com/cosmos/cosmos-sdk/types/kv"
)

const (
Expand Down Expand Up @@ -60,10 +61,9 @@ func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress)
// 0x02<valAddrLen (1 Byte)><valAddr_Bytes>

// Remove prefix and address length.
kv.AssertKeyAtLeastLength(key, 3)
addr := key[2:]
if len(addr) != int(key[1]) {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, int(key[1]))

return sdk.ValAddress(addr)
}
Expand All @@ -74,10 +74,9 @@ func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) {
// 0x03<accAddrLen (1 Byte)><accAddr_Bytes>

// Remove prefix and address length.
kv.AssertKeyAtLeastLength(key, 3)
addr := key[2:]
if len(addr) != int(key[1]) {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, int(key[1]))

return sdk.AccAddress(addr)
}
Expand All @@ -86,13 +85,14 @@ func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) {
func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) {
// key is in the format:
// 0x04<valAddrLen (1 Byte)><valAddr_Bytes><accAddrLen (1 Byte)><accAddr_Bytes>
kv.AssertKeyAtLeastLength(key, 2)
valAddrLen := int(key[1])
kv.AssertKeyAtLeastLength(key, 3+valAddrLen)
valAddr = sdk.ValAddress(key[2 : 2+valAddrLen])
delAddrLen := int(key[2+valAddrLen])
kv.AssertKeyAtLeastLength(key, 4+valAddrLen)
delAddr = sdk.AccAddress(key[3+valAddrLen:])
if len(delAddr.Bytes()) != delAddrLen {
panic("unexpected key length")
}
kv.AssertKeyLength(delAddr.Bytes(), delAddrLen)

return
}
Expand All @@ -101,12 +101,12 @@ func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delA
func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) {
// key is in the format:
// 0x05<valAddrLen (1 Byte)><valAddr_Bytes><period_Bytes>
kv.AssertKeyAtLeastLength(key, 2)
valAddrLen := int(key[1])
kv.AssertKeyAtLeastLength(key, 3+valAddrLen)
valAddr = sdk.ValAddress(key[2 : 2+valAddrLen])
b := key[2+valAddrLen:]
if len(b) != 8 {
panic("unexpected key length")
}
kv.AssertKeyLength(b, 8)
period = binary.LittleEndian.Uint64(b)
return
}
Expand All @@ -117,10 +117,9 @@ func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) {
// 0x06<valAddrLen (1 Byte)><valAddr_Bytes>: ValidatorCurrentRewards

// Remove prefix and address length.
kv.AssertKeyAtLeastLength(key, 3)
addr := key[2:]
if len(addr) != int(key[1]) {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, int(key[1]))

return sdk.ValAddress(addr)
}
Expand All @@ -131,10 +130,9 @@ func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddres
// 0x07<valAddrLen (1 Byte)><valAddr_Bytes>: ValidatorCurrentRewards

// Remove prefix and address length.
kv.AssertKeyAtLeastLength(key, 3)
addr := key[2:]
if len(addr) != int(key[1]) {
panic("unexpected key length")
}
kv.AssertKeyLength(addr, int(key[1]))

return sdk.ValAddress(addr)
}
Expand All @@ -143,9 +141,12 @@ func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddres
func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) {
// key is in the format:
// 0x08<valAddrLen (1 Byte)><valAddr_Bytes><height>: ValidatorSlashEvent
kv.AssertKeyAtLeastLength(key, 2)
valAddrLen := int(key[1])
kv.AssertKeyAtLeastLength(key, 3+valAddrLen)
valAddr = key[2 : 2+valAddrLen]
startB := 2 + valAddrLen
kv.AssertKeyAtLeastLength(key, startB+9)
b := key[startB : startB+8] // the next 8 bytes represent the height
height = binary.BigEndian.Uint64(b)
return
Expand Down
15 changes: 5 additions & 10 deletions x/gov/migrations/v040/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ package v040

import (
"encoding/binary"
"fmt"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/kv"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/migrations/v040"
)

Expand Down Expand Up @@ -113,9 +113,7 @@ func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte {

// SplitProposalKey split the proposal key and returns the proposal id
func SplitProposalKey(key []byte) (proposalID uint64) {
if len(key[1:]) != 8 {
panic(fmt.Sprintf("unexpected key length (%d ≠ 8)", len(key[1:])))
}
kv.AssertKeyLength(key[1:], 8)

return GetProposalIDFromBytes(key[1:])
}
Expand Down Expand Up @@ -143,9 +141,7 @@ func SplitKeyVote(key []byte) (proposalID uint64, voterAddr sdk.AccAddress) {
// private functions

func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) {
if len(key[1:]) != 8+lenTime {
panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key[1:]), lenTime+8))
}
kv.AssertKeyLength(key[1:], 8+lenTime)

endTime, err := sdk.ParseTimeBytes(key[1 : 1+lenTime])
if err != nil {
Expand All @@ -157,10 +153,9 @@ func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) {
}

func splitKeyWithAddress(key []byte) (proposalID uint64, addr sdk.AccAddress) {
if len(key[1:]) != 8+v040auth.AddrLen {
panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key), 8+v040auth.AddrLen))
}
kv.AssertKeyLength(key[1:], 8+v040auth.AddrLen)

kv.AssertKeyAtLeastLength(key, 10)
proposalID = GetProposalIDFromBytes(key[1:9])
addr = sdk.AccAddress(key[9:])
return
Expand Down
12 changes: 5 additions & 7 deletions x/gov/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package types

import (
"encoding/binary"
"fmt"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
"github.com/cosmos/cosmos-sdk/types/kv"
)

const (
Expand Down Expand Up @@ -111,9 +111,7 @@ func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte {

// SplitProposalKey split the proposal key and returns the proposal id
func SplitProposalKey(key []byte) (proposalID uint64) {
if len(key[1:]) != 8 {
panic(fmt.Sprintf("unexpected key length (%d ≠ 8)", len(key[1:])))
}
kv.AssertKeyLength(key[1:], 8)

return GetProposalIDFromBytes(key[1:])
}
Expand Down Expand Up @@ -141,9 +139,7 @@ func SplitKeyVote(key []byte) (proposalID uint64, voterAddr sdk.AccAddress) {
// private functions

func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) {
if len(key[1:]) != 8+lenTime {
panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key[1:]), lenTime+8))
}
kv.AssertKeyLength(key[1:], 8+lenTime)

endTime, err := sdk.ParseTimeBytes(key[1 : 1+lenTime])
if err != nil {
Expand All @@ -157,7 +153,9 @@ func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) {
func splitKeyWithAddress(key []byte) (proposalID uint64, addr sdk.AccAddress) {
// Both Vote and Deposit store keys are of format:
// <prefix (1 Byte)><proposalID (8 bytes)><addrLen (1 Byte)><addr_Bytes>
kv.AssertKeyAtLeastLength(key, 10)
proposalID = GetProposalIDFromBytes(key[1:9])
kv.AssertKeyAtLeastLength(key, 11)
addr = sdk.AccAddress(key[10:])
return
}
Loading