summaryrefslogtreecommitdiffstats
path: root/third_party/rlbox_wasm2c_sandbox/src/wasm2c_rt_mem.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rlbox_wasm2c_sandbox/src/wasm2c_rt_mem.c')
-rw-r--r--third_party/rlbox_wasm2c_sandbox/src/wasm2c_rt_mem.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/third_party/rlbox_wasm2c_sandbox/src/wasm2c_rt_mem.c b/third_party/rlbox_wasm2c_sandbox/src/wasm2c_rt_mem.c
new file mode 100644
index 0000000000..1bdf6f715c
--- /dev/null
+++ b/third_party/rlbox_wasm2c_sandbox/src/wasm2c_rt_mem.c
@@ -0,0 +1,454 @@
+#include "wasm2c_rt_mem.h"
+#include "wasm-rt.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum
+{
+ MMAP_PROT_NONE = 0,
+ MMAP_PROT_READ = 1,
+ MMAP_PROT_WRITE = 2,
+ MMAP_PROT_EXEC = 4
+};
+
+/* Memory map flags */
+enum
+{
+ MMAP_MAP_NONE = 0,
+ /* Put the mapping into 0 to 2 G, supported only on x86_64 */
+ MMAP_MAP_32BIT = 1,
+ /* Don't interpret addr as a hint: place the mapping at exactly
+ that address. */
+ MMAP_MAP_FIXED = 2
+};
+
+// Try reserving an aligned memory space.
+// Returns pointer to allocated space on success, 0 on failure.
+static void* os_mmap_aligned(void* addr,
+ size_t requested_length,
+ int prot,
+ int flags,
+ size_t alignment,
+ size_t alignment_offset);
+// Unreserve the memory space
+static void os_munmap(void* addr, size_t size);
+// Allocates and sets the permissions on the previously reserved memory space
+// Returns 0 on success, non zero on failure.
+static int os_mmap_commit(void* curr_heap_end_pointer,
+ size_t expanded_size,
+ int prot);
+
+wasm_rt_memory_t* w2c_env_memory(struct w2c_env* instance)
+{
+ return instance->sandbox_memory_info;
+}
+
+wasm_rt_funcref_table_t* w2c_env_0x5F_indirect_function_table(
+ struct w2c_env* instance)
+{
+ return instance->sandbox_callback_table;
+}
+
+#define WASM_PAGE_SIZE 65536
+#define RLBOX_FOUR_GIG 0x100000000ull
+
+#if UINTPTR_MAX == 0xffffffffffffffff
+// Guard page of 4GiB
+# define WASM_HEAP_GUARD_PAGE_SIZE 0x100000000ull
+// Heap aligned to 4GB
+# define WASM_HEAP_ALIGNMENT 0x100000000ull
+// By default max heap is 4GB
+# define WASM_HEAP_DEFAULT_MAX_PAGES 65536
+#elif UINTPTR_MAX == 0xffffffff
+// No guard pages
+# define WASM_HEAP_GUARD_PAGE_SIZE 0
+// Unaligned heap
+# define WASM_HEAP_ALIGNMENT 0
+// Default max heap is 16MB
+# define WASM_HEAP_DEFAULT_MAX_PAGES 256
+#else
+# error "Unknown pointer size"
+#endif
+
+static uint64_t compute_heap_reserve_space(uint32_t chosen_max_pages)
+{
+ const uint64_t heap_reserve_size =
+ ((uint64_t)chosen_max_pages) * WASM_PAGE_SIZE + WASM_HEAP_GUARD_PAGE_SIZE;
+ return heap_reserve_size;
+}
+
+w2c_mem_capacity get_valid_wasm2c_memory_capacity(uint64_t min_capacity,
+ bool is_mem_32)
+{
+ const w2c_mem_capacity err_val = { false /* is_valid */,
+ false /* is_mem_32 */,
+ 0 /* max_pages */,
+ 0 /* max_size */ };
+
+ // We do not handle memory 64
+ if (!is_mem_32) {
+ return err_val;
+ }
+
+ const uint64_t default_capacity =
+ ((uint64_t)WASM_HEAP_DEFAULT_MAX_PAGES) * WASM_PAGE_SIZE;
+
+ if (min_capacity <= default_capacity) {
+ // Handle 0 case and small values
+ const w2c_mem_capacity ret = { true /* is_valid */,
+ true /* is_mem_32 */,
+ WASM_HEAP_DEFAULT_MAX_PAGES /* max_pages */,
+ default_capacity /* max_size */ };
+ return ret;
+ } else if (min_capacity > UINT32_MAX) {
+ // Handle out of range values
+ return err_val;
+ }
+
+ const uint64_t page_size_minus_1 = WASM_PAGE_SIZE - 1;
+ // Get number of pages greater than min_capacity
+ const uint64_t capacity_pages = ((min_capacity - 1) / page_size_minus_1) + 1;
+
+ const w2c_mem_capacity ret = { true /* is_valid */,
+ true /* is_mem_32 */,
+ capacity_pages /* max_pages */,
+ capacity_pages *
+ WASM_PAGE_SIZE /* max_size */ };
+ return ret;
+}
+
+wasm_rt_memory_t create_wasm2c_memory(uint32_t initial_pages,
+ const w2c_mem_capacity* custom_capacity)
+{
+
+ if (custom_capacity && !custom_capacity->is_valid) {
+ wasm_rt_memory_t ret = { 0 };
+ return ret;
+ }
+
+ const uint32_t byte_length = initial_pages * WASM_PAGE_SIZE;
+ const uint64_t chosen_max_pages =
+ custom_capacity ? custom_capacity->max_pages : WASM_HEAP_DEFAULT_MAX_PAGES;
+ const uint64_t heap_reserve_size =
+ compute_heap_reserve_space(chosen_max_pages);
+
+ uint8_t* data = 0;
+ const uint64_t retries = 10;
+ for (uint64_t i = 0; i < retries; i++) {
+ data = (uint8_t*)os_mmap_aligned(0,
+ heap_reserve_size,
+ MMAP_PROT_NONE,
+ MMAP_MAP_NONE,
+ WASM_HEAP_ALIGNMENT,
+ 0 /* alignment_offset */);
+ if (data) {
+ int ret =
+ os_mmap_commit(data, byte_length, MMAP_PROT_READ | MMAP_PROT_WRITE);
+ if (ret != 0) {
+ // failed to set permissions
+ os_munmap(data, heap_reserve_size);
+ data = 0;
+ }
+ break;
+ }
+ }
+
+ wasm_rt_memory_t ret;
+ ret.data = data;
+ ret.max_pages = chosen_max_pages;
+ ret.pages = initial_pages;
+ ret.size = byte_length;
+ return ret;
+}
+
+void destroy_wasm2c_memory(wasm_rt_memory_t* memory)
+{
+ if (memory->data != 0) {
+ const uint64_t heap_reserve_size =
+ compute_heap_reserve_space(memory->max_pages);
+ os_munmap(memory->data, heap_reserve_size);
+ memory->data = 0;
+ }
+}
+
+#undef WASM_HEAP_DEFAULT_MAX_PAGES
+#undef WASM_HEAP_ALIGNMENT
+#undef WASM_HEAP_GUARD_PAGE_SIZE
+#undef RLBOX_FOUR_GIG
+#undef WASM_PAGE_SIZE
+
+// Based on
+// https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#BSD
+// Check for windows (non cygwin) environment
+#if defined(_WIN32)
+
+# include <windows.h>
+
+static size_t os_getpagesize()
+{
+ SYSTEM_INFO S;
+ GetNativeSystemInfo(&S);
+ return S.dwPageSize;
+}
+
+static void* win_mmap(void* hint,
+ size_t size,
+ int prot,
+ int flags,
+ DWORD alloc_flag)
+{
+ DWORD flProtect = PAGE_NOACCESS;
+ size_t request_size, page_size;
+ void* addr;
+
+ page_size = os_getpagesize();
+ request_size = (size + page_size - 1) & ~(page_size - 1);
+
+ if (request_size < size)
+ /* integer overflow */
+ return NULL;
+
+ if (request_size == 0)
+ request_size = page_size;
+
+ if (prot & MMAP_PROT_EXEC) {
+ if (prot & MMAP_PROT_WRITE)
+ flProtect = PAGE_EXECUTE_READWRITE;
+ else
+ flProtect = PAGE_EXECUTE_READ;
+ } else if (prot & MMAP_PROT_WRITE)
+ flProtect = PAGE_READWRITE;
+ else if (prot & MMAP_PROT_READ)
+ flProtect = PAGE_READONLY;
+
+ addr = VirtualAlloc((LPVOID)hint, request_size, alloc_flag, flProtect);
+ return addr;
+}
+
+static void* os_mmap_aligned(void* addr,
+ size_t requested_length,
+ int prot,
+ int flags,
+ size_t alignment,
+ size_t alignment_offset)
+{
+ size_t padded_length = requested_length + alignment + alignment_offset;
+ uintptr_t unaligned =
+ (uintptr_t)win_mmap(addr, padded_length, prot, flags, MEM_RESERVE);
+
+ if (!unaligned) {
+ return (void*)unaligned;
+ }
+
+ // Round up the next address that has addr % alignment = 0
+ const size_t alignment_corrected = alignment == 0 ? 1 : alignment;
+ uintptr_t aligned_nonoffset =
+ (unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1);
+
+ // Currently offset 0 is aligned according to alignment
+ // Alignment needs to be enforced at the given offset
+ uintptr_t aligned = 0;
+ if ((aligned_nonoffset - alignment_offset) >= unaligned) {
+ aligned = aligned_nonoffset - alignment_offset;
+ } else {
+ aligned = aligned_nonoffset - alignment_offset + alignment;
+ }
+
+ if (aligned == unaligned && padded_length == requested_length) {
+ return (void*)aligned;
+ }
+
+ // Sanity check
+ if (aligned < unaligned ||
+ (aligned + (requested_length - 1)) > (unaligned + (padded_length - 1)) ||
+ (aligned + alignment_offset) % alignment_corrected != 0) {
+ os_munmap((void*)unaligned, padded_length);
+ return NULL;
+ }
+
+ // windows does not support partial unmapping, so unmap and remap
+ os_munmap((void*)unaligned, padded_length);
+ aligned = (uintptr_t)win_mmap(
+ (void*)aligned, requested_length, prot, flags, MEM_RESERVE);
+ return (void*)aligned;
+}
+
+static void os_munmap(void* addr, size_t size)
+{
+ DWORD alloc_flag = MEM_RELEASE;
+ if (addr) {
+ if (VirtualFree(addr, 0, alloc_flag) == 0) {
+ size_t page_size = os_getpagesize();
+ size_t request_size = (size + page_size - 1) & ~(page_size - 1);
+ int64_t curr_err = errno;
+ printf("os_munmap error addr:%p, size:0x%zx, errno:%" PRId64 "\n",
+ addr,
+ request_size,
+ curr_err);
+ }
+ }
+}
+
+static int os_mmap_commit(void* curr_heap_end_pointer,
+ size_t expanded_size,
+ int prot)
+{
+ uintptr_t addr = (uintptr_t)win_mmap(
+ curr_heap_end_pointer, expanded_size, prot, MMAP_MAP_NONE, MEM_COMMIT);
+ int ret = addr ? 0 : -1;
+ return ret;
+}
+
+#elif !defined(_WIN32) && (defined(__unix__) || defined(__unix) || \
+ (defined(__APPLE__) && defined(__MACH__)))
+
+# include <sys/mman.h>
+# include <unistd.h>
+
+static size_t os_getpagesize()
+{
+ return getpagesize();
+}
+
+static void* os_mmap(void* hint, size_t size, int prot, int flags)
+{
+ int map_prot = PROT_NONE;
+ int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
+ uint64_t request_size, page_size;
+ void* addr;
+
+ page_size = (uint64_t)os_getpagesize();
+ request_size = (size + page_size - 1) & ~(page_size - 1);
+
+ if ((size_t)request_size < size)
+ /* integer overflow */
+ return NULL;
+
+ if (request_size > 16 * (uint64_t)UINT32_MAX)
+ /* At most 16 G is allowed */
+ return NULL;
+
+ if (prot & MMAP_PROT_READ)
+ map_prot |= PROT_READ;
+
+ if (prot & MMAP_PROT_WRITE)
+ map_prot |= PROT_WRITE;
+
+ if (prot & MMAP_PROT_EXEC)
+ map_prot |= PROT_EXEC;
+
+# if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64)
+# ifndef __APPLE__
+ if (flags & MMAP_MAP_32BIT)
+ map_flags |= MAP_32BIT;
+# endif
+# endif
+
+ if (flags & MMAP_MAP_FIXED)
+ map_flags |= MAP_FIXED;
+
+ addr = mmap(hint, request_size, map_prot, map_flags, -1, 0);
+
+ if (addr == MAP_FAILED)
+ return NULL;
+
+ return addr;
+}
+
+static void* os_mmap_aligned(void* addr,
+ size_t requested_length,
+ int prot,
+ int flags,
+ size_t alignment,
+ size_t alignment_offset)
+{
+ size_t padded_length = requested_length + alignment + alignment_offset;
+ uintptr_t unaligned = (uintptr_t)os_mmap(addr, padded_length, prot, flags);
+
+ if (!unaligned) {
+ return (void*)unaligned;
+ }
+
+ // Round up the next address that has addr % alignment = 0
+ const size_t alignment_corrected = alignment == 0 ? 1 : alignment;
+ uintptr_t aligned_nonoffset =
+ (unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1);
+
+ // Currently offset 0 is aligned according to alignment
+ // Alignment needs to be enforced at the given offset
+ uintptr_t aligned = 0;
+ if ((aligned_nonoffset - alignment_offset) >= unaligned) {
+ aligned = aligned_nonoffset - alignment_offset;
+ } else {
+ aligned = aligned_nonoffset - alignment_offset + alignment;
+ }
+
+ // Sanity check
+ if (aligned < unaligned ||
+ (aligned + (requested_length - 1)) > (unaligned + (padded_length - 1)) ||
+ (aligned + alignment_offset) % alignment_corrected != 0) {
+ os_munmap((void*)unaligned, padded_length);
+ return NULL;
+ }
+
+ {
+ size_t unused_front = aligned - unaligned;
+ if (unused_front != 0) {
+ os_munmap((void*)unaligned, unused_front);
+ }
+ }
+
+ {
+ size_t unused_back =
+ (unaligned + (padded_length - 1)) - (aligned + (requested_length - 1));
+ if (unused_back != 0) {
+ os_munmap((void*)(aligned + requested_length), unused_back);
+ }
+ }
+
+ return (void*)aligned;
+}
+
+static void os_munmap(void* addr, size_t size)
+{
+ uint64_t page_size = (uint64_t)os_getpagesize();
+ uint64_t request_size = (size + page_size - 1) & ~(page_size - 1);
+
+ if (addr) {
+ if (munmap(addr, request_size)) {
+ printf("os_munmap error addr:%p, size:0x%" PRIx64 ", errno:%d\n",
+ addr,
+ request_size,
+ errno);
+ }
+ }
+}
+
+static int os_mmap_commit(void* addr, size_t size, int prot)
+{
+ int map_prot = PROT_NONE;
+ uint64_t page_size = (uint64_t)os_getpagesize();
+ uint64_t request_size = (size + page_size - 1) & ~(page_size - 1);
+
+ if (!addr)
+ return 0;
+
+ if (prot & MMAP_PROT_READ)
+ map_prot |= PROT_READ;
+
+ if (prot & MMAP_PROT_WRITE)
+ map_prot |= PROT_WRITE;
+
+ if (prot & MMAP_PROT_EXEC)
+ map_prot |= PROT_EXEC;
+
+ return mprotect(addr, request_size, map_prot);
+}
+
+#else
+# error "Unknown OS"
+#endif