OLD | NEW |
| (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 } | |
OLD | NEW |