Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(756)

Unified Diff: src/nonsfi/linux/irt_signal_handling.c

Issue 1212613002: Non-SFI mode: Add Linux asynchronous signal support (Closed) Base URL: https://chromium.googlesource.com/native_client/src/native_client.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/nonsfi/linux/irt_signal_handling.c
diff --git a/src/nonsfi/linux/irt_signal_handling.c b/src/nonsfi/linux/irt_signal_handling.c
new file mode 100644
index 0000000000000000000000000000000000000000..0953ead52b8a7bbfd3f65201f65c4048c564680e
--- /dev/null
+++ b/src/nonsfi/linux/irt_signal_handling.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2015 The Native Client Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "native_client/src/include/elf_constants.h"
+#include "native_client/src/include/nacl/nacl_exception.h"
+#include "native_client/src/include/nacl_macros.h"
+#include "native_client/src/nonsfi/linux/irt_signal_handling.h"
+#include "native_client/src/nonsfi/linux/linux_sys_private.h"
+#include "native_client/src/nonsfi/linux/linux_syscall_defines.h"
+#include "native_client/src/nonsfi/linux/linux_syscall_structs.h"
+#include "native_client/src/public/linux_syscalls/sys/syscall.h"
+#include "native_client/src/public/nonsfi/irt_signal_handling.h"
+#include "native_client/src/untrusted/irt/irt.h"
+
+typedef struct compat_sigaltstack {
+ uint32_t ss_sp;
+ int32_t ss_flags;
+ uint32_t ss_size;
+} linux_stack_t;
+
+
+/* From linux/arch/arm/include/asm/ucontext.h */
+struct linux_ucontext_t {
+ uint32_t uc_flags;
+ uint32_t uc_link;
+ linux_stack_t uc_stack;
+ linux_mcontext_t uc_mcontext;
+ linux_sigset_t uc_sigmask;
+ /* More data follows which we don't care about. */
+};
+
+pthread_mutex_t g_signal_handler_mutex = PTHREAD_MUTEX_INITIALIZER;
+static NaClExceptionHandler g_signal_handler_function_pointer = NULL;
+static int g_signal_handler_initialized = 0;
+static int g_tgid = 0;
+static int g_main_tid;
+
+static void machine_context_to_register(const linux_mcontext_t *mctx,
+ NaClUserRegisterState *dest) {
+#if defined(__i386__)
+#define COPY_REG(A) dest->e##A = mctx->A
+ COPY_REG(ax);
+ COPY_REG(cx);
+ COPY_REG(dx);
+ COPY_REG(bx);
+ COPY_REG(bp);
+ COPY_REG(si);
+ COPY_REG(di);
+#undef COPY_REG
+ dest->stack_ptr = mctx->sp;
+ dest->prog_ctr = mctx->ip;
+ dest->flags = mctx->flags;
+#elif defined(__arm__)
+#define COPY_REG(A) dest->A = mctx->arm_##A
+ COPY_REG(r0);
+ COPY_REG(r1);
+ COPY_REG(r2);
+ COPY_REG(r3);
+ COPY_REG(r4);
+ COPY_REG(r5);
+ COPY_REG(r6);
+ COPY_REG(r7);
+ COPY_REG(r8);
+ COPY_REG(r9);
+ COPY_REG(r10);
+ COPY_REG(r11);
+ COPY_REG(r12);
+#undef COPY_REG
+ dest->stack_ptr = mctx->arm_sp;
+ dest->lr = mctx->arm_lr;
+ dest->prog_ctr = mctx->arm_pc;
+ dest->cpsr = mctx->arm_cpsr;
+#else
+# error Unsupported architecture
+#endif
+}
+
+void exception_frame_from_signal_context(
+ struct NonSfiExceptionFrame *frame,
+ const void *raw_ctx) {
+ const struct linux_ucontext_t *uctx = (struct linux_ucontext_t *) raw_ctx;
+ const linux_mcontext_t *mctx = &uctx->uc_mcontext;
+ frame->context.size = (((uintptr_t) (&frame->portable + 1))
+ - (uintptr_t) &frame->context);
+ frame->context.portable_context_offset = ((uintptr_t) &frame->portable
+ - (uintptr_t) &frame->context);
+ frame->context.portable_context_size = sizeof(frame->portable);
+ frame->context.regs_size = sizeof(frame->context.regs);
+
+ memset(frame->context.reserved, 0, sizeof(frame->context.reserved));
+ machine_context_to_register(mctx, &frame->context.regs);
+ frame->portable.prog_ctr = frame->context.regs.prog_ctr;
+ frame->portable.stack_ptr = frame->context.regs.stack_ptr;
+
+#if defined(__i386__)
+ frame->context.arch = EM_386;
+ frame->portable.frame_ptr = frame->context.regs.ebp;
+#elif defined(__arm__)
+ frame->context.arch = EM_ARM;
+ /* R11 is frame pointer in ARM mode, R8 is frame pointer in thumb mode. */
+ frame->portable.frame_ptr = frame->context.regs.r11;
+#else
+# error Unsupported architecture
+#endif
+}
+
+/* A replacement of sigreturn. It does not restore the signal mask. */
+static void __attribute__((noreturn))
+_nonsfi_restore_context(const linux_mcontext_t *mctx) {
Junichi Uekawa 2015/07/01 02:14:57 this is not python code, don't prepend function na
Luis Héctor Chávez 2015/07/06 23:44:59 Done.
+
+#if defined(__i386__)
+
+#define OFFSET(name) \
+ [name] "i" (offsetof(linux_mcontext_t, name))
+#define RESTORE_SEGMENT(name) \
+ "mov %c[" #name "](%%eax), %%" #name "\n"
+#define RESTORE(name) \
+ "movl %c[" #name "](%%eax), %%e" #name "\n"
+
+ __asm__ __volatile__(
+ "mov %0, %%eax\n"
+
+ /* Restore floating-point environment */
+ "mov %c[fpstate](%%eax), %%ecx\n"
+ "fldenv (%%ecx)\n"
+
+ /* Restore all segment registers */
+ RESTORE_SEGMENT(gs)
+ RESTORE_SEGMENT(fs)
+ RESTORE_SEGMENT(es)
+ RESTORE_SEGMENT(ds)
+
+ /*
+ * Restore the rest of the registers except for dx, cx (scratch) and ax.
+ */
+ RESTORE(di)
+ RESTORE(si)
+ RESTORE(bp)
+ RESTORE(bx)
+
+ /*
+ * Prepare the last registers. eip, eflags, eax, and ecx should be on the
+ * top of the new stack. Once that is done and esp restored, we can
+ * safely restore them.
+ */
+ "mov %c[sp](%%eax), %%ecx\n"
+ "mov %c[ip](%%eax), %%edx\n"
+ "mov %%edx, -4(%%ecx)\n"
+ "mov %c[flags](%%eax), %%edx\n"
+ "mov %%edx, -8(%%ecx)\n"
+ "mov %c[ax](%%eax), %%edx\n"
+ "mov %%edx, -12(%%ecx)\n"
+ "mov %c[cx](%%eax), %%edx\n"
+ "mov %%edx, -16(%%ecx)\n"
+ RESTORE(dx)
+ "sub $16, %%ecx\n"
+ "mov %%ecx, %%esp\n"
+
+ /*
+ * Finally pop the last registers off the stack and return to
+ * simultaneously restore esp and eip.
+ */
+ "pop %%ecx\n"
+ "pop %%eax\n"
+ "popfd\n"
+ "ret\n"
+ :
+ : "X" (mctx),
+ OFFSET(gs),
+ OFFSET(fs),
+ OFFSET(es),
+ OFFSET(ds),
+ OFFSET(di),
+ OFFSET(si),
+ OFFSET(bp),
+ OFFSET(sp),
+ OFFSET(bx),
+ OFFSET(dx),
+ OFFSET(cx),
+ OFFSET(ax),
+ OFFSET(ip),
+ OFFSET(flags),
+ OFFSET(fpstate)
+ );
+
+#undef OFFSET
+#undef RESTORE
+#undef RESTORE_SEGMENT
+
+#elif defined(__arm__)
+
+ /* TODO(lhchavez): Implement this. */
Junichi Uekawa 2015/07/01 02:14:57 erm... is this required ?
Luis Héctor Chávez 2015/07/06 23:44:59 It is. I wanted to have feedback on the rest of th
+
+#else
+# error Unsupported architecture
+#endif
+
+ /* Should never reach this. */
+ abort();
+}
+
+static __attribute__((noreturn))
+void restore_context(void *raw_ctx) {
+ const struct linux_ucontext_t *uctx = (struct linux_ucontext_t *) raw_ctx;
+ const linux_mcontext_t *mctx = &uctx->uc_mcontext;
+ _nonsfi_restore_context(mctx);
+}
+
+static void signal_catch(int sig, linux_siginfo_t *info, void *uc) {
+ if (g_signal_handler_function_pointer) {
+ struct NonSfiExceptionFrame exception_frame;
+ exception_frame_from_signal_context(&exception_frame, uc);
+ g_signal_handler_function_pointer(&exception_frame.context);
+ }
+ restore_context(uc);
+}
+
+static void nonsfi_install_signal_handler_locked() {
+ struct linux_sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = signal_catch;
+
+ /*
+ * User signal handler can be recursively interrupted to avoid having
+ * to allow sigreturn/sigprocmask.
+ */
+ sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_NODEFER;
+ sigset_t *mask = (sigset_t*)&sa.sa_mask;
+ sigemptyset(mask);
+
+ /*
+ * Install a single handler. Multiple signals can be multiplexed in
+ * userspace.
+ */
+ if (linux_sigaction(LINUX_SIGUSR1, &sa, NULL) != 0)
+ abort();
+}
+
+void nonsfi_initialize_signal_handler_locked() {
+ if (g_signal_handler_initialized)
+ return;
+ nonsfi_install_exception_handler_locked();
+ nonsfi_install_signal_handler_locked();
+ g_tgid = getpid();
+ g_main_tid = syscall(__NR_gettid);
+ g_signal_handler_initialized = 1;
+}
+
+/*
+ * Initialize signal handlers before entering sandbox.
+ */
+void nonsfi_initialize_signal_handler() {
+ if (pthread_mutex_lock(&g_signal_handler_mutex) != 0)
+ abort();
+ nonsfi_initialize_signal_handler_locked();
+ if (pthread_mutex_unlock(&g_signal_handler_mutex) != 0)
+ abort();
+}
+
+int nacl_signal_set_handler(NaClIrtSignalHandler handler) {
+ if (pthread_mutex_lock(&g_signal_handler_mutex) != 0)
+ abort();
+ nonsfi_initialize_signal_handler_locked();
+ g_signal_handler_function_pointer = handler;
+ if (pthread_mutex_unlock(&g_signal_handler_mutex) != 0)
+ abort();
+ return 0;
+}
+
+int nacl_signal_send_async_signal(nacl_irt_tid_t tid) {
+ if (!g_signal_handler_initialized)
+ return ESRCH;
+ if (tid == 0)
+ tid = g_main_tid;
+ if (linux_tgkill(g_tgid, tid, LINUX_SIGUSR1) == -1)
+ return errno;
+ return 0;
+}

Powered by Google App Engine
This is Rietveld 408576698