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

Side by Side Diff: src/nonsfi/linux/irt_signal_handling.c

Issue 1300883003: Revert of 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, 4 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 unified diff | Download patch
« no previous file with comments | « src/nonsfi/linux/irt_signal_handling.h ('k') | src/nonsfi/linux/linux_pthread_private.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2015 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 #include <errno.h>
8 #include <pthread.h>
9 #include <signal.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include "native_client/src/include/elf_constants.h"
15 #include "native_client/src/include/nacl/nacl_exception.h"
16 #include "native_client/src/include/nacl_macros.h"
17 #include "native_client/src/nonsfi/linux/irt_signal_handling.h"
18 #include "native_client/src/nonsfi/linux/linux_sys_private.h"
19 #include "native_client/src/nonsfi/linux/linux_syscall_defines.h"
20 #include "native_client/src/nonsfi/linux/linux_syscall_structs.h"
21 #include "native_client/src/public/linux_syscalls/sys/syscall.h"
22 #include "native_client/src/public/nonsfi/irt_signal_handling.h"
23 #include "native_client/src/untrusted/irt/irt.h"
24
25 typedef struct compat_sigaltstack {
26 uint32_t ss_sp;
27 int32_t ss_flags;
28 uint32_t ss_size;
29 } linux_stack_t;
30
31 #if defined(__i386__)
32
33 /* From linux/arch/x86/include/uapi/asm/sigcontext32.h */
34 struct sigcontext_ia32 {
35 uint16_t gs, __gsh;
36 uint16_t fs, __fsh;
37 uint16_t es, __esh;
38 uint16_t ds, __dsh;
39 uint32_t di;
40 uint32_t si;
41 uint32_t bp;
42 uint32_t sp;
43 uint32_t bx;
44 uint32_t dx;
45 uint32_t cx;
46 uint32_t ax;
47 uint32_t trapno;
48 uint32_t err;
49 uint32_t ip;
50 uint16_t cs, __csh;
51 uint32_t flags;
52 uint32_t sp_at_signal;
53 uint16_t ss, __ssh;
54 uint32_t fpstate;
55 uint32_t oldmask;
56 uint32_t cr2;
57 };
58
59 typedef struct sigcontext_ia32 linux_mcontext_t;
60
61 #elif defined(__arm__)
62
63 /* From linux/arch/arm/include/uapi/asm/sigcontext.h */
64 struct sigcontext_arm {
65 uint32_t trap_no;
66 uint32_t error_code;
67 uint32_t oldmask;
68 uint32_t arm_r0;
69 uint32_t arm_r1;
70 uint32_t arm_r2;
71 uint32_t arm_r3;
72 uint32_t arm_r4;
73 uint32_t arm_r5;
74 uint32_t arm_r6;
75 uint32_t arm_r7;
76 uint32_t arm_r8;
77 uint32_t arm_r9;
78 uint32_t arm_r10;
79 uint32_t arm_r11; /* fp */
80 uint32_t arm_r12; /* ip */
81 uint32_t arm_sp;
82 uint32_t arm_lr;
83 uint32_t arm_pc;
84 uint32_t arm_cpsr;
85 uint32_t fault_address;
86 };
87
88 typedef struct sigcontext_arm linux_mcontext_t;
89
90 #else
91 #error "unsupported architecture"
92 #endif
93
94 /* From linux/arch/arm/include/asm/ucontext.h */
95 struct linux_ucontext_t {
96 uint32_t uc_flags;
97 uint32_t uc_link;
98 linux_stack_t uc_stack;
99 linux_mcontext_t uc_mcontext;
100 linux_sigset_t uc_sigmask;
101 /* More data follows which we don't care about. */
102 };
103
104 /*
105 * Crash signals to handle. The differences from SFI NaCl are that
106 * NonSFI NaCl does not use NACL_THREAD_SUSPEND_SIGNAL (==SIGUSR1),
107 */
108 static const int kSignals[] = {
109 LINUX_SIGSTKFLT,
110 LINUX_SIGINT, LINUX_SIGQUIT, LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGBUS,
111 LINUX_SIGFPE, LINUX_SIGSEGV,
112 /* Handle SIGABRT in case someone sends it asynchronously using kill(). */
113 LINUX_SIGABRT,
114 };
115
116 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
117 static NaClExceptionHandler g_signal_handler_function_pointer = NULL;
118 static NaClExceptionHandler g_exception_handler_function_pointer = NULL;
119 static int g_signal_handler_initialized = 0;
120 static int g_tgid = 0;
121 static int g_main_tid;
122
123 struct NonSfiExceptionFrame {
124 struct NaClExceptionContext context;
125 struct NaClExceptionPortableContext portable;
126 };
127
128 static void machine_context_to_register(const linux_mcontext_t *mctx,
129 NaClUserRegisterState *dest) {
130 #if defined(__i386__)
131 #define COPY_REG(A) dest->e##A = mctx->A
132 COPY_REG(ax);
133 COPY_REG(cx);
134 COPY_REG(dx);
135 COPY_REG(bx);
136 COPY_REG(bp);
137 COPY_REG(si);
138 COPY_REG(di);
139 #undef COPY_REG
140 dest->stack_ptr = mctx->sp;
141 dest->prog_ctr = mctx->ip;
142 dest->flags = mctx->flags;
143 #elif defined(__arm__)
144 #define COPY_REG(A) dest->A = mctx->arm_##A
145 COPY_REG(r0);
146 COPY_REG(r1);
147 COPY_REG(r2);
148 COPY_REG(r3);
149 COPY_REG(r4);
150 COPY_REG(r5);
151 COPY_REG(r6);
152 COPY_REG(r7);
153 COPY_REG(r8);
154 COPY_REG(r9);
155 COPY_REG(r10);
156 COPY_REG(r11);
157 COPY_REG(r12);
158 #undef COPY_REG
159 dest->stack_ptr = mctx->arm_sp;
160 dest->lr = mctx->arm_lr;
161 dest->prog_ctr = mctx->arm_pc;
162 dest->cpsr = mctx->arm_cpsr;
163 #else
164 # error Unsupported architecture
165 #endif
166 }
167
168 static void nonsfi_exception_frame_from_signal_context(
169 struct NonSfiExceptionFrame *frame,
170 const void *raw_ctx) {
171 const struct linux_ucontext_t *uctx = (struct linux_ucontext_t *) raw_ctx;
172 const linux_mcontext_t *mctx = &uctx->uc_mcontext;
173 frame->context.size = (((uintptr_t) (&frame->portable + 1))
174 - (uintptr_t) &frame->context);
175 frame->context.portable_context_offset = ((uintptr_t) &frame->portable
176 - (uintptr_t) &frame->context);
177 frame->context.portable_context_size = sizeof(frame->portable);
178 frame->context.regs_size = sizeof(frame->context.regs);
179
180 memset(frame->context.reserved, 0, sizeof(frame->context.reserved));
181 machine_context_to_register(mctx, &frame->context.regs);
182 frame->portable.prog_ctr = frame->context.regs.prog_ctr;
183 frame->portable.stack_ptr = frame->context.regs.stack_ptr;
184
185 #if defined(__i386__)
186 frame->context.arch = EM_386;
187 frame->portable.frame_ptr = frame->context.regs.ebp;
188 #elif defined(__arm__)
189 frame->context.arch = EM_ARM;
190 /* R11 is frame pointer in ARM mode, R8 is frame pointer in thumb mode. */
191 frame->portable.frame_ptr = frame->context.regs.r11;
192 #else
193 # error Unsupported architecture
194 #endif
195 }
196
197 /* A replacement of sigreturn. It does not restore the signal mask. */
198 static void __attribute__((noreturn))
199 nonsfi_restore_context(const linux_mcontext_t *mctx) {
200
201 #if defined(__i386__)
202
203 #define OFFSET(name) \
204 [name] "i" (offsetof(linux_mcontext_t, name))
205 #define RESTORE_SEGMENT(name) \
206 "mov %c[" #name "](%%eax), %%" #name "\n"
207 #define RESTORE(name) \
208 "movl %c[" #name "](%%eax), %%e" #name "\n"
209
210 __asm__ __volatile__(
211 /* Restore floating-point environment */
212 "mov %c[fpstate](%%eax), %%ecx\n"
213 "fldenv (%%ecx)\n"
214
215 /* Restore all segment registers */
216 RESTORE_SEGMENT(gs)
217 RESTORE_SEGMENT(fs)
218 RESTORE_SEGMENT(es)
219 RESTORE_SEGMENT(ds)
220
221 /*
222 * Restore most of the other registers.
223 */
224 RESTORE(di)
225 RESTORE(si)
226 RESTORE(bp)
227 RESTORE(bx)
228
229 /*
230 * Prepare the last registers. eip *must* be one slot above the original
231 * stack, since that is the only way eip and esp can be simultaneously
232 * restored. Here, we are using ecx as the pseudo stack pointer, and edx
233 * as a scratch register. Once the stack is laid out the way we want it to
234 * be, restore edx and eax last.
235 */
236 "mov %c[sp](%%eax), %%ecx\n"
237 "mov %c[ip](%%eax), %%edx\n"
238 "mov %%edx, -4(%%ecx)\n"
239 "mov %c[flags](%%eax), %%edx\n"
240 "mov %%edx, -8(%%ecx)\n"
241 "mov %c[cx](%%eax), %%edx\n"
242 "mov %%edx, -12(%%ecx)\n"
243 RESTORE(dx)
244 RESTORE(ax)
245 "lea -12(%%ecx), %%esp\n"
246
247 /*
248 * Finally pop ecx off the stack, restore the processor flags, and return
249 * to simultaneously restore esp and eip.
250 */
251 "pop %%ecx\n"
252 "popf\n"
253 "ret\n"
254 :
255 : "a" (mctx),
256 OFFSET(gs),
257 OFFSET(fs),
258 OFFSET(es),
259 OFFSET(ds),
260 OFFSET(di),
261 OFFSET(si),
262 OFFSET(bp),
263 OFFSET(sp),
264 OFFSET(bx),
265 OFFSET(dx),
266 OFFSET(cx),
267 OFFSET(ax),
268 OFFSET(ip),
269 OFFSET(flags),
270 OFFSET(fpstate)
271 );
272
273 #undef OFFSET
274 #undef RESTORE
275 #undef RESTORE_SEGMENT
276
277 #elif defined(__arm__)
278
279 #define OFFSET(name) \
280 [name] "I" (offsetof(linux_mcontext_t, arm_ ## name) - \
281 offsetof(linux_mcontext_t, arm_r0))
282
283 register uint32_t a14 __asm__("r14") = (uint32_t) &mctx->arm_r0;
284
285 __asm__ __volatile__(
286 /* Restore flags */
287 "ldr r0, [r14, %[cpsr]]\n"
288 "msr APSR_nzcvqg, r0\n"
289
290 /*
291 * Restore general-purpose registers.
292 * This code does not use the simpler 'ldmia r14, {r0-pc}' since using
293 * ldmia with either sp or with both lr and pc is deprecated.
294 */
295 "ldmia r14, {r0-r10}\n"
296
297 /*
298 * Copy r11, r12, lr, and pc just before the original sp.
299 * r12 will work as a temporary sp. r11 will be the scratch register, and
300 * will be restored just before moving sp.
301 */
302 "ldr r12, [r14, %[sp]]\n"
303
304 "ldr r11, [r14, %[pc]]\n"
305 "stmdb r12!, {r11}\n"
306 "ldr r11, [r14, %[lr]]\n"
307 "stmdb r12!, {r11}\n"
308 "ldr r11, [r14, %[r12]]\n"
309 "stmdb r12!, {r11}\n"
310 "ldr r11, [r14, %[r11]]\n"
311 "mov sp, r12\n"
312
313 /*
314 * Restore r12, lr, and pc. sp will point to the correct location once
315 * we're done.
316 */
317 "pop {r12, lr}\n"
318 "pop {pc}\n"
319 :
320 : "r" (a14),
321 OFFSET(cpsr),
322 OFFSET(r11),
323 OFFSET(r12),
324 OFFSET(sp),
325 OFFSET(lr),
326 OFFSET(pc)
327 );
328
329 #undef OFFSET
330
331 #else
332 # error Unsupported architecture
333 #endif
334
335 /* Should never reach this. */
336 __builtin_trap();
337 }
338
339 static __attribute__((noreturn))
340 void restore_context(void *raw_ctx) {
341 const struct linux_ucontext_t *uctx = (struct linux_ucontext_t *) raw_ctx;
342 const linux_mcontext_t *mctx = &uctx->uc_mcontext;
343 nonsfi_restore_context(mctx);
344 }
345
346 /* Signal handlers, responsible for calling the registered handlers. */
347 static void exception_catch(int sig, linux_siginfo_t *info, void *uc) {
348 if (g_exception_handler_function_pointer) {
349 struct NonSfiExceptionFrame exception_frame;
350 nonsfi_exception_frame_from_signal_context(&exception_frame, uc);
351 g_exception_handler_function_pointer(&exception_frame.context);
352 }
353 _exit(-sig);
354 }
355
356 static void signal_catch(int sig, linux_siginfo_t *info, void *uc) {
357 if (g_signal_handler_function_pointer) {
358 struct NonSfiExceptionFrame exception_frame;
359 nonsfi_exception_frame_from_signal_context(&exception_frame, uc);
360 g_signal_handler_function_pointer(&exception_frame.context);
361 }
362 restore_context(uc);
363 }
364
365 static void nonsfi_install_exception_handler_locked() {
366 struct linux_sigaction sa;
367 unsigned int a;
368
369 memset(&sa, 0, sizeof(sa));
370 sa.sa_sigaction = exception_catch;
371 sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_ONSTACK;
372
373 /*
374 * Reuse the sigemptyset/sigaddset for the first 32 bits of the
375 * sigmask. Works on little endian systems only.
376 */
377 sigset_t *mask = (sigset_t*)&sa.sa_mask;
378 sigemptyset(mask);
379
380 /* Mask all signals we catch to prevent re-entry. */
381 for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) {
382 sigaddset(mask, kSignals[a]);
383 }
384
385 /* Install all handlers. */
386 for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) {
387 if (linux_sigaction(kSignals[a], &sa, NULL) != 0)
388 abort();
389 }
390 }
391
392 static void nonsfi_install_signal_handler_locked() {
393 struct linux_sigaction sa;
394
395 memset(&sa, 0, sizeof(sa));
396 sa.sa_sigaction = signal_catch;
397
398 /*
399 * User signal handler can be recursively interrupted to avoid having
400 * to allow sigreturn/sigprocmask.
401 */
402 sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_NODEFER | LINUX_SA_RESTART;
403 sigset_t *mask = (sigset_t*)&sa.sa_mask;
404 sigemptyset(mask);
405
406 /*
407 * Install a single handler. Multiple signals can be multiplexed in
408 * userspace.
409 */
410 if (linux_sigaction(LINUX_SIGUSR1, &sa, NULL) != 0)
411 abort();
412 }
413
414 static void nonsfi_initialize_signal_handler_locked() {
415 if (g_signal_handler_initialized)
416 return;
417 pid_t tgid = getpid();
418 if (tgid == -1)
419 abort();
420 pid_t main_tid = syscall(__NR_gettid);
421 if (main_tid == -1)
422 abort();
423 nonsfi_install_exception_handler_locked();
424 nonsfi_install_signal_handler_locked();
425 g_tgid = tgid;
426 g_main_tid = main_tid;
427 g_signal_handler_initialized = 1;
428 }
429
430 /*
431 * Initialize signal handlers before entering sandbox.
432 */
433 void nonsfi_initialize_signal_handler() {
434 if (pthread_mutex_lock(&g_mutex) != 0)
435 abort();
436 nonsfi_initialize_signal_handler_locked();
437 if (pthread_mutex_unlock(&g_mutex) != 0)
438 abort();
439 }
440
441 int nacl_exception_get_and_set_handler(NaClExceptionHandler handler,
442 NaClExceptionHandler *old_handler) {
443 if (pthread_mutex_lock(&g_mutex) != 0)
444 abort();
445 nonsfi_initialize_signal_handler_locked();
446 if (old_handler)
447 *old_handler = g_exception_handler_function_pointer;
448 g_exception_handler_function_pointer = handler;
449 if (pthread_mutex_unlock(&g_mutex) != 0)
450 abort();
451 return 0;
452 }
453
454 int nacl_exception_set_handler(NaClExceptionHandler handler) {
455 return nacl_exception_get_and_set_handler(handler, NULL);
456 }
457
458 int nacl_exception_clear_flag(void) {
459 /*
460 * Unblock signals, useful for unit testing and continuing to
461 * process after fatal signal.
462 */
463
464 /* Allocate the 8 bytes of signal mask. */
465 linux_sigset_t mask;
466
467 /*
468 * sigemptyset will only clear first 4 bytes of sigset_t, and
469 * compat_sigset_t has 8 bytes, clear with memset.
470 */
471 memset(&mask, 0, sizeof(mask));
472
473 /*
474 * Hack to be able to reuse sigset_t utilities from newlib for the
475 * first lower 4 bytes of the signal, works because we are all
476 * little endians.
477 */
478 sigset_t *maskptr = (sigset_t *) &mask;
479 sigemptyset(maskptr);
480 for (int a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) {
481 if (sigaddset(maskptr, kSignals[a]) != 0)
482 abort();
483 }
484 if (linux_sigprocmask(LINUX_SIG_UNBLOCK, &mask, NULL) != 0)
485 abort();
486
487 return 0;
488 }
489
490 int nacl_exception_set_stack(void *p, size_t s) {
491 /* Not implemented yet. */
492 return ENOSYS;
493 }
494
495 int nacl_async_signal_set_handler(NaClIrtAsyncSignalHandler handler) {
496 if (pthread_mutex_lock(&g_mutex) != 0)
497 abort();
498 nonsfi_initialize_signal_handler_locked();
499 g_signal_handler_function_pointer = handler;
500 if (pthread_mutex_unlock(&g_mutex) != 0)
501 abort();
502 return 0;
503 }
504
505 int nacl_async_signal_send_async_signal(nacl_irt_tid_t tid) {
506 if (!g_signal_handler_initialized)
507 return ESRCH;
508 if (tid == 0)
509 tid = g_main_tid;
510 if (linux_tgkill(g_tgid, tid, LINUX_SIGUSR1) == -1)
511 return errno;
512 return 0;
513 }
OLDNEW
« no previous file with comments | « src/nonsfi/linux/irt_signal_handling.h ('k') | src/nonsfi/linux/linux_pthread_private.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698