You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
6.3 KiB
224 lines
6.3 KiB
#include <assert.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "current_sandbox.h"
|
|
#include "debuglog.h"
|
|
#include "panic.h"
|
|
#include "pool.h"
|
|
#include "runtime.h"
|
|
#include "sandbox_functions.h"
|
|
#include "sandbox_set_as_error.h"
|
|
#include "sandbox_set_as_initialized.h"
|
|
#include "sandbox_set_as_allocated.h"
|
|
#include "sandbox_total.h"
|
|
#include "wasm_memory.h"
|
|
#include "wasm_stack.h"
|
|
|
|
_Atomic uint32_t sandbox_total = 0;
|
|
|
|
static inline void
|
|
sandbox_log_allocation(struct sandbox *sandbox)
|
|
{
|
|
#ifdef LOG_SANDBOX_ALLOCATION
|
|
debuglog("Sandbox %lu: of %s:%d\n", sandbox->id, sandbox->module->name, sandbox->module->port);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Allocates a WebAssembly linear memory for a sandbox based on the starting_pages and max_pages globals present in
|
|
* the associated *.so module
|
|
* @param sandbox sandbox that we want to allocate a linear memory for
|
|
* @returns 0 on success, -1 on error
|
|
*/
|
|
static inline int
|
|
sandbox_allocate_linear_memory(struct sandbox *sandbox)
|
|
{
|
|
assert(sandbox != NULL);
|
|
sandbox->memory = module_allocate_linear_memory(sandbox->module);
|
|
if (unlikely(sandbox->memory == NULL)) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int
|
|
sandbox_allocate_stack(struct sandbox *sandbox)
|
|
{
|
|
assert(sandbox);
|
|
assert(sandbox->module);
|
|
|
|
sandbox->stack = module_allocate_stack(sandbox->module);
|
|
if (sandbox->stack == NULL) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline int
|
|
sandbox_allocate_globals(struct sandbox *sandbox)
|
|
{
|
|
assert(sandbox);
|
|
assert(sandbox->module);
|
|
|
|
return wasm_globals_init(&sandbox->globals, sandbox->module->abi.globals_len);
|
|
}
|
|
|
|
static inline void
|
|
sandbox_free_globals(struct sandbox *sandbox)
|
|
{
|
|
assert(sandbox);
|
|
assert(sandbox->module);
|
|
assert(sandbox->globals.buffer != NULL);
|
|
|
|
wasm_globals_deinit(&sandbox->globals);
|
|
}
|
|
|
|
static inline void
|
|
sandbox_free_stack(struct sandbox *sandbox)
|
|
{
|
|
assert(sandbox);
|
|
|
|
return module_free_stack(sandbox->module, sandbox->stack);
|
|
}
|
|
|
|
/**
|
|
* Allocates HTTP buffers and performs our approximation of "WebAssembly instantiation"
|
|
* @param sandbox
|
|
* @returns 0 on success, -1 on error
|
|
*/
|
|
int
|
|
sandbox_prepare_execution_environment(struct sandbox *sandbox)
|
|
{
|
|
assert(sandbox != NULL);
|
|
|
|
char *error_message = "";
|
|
|
|
int rc;
|
|
|
|
rc = sandbox_allocate_globals(sandbox);
|
|
if (rc < 0) {
|
|
error_message = "failed to allocate globals";
|
|
goto err_globals_allocation_failed;
|
|
}
|
|
|
|
/* Allocate linear memory in a 4GB address space */
|
|
if (sandbox_allocate_linear_memory(sandbox)) {
|
|
error_message = "failed to allocate sandbox linear memory";
|
|
goto err_memory_allocation_failed;
|
|
}
|
|
|
|
/* Allocate the Stack */
|
|
if (sandbox_allocate_stack(sandbox) < 0) {
|
|
error_message = "failed to allocate sandbox stack";
|
|
goto err_stack_allocation_failed;
|
|
}
|
|
|
|
/* Initialize the sandbox's context, stack, and instruction pointer */
|
|
/* stack grows down, so set to high address */
|
|
arch_context_init(&sandbox->ctxt, (reg_t)current_sandbox_start, (reg_t)sandbox->stack->high);
|
|
|
|
rc = 0;
|
|
done:
|
|
return rc;
|
|
err_stack_allocation_failed:
|
|
err_memory_allocation_failed:
|
|
err_globals_allocation_failed:
|
|
err_http_allocation_failed:
|
|
http_session_send_err_oneshot(sandbox->http, 503);
|
|
http_session_close(sandbox->http);
|
|
sandbox_set_as_error(sandbox, SANDBOX_ALLOCATED);
|
|
perror(error_message);
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
void
|
|
sandbox_init(struct sandbox *sandbox, struct module *module, int socket_descriptor,
|
|
const struct sockaddr *socket_address, uint64_t request_arrival_timestamp, uint64_t admissions_estimate)
|
|
{
|
|
/* Sets the ID to the value before the increment */
|
|
sandbox->id = sandbox_total_postfix_increment();
|
|
sandbox->module = module;
|
|
module_acquire(sandbox->module);
|
|
|
|
/* Initialize Parsec control structures */
|
|
ps_list_init_d(sandbox);
|
|
|
|
/* Allocate HTTP session structure */
|
|
sandbox->http = http_session_alloc(sandbox->module->max_request_size, sandbox->module->max_response_size,
|
|
socket_descriptor, socket_address);
|
|
assert(sandbox->http);
|
|
|
|
sandbox->timestamp_of.request_arrival = request_arrival_timestamp;
|
|
sandbox->absolute_deadline = request_arrival_timestamp + module->relative_deadline;
|
|
|
|
/*
|
|
* Admissions Control State
|
|
* Assumption: an estimate of 0 should have been interpreted as a rejection
|
|
*/
|
|
assert(admissions_estimate != 0);
|
|
sandbox->admissions_estimate = admissions_estimate;
|
|
|
|
sandbox_log_allocation(sandbox);
|
|
sandbox_set_as_initialized(sandbox, SANDBOX_ALLOCATED);
|
|
}
|
|
|
|
/**
|
|
* Allocates a new Sandbox Request and places it on the Global Deque
|
|
* @param module the module we want to request
|
|
* @param socket_descriptor
|
|
* @param socket_address
|
|
* @param request_arrival_timestamp the timestamp of when we receives the request from the network (in cycles)
|
|
* @param admissions_estimate the timestamp of when we receives the request from the network (in cycles)
|
|
* @return the new sandbox request
|
|
*/
|
|
struct sandbox *
|
|
sandbox_alloc(struct module *module, int socket_descriptor, const struct sockaddr *socket_address,
|
|
uint64_t request_arrival_timestamp, uint64_t admissions_estimate)
|
|
{
|
|
struct sandbox *sandbox = NULL;
|
|
size_t page_aligned_sandbox_size = round_up_to_page(sizeof(struct sandbox));
|
|
sandbox = aligned_alloc(PAGE_SIZE, page_aligned_sandbox_size);
|
|
memset(sandbox, 0, page_aligned_sandbox_size);
|
|
if (unlikely(sandbox == NULL)) return NULL;
|
|
|
|
sandbox_set_as_allocated(sandbox);
|
|
sandbox_init(sandbox, module, socket_descriptor, socket_address, request_arrival_timestamp,
|
|
admissions_estimate);
|
|
|
|
|
|
return sandbox;
|
|
}
|
|
|
|
void
|
|
sandbox_deinit(struct sandbox *sandbox)
|
|
{
|
|
assert(sandbox != NULL);
|
|
assert(sandbox != current_sandbox_get());
|
|
assert(sandbox->state == SANDBOX_ERROR || sandbox->state == SANDBOX_COMPLETE);
|
|
|
|
module_release(sandbox->module);
|
|
|
|
/* HTTP Session was already deinited, freed, and set to NULL */
|
|
/* Linear Memory and Guard Page should already have been munmaped and set to NULL */
|
|
assert(sandbox->memory == NULL);
|
|
|
|
if (likely(sandbox->stack != NULL)) sandbox_free_stack(sandbox);
|
|
|
|
if (likely(sandbox->globals.buffer != NULL)) sandbox_free_globals(sandbox);
|
|
}
|
|
|
|
/**
|
|
* Free stack and heap resources.. also any I/O handles.
|
|
* @param sandbox
|
|
*/
|
|
void
|
|
sandbox_free(struct sandbox *sandbox)
|
|
{
|
|
assert(sandbox != NULL);
|
|
assert(sandbox != current_sandbox_get());
|
|
assert(sandbox->state == SANDBOX_ERROR || sandbox->state == SANDBOX_COMPLETE);
|
|
|
|
sandbox_deinit(sandbox);
|
|
free(sandbox);
|
|
}
|