store/internal: validate keys before calling ProofsFromMap (#9235)

Otherwise, an empty key as input or present in data can cause a panic at
runtime.

Caught by oss-fuzz: https://oss-fuzz.com/testcase-detail/4647668077953024

Fixes #9233
This commit is contained in:
Cuong Manh Le
2021-05-02 15:53:59 -07:00
committed by GitHub
parent 72873a072f
commit 711976efc1
3 changed files with 42 additions and 0 deletions
+17
View File
@@ -1,6 +1,7 @@
package proofs
import (
"errors"
"fmt"
"sort"
@@ -9,6 +10,11 @@ import (
sdkmaps "github.com/cosmos/cosmos-sdk/store/internal/maps"
)
var (
ErrEmptyKey = errors.New("key is empty")
ErrEmptyKeyInData = errors.New("data contains empty key")
)
// TendermintSpec constrains the format from ics23-tendermint (crypto/merkle SimpleProof)
var TendermintSpec = &ics23.ProofSpec{
LeafSpec: &ics23.LeafOp{
@@ -31,6 +37,9 @@ CreateMembershipProof will produce a CommitmentProof that the given key (and que
If the key doesn't exist in the tree, this will return an error.
*/
func CreateMembershipProof(data map[string][]byte, key []byte) (*ics23.CommitmentProof, error) {
if len(key) == 0 {
return nil, ErrEmptyKey
}
exist, err := createExistenceProof(data, key)
if err != nil {
return nil, err
@@ -48,6 +57,9 @@ CreateNonMembershipProof will produce a CommitmentProof that the given key doesn
If the key exists in the tree, this will return an error.
*/
func CreateNonMembershipProof(data map[string][]byte, key []byte) (*ics23.CommitmentProof, error) {
if len(key) == 0 {
return nil, ErrEmptyKey
}
// ensure this key is not in the store
if _, ok := data[string(key)]; ok {
return nil, fmt.Errorf("cannot create non-membership proof if key is in map")
@@ -89,6 +101,11 @@ func CreateNonMembershipProof(data map[string][]byte, key []byte) (*ics23.Commit
}
func createExistenceProof(data map[string][]byte, key []byte) (*ics23.ExistenceProof, error) {
for k := range data {
if k == "" {
return nil, ErrEmptyKeyInData
}
}
value, ok := data[string(key)]
if !ok {
return nil, fmt.Errorf("cannot make existence proof if key is not in map")
+23
View File
@@ -1,9 +1,11 @@
package proofs
import (
"errors"
"testing"
ics23 "github.com/confio/ics23/go"
"github.com/stretchr/testify/assert"
)
func TestCreateMembership(t *testing.T) {
@@ -87,3 +89,24 @@ func TestCreateNonMembership(t *testing.T) {
})
}
}
func TestInvalidKey(t *testing.T) {
tests := []struct {
name string
f func(data map[string][]byte, key []byte) (*ics23.CommitmentProof, error)
data map[string][]byte
key []byte
err error
}{
{"CreateMembershipProof empty key", CreateMembershipProof, map[string][]byte{"": nil}, []byte(""), ErrEmptyKey},
{"CreateMembershipProof empty key in data", CreateMembershipProof, map[string][]byte{"": nil, " ": nil}, []byte(" "), ErrEmptyKeyInData},
{"CreateNonMembershipProof empty key", CreateNonMembershipProof, map[string][]byte{" ": nil}, []byte(""), ErrEmptyKey},
{"CreateNonMembershipProof empty key in data", CreateNonMembershipProof, map[string][]byte{"": nil}, []byte(" "), ErrEmptyKeyInData},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
_, err := tc.f(tc.data, tc.key)
assert.True(t, errors.Is(err, tc.err))
})
}
}