diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 452cf242..14a71c15 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -182,3 +182,7 @@ jobs: run: | make -f test.mk trap_divzero if: success() || failure() + - name: Wasm Trap Stack Overflow + run: | + make -f test.mk stack_overflow + if: success() || failure() diff --git a/applications/Makefile b/applications/Makefile index d243c70d..3b0a5256 100644 --- a/applications/Makefile +++ b/applications/Makefile @@ -82,3 +82,6 @@ license_plate_detection.install: ../runtime/bin/license_plate_detection.wasm.so .PHONY: trap_divzero.install trap_divzero.install: ../runtime/bin/trap_divzero.wasm.so + +.PHONY: stack_overflow.install +stack_overflow.install: ../runtime/bin/stack_overflow.wasm.so diff --git a/applications/wasm_apps b/applications/wasm_apps index 8a97541b..f6d07455 160000 --- a/applications/wasm_apps +++ b/applications/wasm_apps @@ -1 +1 @@ -Subproject commit 8a97541b83373b5f30306f569515326dee4c1f2a +Subproject commit f6d07455676a1a5cb64b03276c9b4985ef721451 diff --git a/libsledge/src/memory_instructions.c b/libsledge/src/memory_instructions.c index bf36bdfb..2e8be909 100644 --- a/libsledge/src/memory_instructions.c +++ b/libsledge/src/memory_instructions.c @@ -19,11 +19,6 @@ get_f32(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(float) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - return *(float *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -32,11 +27,6 @@ get_f64(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(double) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - return *(double *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -45,11 +35,6 @@ get_i8(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(int8_t) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - return *(int8_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -58,11 +43,6 @@ get_i16(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(int16_t) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - return *(int16_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -71,11 +51,6 @@ get_i32(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(int32_t) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - return *(int32_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -84,11 +59,6 @@ get_i64(uint32_t offset) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(int64_t) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - return *(int64_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset]; } @@ -98,11 +68,6 @@ set_f32(uint32_t offset, float value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(float) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - *(float *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -111,11 +76,6 @@ set_f64(uint32_t offset, double value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(double) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - *(double *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -124,11 +84,6 @@ set_i8(uint32_t offset, int8_t value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(int8_t) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - *(int8_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -137,11 +92,6 @@ set_i16(uint32_t offset, int16_t value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(int16_t) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - *(int16_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -150,11 +100,6 @@ set_i32(uint32_t offset, int32_t value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(int32_t) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - *(int32_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } @@ -163,11 +108,6 @@ set_i64(uint32_t offset, int64_t value) { assert(sledge_abi__current_wasm_module_instance.memory.buffer != NULL); - if (unlikely((uint64_t)offset + (uint64_t)sizeof(int64_t) - > sledge_abi__current_wasm_module_instance.memory.size)) { - sledge_abi__wasm_trap_raise(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); - } - *(int64_t *)&sledge_abi__current_wasm_module_instance.memory.buffer[offset] = value; } diff --git a/runtime/include/software_interrupt.h b/runtime/include/software_interrupt.h index f1e8d871..e1f048c5 100644 --- a/runtime/include/software_interrupt.h +++ b/runtime/include/software_interrupt.h @@ -31,7 +31,7 @@ software_interrupt_mask_signal(int signal) sigset_t set; int return_code; - assert(signal == SIGALRM || signal == SIGUSR1 || signal == SIGFPE); + assert(signal == SIGALRM || signal == SIGUSR1 || signal == SIGFPE || signal == SIGSEGV); /* all threads created by the calling thread will have signal blocked */ sigemptyset(&set); sigaddset(&set, signal); @@ -55,7 +55,7 @@ software_interrupt_unmask_signal(int signal) sigset_t set; int return_code; - assert(signal == SIGALRM || signal == SIGUSR1 || signal == SIGFPE); + assert(signal == SIGALRM || signal == SIGUSR1 || signal == SIGFPE || signal == SIGSEGV); /* all threads created by the calling thread will have signal unblocked */ sigemptyset(&set); sigaddset(&set, signal); diff --git a/runtime/include/software_interrupt_counts.h b/runtime/include/software_interrupt_counts.h index 88840e78..9daa5afe 100644 --- a/runtime/include/software_interrupt_counts.h +++ b/runtime/include/software_interrupt_counts.h @@ -11,6 +11,7 @@ extern _Atomic volatile sig_atomic_t *software_interrupt_counts_deferred_sigalrm extern _Atomic volatile sig_atomic_t *software_interrupt_counts_sigalrm_kernel; extern _Atomic volatile sig_atomic_t *software_interrupt_counts_sigalrm_thread; extern _Atomic volatile sig_atomic_t *software_interrupt_counts_sigfpe; +extern _Atomic volatile sig_atomic_t *software_interrupt_counts_sigsegv; extern _Atomic volatile sig_atomic_t *software_interrupt_counts_sigusr; static inline void @@ -22,6 +23,7 @@ software_interrupt_counts_alloc() software_interrupt_counts_sigalrm_kernel = calloc(runtime_worker_threads_count, sizeof(sig_atomic_t)); software_interrupt_counts_sigalrm_thread = calloc(runtime_worker_threads_count, sizeof(sig_atomic_t)); software_interrupt_counts_sigfpe = calloc(runtime_worker_threads_count, sizeof(sig_atomic_t)); + software_interrupt_counts_sigsegv = calloc(runtime_worker_threads_count, sizeof(sig_atomic_t)); software_interrupt_counts_sigusr = calloc(runtime_worker_threads_count, sizeof(sig_atomic_t)); #endif } @@ -35,6 +37,7 @@ software_interrupt_counts_free() free((void *)software_interrupt_counts_sigalrm_kernel); free((void *)software_interrupt_counts_sigalrm_thread); free((void *)software_interrupt_counts_sigfpe); + free((void *)software_interrupt_counts_sigsegv); free((void *)software_interrupt_counts_sigusr); #endif } @@ -81,6 +84,14 @@ software_interrupt_counts_sigfpe_increment() #endif } +static inline void +software_interrupt_counts_sigsegv_increment() +{ +#ifdef LOG_SOFTWARE_INTERRUPT_COUNTS + atomic_fetch_add(&software_interrupt_counts_sigsegv[worker_thread_idx], 1); +#endif +} + static inline void software_interrupt_counts_sigusr_increment() { diff --git a/runtime/src/software_interrupt.c b/runtime/src/software_interrupt.c index 4a530dad..a61ab2a2 100644 --- a/runtime/src/software_interrupt.c +++ b/runtime/src/software_interrupt.c @@ -156,12 +156,23 @@ software_interrupt_handle_signals(int signal_type, siginfo_t *signal_info, void atomic_fetch_sub(&handler_depth, 1); current_sandbox_trap(WASM_TRAP_ILLEGAL_ARITHMETIC_OPERATION); } else { - // Runtime FPE panic("Runtime SIGFPE\n"); } break; } + case SIGSEGV: { + software_interrupt_counts_sigsegv_increment(); + + if (likely(current_sandbox && current_sandbox->state == SANDBOX_RUNNING_USER)) { + atomic_fetch_sub(&handler_depth, 1); + current_sandbox_trap(WASM_TRAP_OUT_OF_BOUNDS_LINEAR_MEMORY); + } else { + panic("Runtime SIGSEGV\n"); + } + + break; + } default: { const char *signal_name = strsignal(signal_type); switch (signal_info->si_code) { @@ -245,9 +256,10 @@ software_interrupt_initialize(void) sigaddset(&signal_action.sa_mask, SIGALRM); sigaddset(&signal_action.sa_mask, SIGUSR1); sigaddset(&signal_action.sa_mask, SIGFPE); + sigaddset(&signal_action.sa_mask, SIGSEGV); - const int supported_signals[] = { SIGALRM, SIGUSR1, SIGFPE }; - const size_t supported_signals_len = 3; + const int supported_signals[] = { SIGALRM, SIGUSR1, SIGFPE, SIGSEGV }; + const size_t supported_signals_len = 4; for (int i = 0; i < supported_signals_len; i++) { int signal = supported_signals[i]; diff --git a/runtime/src/worker_thread.c b/runtime/src/worker_thread.c index e89c2b7d..b1399cbf 100644 --- a/runtime/src/worker_thread.c +++ b/runtime/src/worker_thread.c @@ -60,6 +60,7 @@ worker_thread_main(void *argument) if (unlikely(worker_thread_epoll_file_descriptor < 0)) panic_err(); software_interrupt_unmask_signal(SIGFPE); + software_interrupt_unmask_signal(SIGSEGV); /* Unmask signals, unless the runtime has disabled preemption */ if (runtime_preemption_enabled) { diff --git a/test.mk b/test.mk index bc237d4a..fc953a5c 100755 --- a/test.mk +++ b/test.mk @@ -122,6 +122,13 @@ PHONY: trap_divzero trap_divzero: ./runtime/bin/trap_divzero.wasm.so cd ./tests/traps/ && ./run.sh +./runtime/bin/stack_overflow.wasm.so: + make stack_overflow.install -C ./applications + +PHONY: stack_overflow +stack_overflow: ./runtime/bin/stack_overflow.wasm.so + cd ./tests/stack_overflow/ && ./run.sh + all: \ gocr__all \ ekf__all \ diff --git a/tests/stack_overflow/.gitignore b/tests/stack_overflow/.gitignore new file mode 100644 index 00000000..723e9af7 --- /dev/null +++ b/tests/stack_overflow/.gitignore @@ -0,0 +1,4 @@ +*res.dat +rt.log +log.csv +res/* diff --git a/tests/stack_overflow/Makefile b/tests/stack_overflow/Makefile new file mode 100644 index 00000000..14e8ca98 --- /dev/null +++ b/tests/stack_overflow/Makefile @@ -0,0 +1,38 @@ +RUNTIME_DIR=../../runtime/ +SLEDGE_BINARY_DIR=${RUNTIME_DIR}/bin +SLEDGE_TESTS_DIR=${RUNTIME_DIR}/tests +HOSTNAME=localhost +DURATION_SEC=15 + +all: run + +clean: + make -C ${RUNTIME_DIR} clean + make -C ${SLEDGE_TESTS_DIR} clean + rm -f ${SLEDGE_BINARY_DIR}/stack_overflow.wasm.so + +${SLEDGE_BINARY_DIR}/sledgert: + make -C ${RUNTIME_DIR} runtime + +.PHONY: sledgert +sledgert: ${SLEDGE_BINARY_DIR}/sledgert + +${SLEDGE_BINARY_DIR}/stack_overflow.wasm.so: + make -C ../../applications stack_overflow.install + +.PHONY: stack_overflow +stack_overflow: ${SLEDGE_BINARY_DIR}/stack_overflow.wasm.so + +run: sledgert stack_overflow + LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} ${SLEDGE_BINARY_DIR}/sledgert spec.json + +debug: sledgert stack_overflow + SLEDGE_DISABLE_PREEMPTION=true SLEDGE_NWORKERS=1 \ + LD_LIBRARY_PATH=${SLEDGE_BINARY_DIR} gdb ${SLEDGE_BINARY_DIR}/sledgert \ + --eval-command="handle SIGUSR1 noprint nostop" \ + --eval-command="handle SIGPIPE noprint nostop" \ + --eval-command="set pagination off" \ + --eval-command="run spec.json" + +client: + http :10000 diff --git a/tests/stack_overflow/edf_nopreemption.env b/tests/stack_overflow/edf_nopreemption.env new file mode 100644 index 00000000..eeba531f --- /dev/null +++ b/tests/stack_overflow/edf_nopreemption.env @@ -0,0 +1,2 @@ +SLEDGE_SCHEDULER=EDF +SLEDGE_DISABLE_PREEMPTION=true diff --git a/tests/stack_overflow/edf_preemption.env b/tests/stack_overflow/edf_preemption.env new file mode 100644 index 00000000..302a324d --- /dev/null +++ b/tests/stack_overflow/edf_preemption.env @@ -0,0 +1,3 @@ +SLEDGE_SCHEDULER=EDF +SLEDGE_DISABLE_PREEMPTION=false +SLEDGE_SIGALRM_HANDLER=TRIAGED diff --git a/tests/stack_overflow/fifo_nopreemption.env b/tests/stack_overflow/fifo_nopreemption.env new file mode 100644 index 00000000..a572a700 --- /dev/null +++ b/tests/stack_overflow/fifo_nopreemption.env @@ -0,0 +1,2 @@ +SLEDGE_SCHEDULER=FIFO +SLEDGE_DISABLE_PREEMPTION=true diff --git a/tests/stack_overflow/fifo_preemption.env b/tests/stack_overflow/fifo_preemption.env new file mode 100644 index 00000000..eb1298f1 --- /dev/null +++ b/tests/stack_overflow/fifo_preemption.env @@ -0,0 +1,2 @@ +SLEDGE_SCHEDULER=FIFO +SLEDGE_DISABLE_PREEMPTION=false diff --git a/tests/stack_overflow/run.sh b/tests/stack_overflow/run.sh new file mode 100755 index 00000000..15305596 --- /dev/null +++ b/tests/stack_overflow/run.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +__run_sh__base_path="$(dirname "$(realpath --logical "${BASH_SOURCE[0]}")")" +__run_sh__bash_libraries_relative_path="../bash_libraries" +__run_sh__bash_libraries_absolute_path=$(cd "$__run_sh__base_path" && cd "$__run_sh__bash_libraries_relative_path" && pwd) +export PATH="$__run_sh__bash_libraries_absolute_path:$PATH" + +source framework.sh || exit 1 +source validate_dependencies.sh || exit 1 + +experiment_client() { + local -r hostname="$1" + + for ((i = 1; i <= 10; i++)); do + http -p h "${hostname}:10000" | grep 500 || { + echo "FAIL" + return 1 + } + done + + echo "SUCCESS" + return 0 + +} + +validate_dependencies http + +framework_init "$@" diff --git a/tests/stack_overflow/spec.json b/tests/stack_overflow/spec.json new file mode 100644 index 00000000..a9a86950 --- /dev/null +++ b/tests/stack_overflow/spec.json @@ -0,0 +1,13 @@ +[ + { + "name": "stack_overflow", + "path": "stack_overflow.wasm.so", + "port": 10000, + "expected-execution-us": 10000000, + "admissions-percentile": 70, + "relative-deadline-us": 20000000, + "http-req-size": 1024, + "http-resp-size": 1024, + "http-resp-content-type": "text/plain" + } +]