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

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

Powered by Google App Engine
This is Rietveld 408576698