memory: avoid integer overflow (#1459)

Signed-off-by: Nuno Cruces <ncruces@users.noreply.github.com>
This commit is contained in:
Nuno Cruces
2023-05-12 07:53:00 +01:00
committed by GitHub
parent cd5c9ed37c
commit 4ceef7b245
2 changed files with 25 additions and 6 deletions

View File

@@ -111,7 +111,7 @@ func (m *MemoryInstance) ReadFloat64Le(offset uint32) (float64, bool) {
// Read implements the same method as documented on api.Memory.
func (m *MemoryInstance) Read(offset, byteCount uint32) ([]byte, bool) {
if !m.hasSize(offset, byteCount) {
if !m.hasSize(offset, uint64(byteCount)) {
return nil, false
}
return m.Buffer[offset : offset+byteCount : offset+byteCount], true
@@ -157,7 +157,7 @@ func (m *MemoryInstance) WriteFloat64Le(offset uint32, v float64) bool {
// Write implements the same method as documented on api.Memory.
func (m *MemoryInstance) Write(offset uint32, val []byte) bool {
if !m.hasSize(offset, uint32(len(val))) {
if !m.hasSize(offset, uint64(len(val))) {
return false
}
copy(m.Buffer[offset:], val)
@@ -166,7 +166,7 @@ func (m *MemoryInstance) Write(offset uint32, val []byte) bool {
// WriteString implements the same method as documented on api.Memory.
func (m *MemoryInstance) WriteString(offset uint32, val string) bool {
if !m.hasSize(offset, uint32(len(val))) {
if !m.hasSize(offset, uint64(len(val))) {
return false
}
copy(m.Buffer[offset:], val)
@@ -243,8 +243,8 @@ func (m *MemoryInstance) size() uint32 {
// hasSize returns true if Len is sufficient for byteCount at the given offset.
//
// Note: This is always fine, because memory can grow, but never shrink.
func (m *MemoryInstance) hasSize(offset uint32, byteCount uint32) bool {
return uint64(offset)+uint64(byteCount) <= uint64(len(m.Buffer)) // uint64 prevents overflow on add
func (m *MemoryInstance) hasSize(offset uint32, byteCount uint64) bool {
return uint64(offset)+byteCount <= uint64(len(m.Buffer)) // uint64 prevents overflow on add
}
// readUint32Le implements ReadUint32Le without using a context. This is extracted as both ints and floats are stored in

View File

@@ -2,8 +2,10 @@ package wasm
import (
"math"
"reflect"
"strings"
"testing"
"unsafe"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/testing/require"
@@ -194,7 +196,7 @@ func TestMemoryInstance_HasSize(t *testing.T) {
tc := tt
t.Run(tc.name, func(t *testing.T) {
require.Equal(t, tc.expected, memory.hasSize(tc.offset, uint32(tc.sizeInBytes)))
require.Equal(t, tc.expected, memory.hasSize(tc.offset, tc.sizeInBytes))
})
}
}
@@ -735,6 +737,23 @@ func TestMemoryInstance_Write(t *testing.T) {
require.False(t, ok)
}
func TestMemoryInstance_Write_overflow(t *testing.T) {
mem := &MemoryInstance{Buffer: []byte{0, 0, 0, 0, 16, 0, 0, 0}, Min: 1}
// Test overflow
huge := uint64(math.MaxUint32 + 1 + 4)
if huge != uint64(int(huge)) {
t.Skip("Skipping on 32-bit")
}
buf := []byte{16, 0, 0, 4}
header := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
header.Len = int(huge)
header.Cap = int(huge)
require.False(t, mem.Write(4, buf))
}
func TestMemoryInstance_WriteString(t *testing.T) {
mem := &MemoryInstance{Buffer: []byte{0, 0, 0, 0, 16, 0, 0, 0}, Min: 1}