mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-08-31 19:23:04 +02:00
Remove exceptions from the sandbox implementation in libretro builds
This commit is contained in:
parent
d0b211e239
commit
0d07aff3e2
6 changed files with 84 additions and 108 deletions
|
@ -83,7 +83,7 @@ wasm_ptr_t binding_base::sandbox_malloc(wasm_size_t size) {
|
|||
|
||||
// Verify that the entire allocated buffer is in valid memory
|
||||
wasm_ptr_t buf_end;
|
||||
if (buf == 0 || __builtin_add_overflow(buf, size, &buf_end) || buf_end >= instance().w2c_memory.size) {
|
||||
if (buf == 0 || (buf_end = buf + size) < buf || buf_end >= instance().w2c_memory.size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@ usize sandbox::sandbox_malloc(usize size) {
|
|||
|
||||
// Verify that the returned pointer is non-null and the entire allocated buffer is in valid memory
|
||||
usize buf_end;
|
||||
if (buf == WASM_NULL || __builtin_add_overflow(buf, size, &buf_end) || buf_end >= ruby->w2c_memory.size) {
|
||||
throw SandboxOutOfMemoryException();
|
||||
if (buf == WASM_NULL || (buf_end = buf + size) < buf || buf_end >= ruby->w2c_memory.size) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
@ -58,83 +58,78 @@ void sandbox::sandbox_free(usize ptr) {
|
|||
}
|
||||
|
||||
sandbox::sandbox() : ruby(new struct w2c_ruby), wasi(new wasi_t(ruby)), bindings(ruby), yielding(false), transitioning(false) {
|
||||
try {
|
||||
// Initialize the sandbox
|
||||
wasm2c_ruby_instantiate(RB, wasi.get());
|
||||
w2c_ruby_mkxp_sandbox_init(
|
||||
RB,
|
||||
0, // heap_free_slots
|
||||
1.1, // growth_factor
|
||||
0, // growth_max_slots
|
||||
0, // heap_free_slots_min_ratio
|
||||
0, // heap_free_slots_goal_ratio
|
||||
0, // heap_free_slots_max_ratio
|
||||
0, // uncollectible_wb_unprotected_objects_limit_ratio
|
||||
0, // oldobject_limit_factor
|
||||
1 * 0x100000, // malloc_limit_min
|
||||
4 * 0x100000, // malloc_limit_max
|
||||
1.1, // malloc_limit_growth_factor
|
||||
4 * 0x100000, // oldmalloc_limit_min
|
||||
8 * 0x100000, // oldmalloc_limit_max
|
||||
1.1 // oldmalloc_limit_growth_factor
|
||||
);
|
||||
// Initialize the sandbox
|
||||
wasm2c_ruby_instantiate(RB, wasi.get());
|
||||
w2c_ruby_mkxp_sandbox_init(
|
||||
RB,
|
||||
0, // heap_free_slots
|
||||
1.1, // growth_factor
|
||||
0, // growth_max_slots
|
||||
0, // heap_free_slots_min_ratio
|
||||
0, // heap_free_slots_goal_ratio
|
||||
0, // heap_free_slots_max_ratio
|
||||
0, // uncollectible_wb_unprotected_objects_limit_ratio
|
||||
0, // oldobject_limit_factor
|
||||
1 * 0x100000, // malloc_limit_min
|
||||
4 * 0x100000, // malloc_limit_max
|
||||
1.1, // malloc_limit_growth_factor
|
||||
4 * 0x100000, // oldmalloc_limit_min
|
||||
8 * 0x100000, // oldmalloc_limit_max
|
||||
1.1 // oldmalloc_limit_growth_factor
|
||||
);
|
||||
|
||||
// Determine Ruby command-line arguments
|
||||
std::vector<std::string> args{"mkxp-z"};
|
||||
args.push_back("/mkxp-retro-dist/bin/mkxp-z");
|
||||
if (MJIT_ENABLED) {
|
||||
std::string verboseLevel("--mjit-verbose=");
|
||||
std::string maxCache("--mjit-max-cache=");
|
||||
std::string minCalls("--mjit-min-calls=");
|
||||
args.push_back("--mjit");
|
||||
verboseLevel += std::to_string(MJIT_VERBOSE);
|
||||
maxCache += std::to_string(MJIT_MAX_CACHE);
|
||||
minCalls += std::to_string(MJIT_MIN_CALLS);
|
||||
args.push_back(verboseLevel.c_str());
|
||||
args.push_back(maxCache.c_str());
|
||||
args.push_back(minCalls.c_str());
|
||||
} else if (YJIT_ENABLED) {
|
||||
args.push_back("--yjit");
|
||||
}
|
||||
|
||||
// Copy all the command-line arguments into the sandbox (sandboxed code can't access memory that's outside the sandbox!)
|
||||
usize argv_buf = sandbox_malloc(args.size() * sizeof(usize));
|
||||
for (usize i = 0; i < args.size(); ++i) {
|
||||
usize arg_buf = sandbox_malloc(args[i].length() + 1);
|
||||
std::strcpy((char *)WASM_MEM(arg_buf), args[i].c_str());
|
||||
WASM_SET(usize, argv_buf + i * sizeof(usize), arg_buf);
|
||||
}
|
||||
|
||||
// Pass the command-line arguments to Ruby
|
||||
AWAIT(w2c_ruby_ruby_init_stack(RB, w2c_ruby_rb_wasm_get_stack_pointer(RB)));
|
||||
AWAIT(w2c_ruby_ruby_init(RB));
|
||||
usize node;
|
||||
AWAIT(node = w2c_ruby_ruby_options(RB, args.size(), argv_buf));
|
||||
|
||||
// Start up Ruby executable node
|
||||
bool valid;
|
||||
u32 state;
|
||||
usize state_buf = sandbox_malloc(sizeof(usize));
|
||||
AWAIT(valid = w2c_ruby_ruby_executable_node(RB, node, state_buf));
|
||||
if (valid) {
|
||||
AWAIT(state = w2c_ruby_ruby_exec_node(RB, node));
|
||||
}
|
||||
if (!valid || state) {
|
||||
throw SandboxNodeException();
|
||||
}
|
||||
sandbox_free(state_buf);
|
||||
|
||||
// Set the default encoding to UTF-8
|
||||
usize encoding;
|
||||
AWAIT(encoding = w2c_ruby_rb_utf8_encoding(RB));
|
||||
usize enc;
|
||||
AWAIT(enc = w2c_ruby_rb_enc_from_encoding(RB, encoding));
|
||||
AWAIT(w2c_ruby_rb_enc_set_default_internal(RB, enc));
|
||||
AWAIT(w2c_ruby_rb_enc_set_default_external(RB, enc));
|
||||
} catch (SandboxException &) {
|
||||
wasm2c_ruby_free(RB);
|
||||
throw;
|
||||
// Determine Ruby command-line arguments
|
||||
std::vector<std::string> args{"mkxp-z"};
|
||||
args.push_back("/mkxp-retro-dist/bin/mkxp-z");
|
||||
if (MJIT_ENABLED) {
|
||||
std::string verboseLevel("--mjit-verbose=");
|
||||
std::string maxCache("--mjit-max-cache=");
|
||||
std::string minCalls("--mjit-min-calls=");
|
||||
args.push_back("--mjit");
|
||||
verboseLevel += std::to_string(MJIT_VERBOSE);
|
||||
maxCache += std::to_string(MJIT_MAX_CACHE);
|
||||
minCalls += std::to_string(MJIT_MIN_CALLS);
|
||||
args.push_back(verboseLevel.c_str());
|
||||
args.push_back(maxCache.c_str());
|
||||
args.push_back(minCalls.c_str());
|
||||
} else if (YJIT_ENABLED) {
|
||||
args.push_back("--yjit");
|
||||
}
|
||||
|
||||
// Copy all the command-line arguments into the sandbox (sandboxed code can't access memory that's outside the sandbox!)
|
||||
usize argv_buf = sandbox_malloc(args.size() * sizeof(usize));
|
||||
for (usize i = 0; i < args.size(); ++i) {
|
||||
usize arg_buf = sandbox_malloc(args[i].length() + 1);
|
||||
std::strcpy((char *)WASM_MEM(arg_buf), args[i].c_str());
|
||||
WASM_SET(usize, argv_buf + i * sizeof(usize), arg_buf);
|
||||
}
|
||||
|
||||
// Pass the command-line arguments to Ruby
|
||||
AWAIT(w2c_ruby_ruby_init_stack(RB, w2c_ruby_rb_wasm_get_stack_pointer(RB)));
|
||||
AWAIT(w2c_ruby_ruby_init(RB));
|
||||
usize node;
|
||||
AWAIT(node = w2c_ruby_ruby_options(RB, args.size(), argv_buf));
|
||||
|
||||
// Start up Ruby executable node
|
||||
bool valid;
|
||||
u32 state;
|
||||
usize state_buf = sandbox_malloc(sizeof(usize));
|
||||
AWAIT(valid = w2c_ruby_ruby_executable_node(RB, node, state_buf));
|
||||
if (valid) {
|
||||
AWAIT(state = w2c_ruby_ruby_exec_node(RB, node));
|
||||
}
|
||||
if (!valid || state) {
|
||||
std::abort();
|
||||
}
|
||||
sandbox_free(state_buf);
|
||||
|
||||
// Set the default encoding to UTF-8
|
||||
usize encoding;
|
||||
AWAIT(encoding = w2c_ruby_rb_utf8_encoding(RB));
|
||||
usize enc;
|
||||
AWAIT(enc = w2c_ruby_rb_enc_from_encoding(RB, encoding));
|
||||
AWAIT(w2c_ruby_rb_enc_set_default_internal(RB, enc));
|
||||
AWAIT(w2c_ruby_rb_enc_set_default_external(RB, enc));
|
||||
}
|
||||
|
||||
sandbox::~sandbox() {
|
||||
|
|
|
@ -53,12 +53,4 @@ typedef float f32;
|
|||
typedef double f64;
|
||||
#endif // WASM_RT_CORE_TYPES_DEFINED
|
||||
|
||||
struct SandboxException {};
|
||||
// The call to `ruby_executable_node()` or `ruby_exec_node()` failed when initializing Ruby.
|
||||
struct SandboxNodeException : SandboxException {};
|
||||
// Failed to allocate memory.
|
||||
struct SandboxOutOfMemoryException : SandboxException {};
|
||||
// An exception occurred inside of Ruby and was not caught.
|
||||
struct SandboxTrapException : SandboxException {};
|
||||
|
||||
#endif // MKXPZ_SANDBOX_TYPES_H
|
||||
|
|
|
@ -805,7 +805,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_poll_oneoff(wasi_t *wasi, usize in,
|
|||
|
||||
extern "C" void w2c_wasi__snapshot__preview1_proc_exit(wasi_t *wasi, u32 rval) {
|
||||
WASI_DEBUG("proc_exit(%u)\n", rval);
|
||||
throw SandboxTrapException();
|
||||
std::abort();
|
||||
}
|
||||
|
||||
extern "C" u32 w2c_wasi__snapshot__preview1_random_get(wasi_t *wasi, usize buf, u32 buf_len) {
|
||||
|
|
|
@ -291,7 +291,7 @@ PRELUDE = <<~HEREDOC
|
|||
bindings::rb_data_type::rb_data_type(wasm_ptr_t ptr) : ptr(ptr) {}
|
||||
|
||||
wasm_ptr_t bindings::rb_data_type::get() const {
|
||||
if (ptr == 0) throw SandboxTrapException();
|
||||
if (ptr == 0) std::abort();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
@ -309,12 +309,12 @@ POSTSCRIPT = <<~HEREDOC
|
|||
|
||||
buf = sandbox_malloc(9 * sizeof(wasm_ptr_t));
|
||||
if (buf == 0) {
|
||||
throw SandboxOutOfMemoryException();
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
str = sandbox_malloc(std::strlen(wrap_struct_name) + 1);
|
||||
if (str == 0) {
|
||||
sandbox_free(buf);
|
||||
throw SandboxOutOfMemoryException();
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
std::strcpy((char *)(**this + str), wrap_struct_name);
|
||||
|
@ -480,7 +480,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
end
|
||||
coroutine_initializer += <<~HEREDOC
|
||||
default:
|
||||
throw SandboxTrapException();
|
||||
std::abort();
|
||||
}
|
||||
HEREDOC
|
||||
else
|
||||
|
@ -498,7 +498,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
elsif !handler[:buf_size].nil?
|
||||
coroutine_initializer += <<~HEREDOC
|
||||
f#{i} = bind.sandbox_malloc(#{handler[:buf_size].gsub('PREV_ARG', "a#{i - 1}").gsub('ARG', "a#{i}")});
|
||||
if (f#{i} == 0) throw SandboxOutOfMemoryException();
|
||||
if (f#{i} == 0) throw std::bad_alloc();
|
||||
HEREDOC
|
||||
coroutine_initializer += handler[:serialize].gsub('PREV_ARG', "a#{i - 1}").gsub('ARG', "a#{i}").gsub('BUF', "f#{i}")
|
||||
coroutine_initializer += "\n"
|
||||
|
@ -523,7 +523,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
fp = w2c_ruby_rb_wasm_get_stack_pointer(&bind.instance());
|
||||
sp = fp - CEIL_WASMSTACKALIGN(a#{args.length - 2} * sizeof(VALUE));
|
||||
if (sp > fp) {
|
||||
throw SandboxOutOfMemoryException();
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
w2c_ruby_rb_wasm_set_stack_pointer(&bind.instance(), sp);
|
||||
std::va_list a;
|
||||
|
@ -550,7 +550,7 @@ File.readlines('tags', chomp: true).each do |line|
|
|||
fp = w2c_ruby_rb_wasm_get_stack_pointer(&bind.instance());
|
||||
sp = fp - CEIL_WASMSTACKALIGN(n * sizeof(VALUE));
|
||||
if (sp > fp) {
|
||||
throw SandboxOutOfMemoryException();
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
w2c_ruby_rb_wasm_set_stack_pointer(&bind.instance(), sp);
|
||||
for (wasm_size_t i = 0; i < n; ++i) {
|
||||
|
|
17
src/core.cpp
17
src/core.cpp
|
@ -320,13 +320,7 @@ static bool init_sandbox() {
|
|||
|
||||
audio.emplace(*thread_data);
|
||||
|
||||
try {
|
||||
mkxp_retro::sandbox.emplace();
|
||||
} catch (SandboxException) {
|
||||
log_printf(RETRO_LOG_ERROR, "Failed to initialize Ruby\n");
|
||||
deinit_sandbox();
|
||||
return false;
|
||||
}
|
||||
mkxp_retro::sandbox.emplace();
|
||||
|
||||
{
|
||||
float refresh_rate;
|
||||
|
@ -467,13 +461,8 @@ extern "C" RETRO_API void retro_run() {
|
|||
}
|
||||
|
||||
if (should_render) {
|
||||
try {
|
||||
if (sb().run<struct main>()) {
|
||||
log_printf(RETRO_LOG_INFO, "[Sandbox] Ruby terminated normally\n");
|
||||
deinit_sandbox();
|
||||
}
|
||||
} catch (SandboxException) {
|
||||
log_printf(RETRO_LOG_ERROR, "[Sandbox] Ruby threw an exception\n");
|
||||
if (sb().run<struct main>()) {
|
||||
log_printf(RETRO_LOG_INFO, "[Sandbox] Ruby terminated normally\n");
|
||||
deinit_sandbox();
|
||||
}
|
||||
} else if (!dupe_supported && mkxp_retro::sandbox.has_value()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue