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

Side by Side 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: Fixed a small window where signals could corrupt the stack Created 5 years, 5 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
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
32 /* From linux/arch/arm/include/asm/ucontext.h */
33 struct linux_ucontext_t {
34 uint32_t uc_flags;
35 uint32_t uc_link;
36 linux_stack_t uc_stack;
37 linux_mcontext_t uc_mcontext;
38 linux_sigset_t uc_sigmask;
39 /* More data follows which we don't care about. */
40 };
41
42 pthread_mutex_t g_signal_handler_mutex = PTHREAD_MUTEX_INITIALIZER;
43 static NaClExceptionHandler g_signal_handler_function_pointer = NULL;
44 static int g_signal_handler_initialized = 0;
45 static int g_tgid = 0;
46 static int g_main_tid;
47
48 static void machine_context_to_register(const linux_mcontext_t *mctx,
49 NaClUserRegisterState *dest) {
50 #if defined(__i386__)
51 #define COPY_REG(A) dest->e##A = mctx->A
52 COPY_REG(ax);
53 COPY_REG(cx);
54 COPY_REG(dx);
55 COPY_REG(bx);
56 COPY_REG(bp);
57 COPY_REG(si);
58 COPY_REG(di);
59 #undef COPY_REG
60 dest->stack_ptr = mctx->sp;
61 dest->prog_ctr = mctx->ip;
62 dest->flags = mctx->flags;
63 #elif defined(__arm__)
64 #define COPY_REG(A) dest->A = mctx->arm_##A
65 COPY_REG(r0);
66 COPY_REG(r1);
67 COPY_REG(r2);
68 COPY_REG(r3);
69 COPY_REG(r4);
70 COPY_REG(r5);
71 COPY_REG(r6);
72 COPY_REG(r7);
73 COPY_REG(r8);
74 COPY_REG(r9);
75 COPY_REG(r10);
76 COPY_REG(r11);
77 COPY_REG(r12);
78 #undef COPY_REG
79 dest->stack_ptr = mctx->arm_sp;
80 dest->lr = mctx->arm_lr;
81 dest->prog_ctr = mctx->arm_pc;
82 dest->cpsr = mctx->arm_cpsr;
83 #else
84 # error Unsupported architecture
85 #endif
86 }
87
88 void exception_frame_from_signal_context(
89 struct NonSfiExceptionFrame *frame,
90 const void *raw_ctx) {
91 const struct linux_ucontext_t *uctx = (struct linux_ucontext_t *) raw_ctx;
92 const linux_mcontext_t *mctx = &uctx->uc_mcontext;
93 frame->context.size = (((uintptr_t) (&frame->portable + 1))
94 - (uintptr_t) &frame->context);
95 frame->context.portable_context_offset = ((uintptr_t) &frame->portable
96 - (uintptr_t) &frame->context);
97 frame->context.portable_context_size = sizeof(frame->portable);
98 frame->context.regs_size = sizeof(frame->context.regs);
99
100 memset(frame->context.reserved, 0, sizeof(frame->context.reserved));
101 machine_context_to_register(mctx, &frame->context.regs);
102 frame->portable.prog_ctr = frame->context.regs.prog_ctr;
103 frame->portable.stack_ptr = frame->context.regs.stack_ptr;
104
105 #if defined(__i386__)
106 frame->context.arch = EM_386;
107 frame->portable.frame_ptr = frame->context.regs.ebp;
108 #elif defined(__arm__)
109 frame->context.arch = EM_ARM;
110 /* R11 is frame pointer in ARM mode, R8 is frame pointer in thumb mode. */
111 frame->portable.frame_ptr = frame->context.regs.r11;
112 #else
113 # error Unsupported architecture
114 #endif
115 }
116
117 /* A replacement of sigreturn. It does not restore the signal mask. */
118 static void __attribute__((noreturn))
119 nonsfi_restore_context(const linux_mcontext_t *mctx) {
120
121 #if defined(__i386__)
122
123 #define OFFSET(name) \
124 [name] "i" (offsetof(linux_mcontext_t, name))
125 #define RESTORE_SEGMENT(name) \
126 "mov %c[" #name "](%%eax), %%" #name "\n"
127 #define RESTORE(name) \
128 "movl %c[" #name "](%%eax), %%e" #name "\n"
129
130 __asm__ __volatile__(
131 /* Restore floating-point environment */
132 "mov %c[fpstate](%%eax), %%ecx\n"
133 "fldenv (%%ecx)\n"
134
135 /* Restore all segment registers */
136 RESTORE_SEGMENT(gs)
137 RESTORE_SEGMENT(fs)
138 RESTORE_SEGMENT(es)
139 RESTORE_SEGMENT(ds)
140
141 /*
142 * Restore most of the other registers.
143 */
144 RESTORE(di)
145 RESTORE(si)
146 RESTORE(bp)
147 RESTORE(bx)
148
149 /*
150 * Prepare the last registers. eip *must* be one slot above the original
151 * stack, since that is the only way eip and esp can be simultaneously
152 * restored. Here, we are using ecx as the pseudo stack pointer, and edx
153 * as a scratch register. Once the stack is laid out the way we want it to
154 * be, restore edx and eax last.
155 */
156 "mov %c[sp](%%eax), %%ecx\n"
157 "mov %c[ip](%%eax), %%edx\n"
158 "mov %%edx, -4(%%ecx)\n"
159 "mov %c[flags](%%eax), %%edx\n"
160 "mov %%edx, -8(%%ecx)\n"
161 "mov %c[cx](%%eax), %%edx\n"
162 "mov %%edx, -12(%%ecx)\n"
163 RESTORE(dx)
164 RESTORE(ax)
165 "lea -12(%%ecx), %%esp\n"
166
167 /*
168 * Finally pop ecx off the stack, restore the processor flags, and return
169 * to simultaneously restore esp and eip.
170 */
171 "pop %%ecx\n"
172 "popf\n"
173 "ret\n"
174 :
175 : "a" (mctx),
176 OFFSET(gs),
177 OFFSET(fs),
178 OFFSET(es),
179 OFFSET(ds),
180 OFFSET(di),
181 OFFSET(si),
182 OFFSET(bp),
183 OFFSET(sp),
184 OFFSET(bx),
185 OFFSET(dx),
186 OFFSET(cx),
187 OFFSET(ax),
188 OFFSET(ip),
189 OFFSET(flags),
190 OFFSET(fpstate)
191 );
192
193 #undef OFFSET
194 #undef RESTORE
195 #undef RESTORE_SEGMENT
196
197 #elif defined(__arm__)
198
199 #define OFFSET(name) \
200 [name] "I" (offsetof(linux_mcontext_t, arm_ ## name) - \
201 offsetof(linux_mcontext_t, arm_r0))
202
203 register uint32_t a14 __asm__("r14") = (uint32_t) &mctx->arm_r0;
204
205 __asm__ __volatile__(
206 /* Restore flags */
207 "ldr r0, [r14, %[cpsr]]\n"
208 "msr APSR_nzcvqg, r0\n"
209
210 /* Restore general-purpose registers */
211 "ldmia r14, {r0-r10}\n"
212
213 /*
214 * Copy r11, r12, lr, and pc just before the original sp.
215 * r12 will work as a temporary sp. r11 will be the scratch register, and
216 * will be restored just before moving sp.
217 */
218 "ldr r12, [r14, %[sp]]\n"
219
220 "ldr r11, [r14, %[pc]]\n"
221 "stmdb r12!, {r11}\n"
222 "ldr r11, [r14, %[lr]]\n"
223 "stmdb r12!, {r11}\n"
224 "ldr r11, [r14, %[r12]]\n"
225 "stmdb r12!, {r11}\n"
226 "ldr r11, [r14, %[r11]]\n"
227 "mov sp, r12\n"
228
229 /*
230 * Restore r12, lr, and pc. sp will point to the correct location once
231 * we're done.
232 */
233 "pop {r12, lr}\n"
234 "pop {pc}\n"
235 :
236 : "r" (a14),
237 OFFSET(cpsr),
238 OFFSET(r11),
239 OFFSET(r12),
240 OFFSET(sp),
241 OFFSET(lr),
242 OFFSET(pc)
243 );
244
245 #undef OFFSET
246
247 #else
248 # error Unsupported architecture
249 #endif
250
251 /* Should never reach this. */
252 __builtin_trap();
253 }
254
255 static __attribute__((noreturn))
256 void restore_context(void *raw_ctx) {
257 const struct linux_ucontext_t *uctx = (struct linux_ucontext_t *) raw_ctx;
258 const linux_mcontext_t *mctx = &uctx->uc_mcontext;
259 nonsfi_restore_context(mctx);
260 }
261
262 static void signal_catch(int sig, linux_siginfo_t *info, void *uc) {
263 if (g_signal_handler_function_pointer) {
264 struct NonSfiExceptionFrame exception_frame;
265 exception_frame_from_signal_context(&exception_frame, uc);
266 g_signal_handler_function_pointer(&exception_frame.context);
267 }
268 restore_context(uc);
269 }
270
271 static void nonsfi_install_signal_handler_locked() {
272 struct linux_sigaction sa;
273
274 memset(&sa, 0, sizeof(sa));
275 sa.sa_sigaction = signal_catch;
276
277 /*
278 * User signal handler can be recursively interrupted to avoid having
279 * to allow sigreturn/sigprocmask.
280 */
281 sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_NODEFER;
282 sigset_t *mask = (sigset_t*)&sa.sa_mask;
283 sigemptyset(mask);
284
285 /*
286 * Install a single handler. Multiple signals can be multiplexed in
287 * userspace.
288 */
289 if (linux_sigaction(LINUX_SIGUSR1, &sa, NULL) != 0)
290 abort();
291 }
292
293 void nonsfi_initialize_signal_handler_locked() {
294 if (g_signal_handler_initialized)
295 return;
296 nonsfi_install_exception_handler_locked();
297 nonsfi_install_signal_handler_locked();
298 g_tgid = getpid();
299 g_main_tid = syscall(__NR_gettid);
300 g_signal_handler_initialized = 1;
301 }
302
303 /*
304 * Initialize signal handlers before entering sandbox.
305 */
306 void nonsfi_initialize_signal_handler() {
307 if (pthread_mutex_lock(&g_signal_handler_mutex) != 0)
308 abort();
309 nonsfi_initialize_signal_handler_locked();
310 if (pthread_mutex_unlock(&g_signal_handler_mutex) != 0)
311 abort();
312 }
313
314 int nacl_signal_set_handler(NaClIrtSignalHandler handler) {
315 if (pthread_mutex_lock(&g_signal_handler_mutex) != 0)
316 abort();
317 nonsfi_initialize_signal_handler_locked();
318 g_signal_handler_function_pointer = handler;
319 if (pthread_mutex_unlock(&g_signal_handler_mutex) != 0)
320 abort();
321 return 0;
322 }
323
324 int nacl_signal_send_async_signal(nacl_irt_tid_t tid) {
325 if (!g_signal_handler_initialized)
326 return ESRCH;
327 if (tid == 0)
328 tid = g_main_tid;
329 if (linux_tgkill(g_tgid, tid, LINUX_SIGUSR1) == -1)
330 return errno;
331 return 0;
332 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698