memory: avoid integer overflow (#1459)
Signed-off-by: Nuno Cruces <ncruces@users.noreply.github.com>
This commit is contained in:
@@ -111,7 +111,7 @@ func (m *MemoryInstance) ReadFloat64Le(offset uint32) (float64, bool) {
|
|||||||
|
|
||||||
// Read implements the same method as documented on api.Memory.
|
// Read implements the same method as documented on api.Memory.
|
||||||
func (m *MemoryInstance) Read(offset, byteCount uint32) ([]byte, bool) {
|
func (m *MemoryInstance) Read(offset, byteCount uint32) ([]byte, bool) {
|
||||||
if !m.hasSize(offset, byteCount) {
|
if !m.hasSize(offset, uint64(byteCount)) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
return m.Buffer[offset : offset+byteCount : offset+byteCount], true
|
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.
|
// Write implements the same method as documented on api.Memory.
|
||||||
func (m *MemoryInstance) Write(offset uint32, val []byte) bool {
|
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
|
return false
|
||||||
}
|
}
|
||||||
copy(m.Buffer[offset:], val)
|
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.
|
// WriteString implements the same method as documented on api.Memory.
|
||||||
func (m *MemoryInstance) WriteString(offset uint32, val string) bool {
|
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
|
return false
|
||||||
}
|
}
|
||||||
copy(m.Buffer[offset:], val)
|
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.
|
// 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.
|
// Note: This is always fine, because memory can grow, but never shrink.
|
||||||
func (m *MemoryInstance) hasSize(offset uint32, byteCount uint32) bool {
|
func (m *MemoryInstance) hasSize(offset uint32, byteCount uint64) bool {
|
||||||
return uint64(offset)+uint64(byteCount) <= uint64(len(m.Buffer)) // uint64 prevents overflow on add
|
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
|
// readUint32Le implements ReadUint32Le without using a context. This is extracted as both ints and floats are stored in
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ package wasm
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/tetratelabs/wazero/api"
|
"github.com/tetratelabs/wazero/api"
|
||||||
"github.com/tetratelabs/wazero/internal/testing/require"
|
"github.com/tetratelabs/wazero/internal/testing/require"
|
||||||
@@ -194,7 +196,7 @@ func TestMemoryInstance_HasSize(t *testing.T) {
|
|||||||
tc := tt
|
tc := tt
|
||||||
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
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)
|
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) {
|
func TestMemoryInstance_WriteString(t *testing.T) {
|
||||||
mem := &MemoryInstance{Buffer: []byte{0, 0, 0, 0, 16, 0, 0, 0}, Min: 1}
|
mem := &MemoryInstance{Buffer: []byte{0, 0, 0, 0, 16, 0, 0, 0}, Min: 1}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user