Skip to content

Commit

Permalink
add safe casting to runtime pointer casts
Browse files Browse the repository at this point in the history
  • Loading branch information
jimjbrettj committed Apr 10, 2023
1 parent 2fd876d commit 47b0040
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 19 deletions.
8 changes: 8 additions & 0 deletions lib/runtime/wasmer/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package wasmer

import (
"fmt"
"math"
"math/big"

"github.com/ChainSafe/gossamer/lib/common/types"
Expand All @@ -13,6 +14,13 @@ import (
"github.com/wasmerio/wasmer-go/wasmer"
)

func safeCastInt32(value uint32) (int32, error) {
if value > math.MaxInt32 {
return 0, fmt.Errorf("%w", errMemoryValueOutOfBounds)
}
return int32(value), nil
}

// toPointerSize converts an uint32 pointer and uint32 size
// to an int64 pointer size.
func toPointerSize(ptr, size uint32) (pointerSize int64) {
Expand Down
41 changes: 41 additions & 0 deletions lib/runtime/wasmer/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package wasmer
import (
"encoding/json"
"errors"
"math"
"os"
"path/filepath"
"testing"
Expand All @@ -30,6 +31,46 @@ func genesisFromRawJSON(t *testing.T, jsonFilepath string) (gen genesis.Genesis)
return gen
}

func TestMemory_safeCastInt32(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
value uint32
exp int32
expErr error
expErrMsg string
}{
{
name: "valid cast",
value: uint32(0),
exp: int32(0),
},
{
name: "max uint32",
value: uint32(math.MaxInt32),
exp: math.MaxInt32,
},
{
name: "out of bounds",
value: uint32(math.MaxInt32 + 1),
expErr: errMemoryValueOutOfBounds,
expErrMsg: errMemoryValueOutOfBounds.Error(),
},
}
for _, test := range testCases {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
res, err := safeCastInt32(test.value)
assert.ErrorIs(t, err, test.expErr)
if test.expErr != nil {
assert.EqualError(t, err, test.expErrMsg)
}
assert.Equal(t, test.exp, res)
})
}
}

func Test_pointerSize(t *testing.T) {
t.Parallel()

Expand Down
113 changes: 95 additions & 18 deletions lib/runtime/wasmer/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,14 @@ func ext_crypto_ed25519_generate_version_1(env interface{}, args []wasmer.Value)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

castedRet, err := safeCastInt32(ret)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

logger.Debug("generated ed25519 keypair with public key: " + kp.Public().Hex())
return []wasmer.Value{wasmer.NewI32(int32(ret))}, nil
return []wasmer.Value{wasmer.NewI32(castedRet)}, nil
}

//export ext_crypto_ed25519_public_keys_version_1
Expand Down Expand Up @@ -518,11 +524,14 @@ func ext_crypto_sr25519_generate_version_1(env interface{}, args []wasmer.Value)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

// TODO dont think this is safe
val := int32(ret)
castedRet, err := safeCastInt32(ret)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

logger.Debug("generated sr25519 keypair with public key: " + kp.Public().Hex())
return []wasmer.Value{wasmer.NewI32(val)}, nil
return []wasmer.Value{wasmer.NewI32(castedRet)}, nil
}

//export ext_crypto_sr25519_public_keys_version_1
Expand Down Expand Up @@ -789,10 +798,16 @@ func ext_trie_blake2_256_root_version_1(env interface{}, args []wasmer.Value) ([
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

castedPtr, err := safeCastInt32(ptr)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

logger.Debugf("root hash is %s", hash)
copy(memory[ptr:ptr+32], hash[:])
// TODO is this safe?
return []wasmer.Value{wasmer.NewI32(int32(ptr))}, nil
// TODO should i use cased pointer above? Maybe should just panic if safeCast fails
return []wasmer.Value{wasmer.NewI32(castedPtr)}, nil
}

//export ext_trie_blake2_256_ordered_root_version_1
Expand Down Expand Up @@ -844,10 +859,16 @@ func ext_trie_blake2_256_ordered_root_version_1(env interface{}, args []wasmer.V
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

castedPtr, err := safeCastInt32(ptr)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

logger.Debugf("root hash is %s", hash)
copy(memory[ptr:ptr+32], hash[:])
// TODO is this safe cast
return []wasmer.Value{wasmer.NewI32(int32(ptr))}, nil
// TODO use casted pointer here? Maybe panic?
return []wasmer.Value{wasmer.NewI32(castedPtr)}, nil
}

//export ext_trie_blake2_256_ordered_root_version_2
Expand Down Expand Up @@ -1312,7 +1333,13 @@ func ext_allocator_malloc_version_1(env interface{}, args []wasmer.Value) ([]was
panic(err)
}

return []wasmer.Value{wasmer.NewI32(int32(res))}, nil
castedRes, err := safeCastInt32(res)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedRes)}, nil
}

//export ext_hashing_blake2_128_version_1
Expand All @@ -1338,7 +1365,13 @@ func ext_hashing_blake2_128_version_1(env interface{}, args []wasmer.Value) ([]w
return []wasmer.Value{wasmer.NewI32(int32(0))}, nil
}

return []wasmer.Value{wasmer.NewI32(int32(out))}, nil
castedOut, err := safeCastInt32(out)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedOut)}, nil
}

//export ext_hashing_blake2_256_version_1
Expand All @@ -1362,7 +1395,13 @@ func ext_hashing_blake2_256_version_1(env interface{}, args []wasmer.Value) ([]w
return []wasmer.Value{wasmer.NewI32(int32(0))}, nil
}

return []wasmer.Value{wasmer.NewI32(int32(out))}, nil
castedOut, err := safeCastInt32(out)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedOut)}, nil
}

//export ext_hashing_keccak_256_version_1
Expand All @@ -1386,7 +1425,13 @@ func ext_hashing_keccak_256_version_1(env interface{}, args []wasmer.Value) ([]w
return []wasmer.Value{wasmer.NewI32(int32(0))}, nil
}

return []wasmer.Value{wasmer.NewI32(int32(out))}, nil
castedOut, err := safeCastInt32(out)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedOut)}, nil
}

//export ext_hashing_sha2_256_version_1
Expand All @@ -1405,7 +1450,13 @@ func ext_hashing_sha2_256_version_1(env interface{}, args []wasmer.Value) ([]was
return []wasmer.Value{wasmer.NewI32(int32(0))}, nil
}

return []wasmer.Value{wasmer.NewI32(int32(out))}, nil
castedOut, err := safeCastInt32(out)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedOut)}, nil
}

//export ext_hashing_twox_256_version_1
Expand All @@ -1429,7 +1480,13 @@ func ext_hashing_twox_256_version_1(env interface{}, args []wasmer.Value) ([]was
return []wasmer.Value{wasmer.NewI32(int32(0))}, nil
}

return []wasmer.Value{wasmer.NewI32(int32(out))}, nil
castedOut, err := safeCastInt32(out)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedOut)}, nil
}

//export ext_hashing_twox_128_version_1
Expand All @@ -1455,7 +1512,13 @@ func ext_hashing_twox_128_version_1(env interface{}, args []wasmer.Value) ([]was
return []wasmer.Value{wasmer.NewI32(int32(0))}, nil
}

return []wasmer.Value{wasmer.NewI32(int32(out))}, nil
castedOut, err := safeCastInt32(out)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedOut)}, nil
}

//export ext_hashing_twox_64_version_1
Expand All @@ -1481,7 +1544,13 @@ func ext_hashing_twox_64_version_1(env interface{}, args []wasmer.Value) ([]wasm
return []wasmer.Value{wasmer.NewI32(int32(0))}, nil
}

return []wasmer.Value{wasmer.NewI32(int32(out))}, nil
castedOut, err := safeCastInt32(out)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedOut)}, nil
}

//export ext_offchain_index_set_version_1
Expand Down Expand Up @@ -1611,7 +1680,8 @@ func ext_offchain_local_storage_get_version_1(env interface{}, args []wasmer.Val
logger.Errorf("failed to allocate memory: %s", err)
return []wasmer.Value{wasmer.NewI64(int64(0))}, nil
}
return []wasmer.Value{wasmer.NewI64(int32(ptr))}, nil

return []wasmer.Value{wasmer.NewI64(ptr)}, nil
}

//export ext_offchain_local_storage_set_version_1
Expand Down Expand Up @@ -1680,7 +1750,14 @@ func ext_offchain_random_seed_version_1(env interface{}, _ []wasmer.Value) ([]wa
if err != nil {
logger.Errorf("failed to allocate memory: %s", err)
}
return []wasmer.Value{wasmer.NewI32(ptr)}, nil

castedPtr, err := safeCastInt32(ptr)
if err != nil {
logger.Errorf("failed to safely cast pointer: %s", err)
return []wasmer.Value{wasmer.NewI32(0)}, nil
}

return []wasmer.Value{wasmer.NewI32(castedPtr)}, nil
}

//export ext_offchain_submit_transaction_version_1
Expand Down
12 changes: 11 additions & 1 deletion lib/runtime/wasmer/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,17 @@ func (in *Instance) Exec(function string, data []byte) (result []byte, err error
return nil, fmt.Errorf("%w: %s", ErrExportFunctionNotFound, function)
}

wasmValue, err := runtimeFunc(int32(inputPtr), int32(dataLength))
castedInputPointer, err := safeCastInt32(inputPtr)
if err != nil {
panic(err)
}

castedDataLength, err := safeCastInt32(dataLength)
if err != nil {
panic(err)
}

wasmValue, err := runtimeFunc(castedInputPointer, castedDataLength)
if err != nil {
return nil, fmt.Errorf("running runtime function: %w", err)
}
Expand Down

0 comments on commit 47b0040

Please sign in to comment.