1 : /*
2 : * Copyright (c) 2012 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 <string.h>
8 :
9 : #include "native_client/src/include/portability_io.h"
10 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
11 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
12 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
13 : #include "native_client/src/trusted/service_runtime/sel_rt.h"
14 : #include "native_client/src/trusted/service_runtime/thread_suspension.h"
15 : #include "native_client/src/trusted/service_runtime/thread_suspension_unwind.h"
16 : #include "native_client/src/trusted/service_runtime/win/debug_exception_handler.h"
17 :
18 12386 : void NaClUntrustedThreadsSuspendAll(struct NaClApp *nap, int save_registers) {
19 12386 : size_t index;
20 :
21 12386 : NaClXMutexLock(&nap->threads_mu);
22 :
23 : /*
24 : * TODO(mseaborn): A possible refinement here would be to use separate loops
25 : * for initiating and waiting for the suspension of the threads. This might
26 : * be faster, since we would not be waiting for each thread to suspend one by
27 : * one. It would take advantage of the asynchronous nature of thread
28 : * suspension.
29 : */
30 49562 : for (index = 0; index < nap->threads.num_entries; index++) {
31 12395 : struct NaClAppThread *natp = NaClGetThreadMu(nap, (int) index);
32 12395 : if (natp != NULL) {
33 12393 : NaClUntrustedThreadSuspend(natp, save_registers);
34 12393 : }
35 12395 : }
36 12386 : }
37 :
38 12370 : void NaClUntrustedThreadsResumeAll(struct NaClApp *nap) {
39 12370 : size_t index;
40 49492 : for (index = 0; index < nap->threads.num_entries; index++) {
41 12376 : struct NaClAppThread *natp = NaClGetThreadMu(nap, (int) index);
42 12376 : if (natp != NULL) {
43 12376 : NaClUntrustedThreadResume(natp);
44 12376 : }
45 12376 : }
46 :
47 12370 : NaClXMutexUnlock(&nap->threads_mu);
48 12370 : }
49 :
50 11104 : void NaClAppThreadGetSuspendedRegisters(struct NaClAppThread *natp,
51 11104 : struct NaClSignalContext *regs) {
52 11104 : if ((natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) != 0) {
53 5847 : NaClAppThreadGetSuspendedRegistersInternal(natp, regs);
54 5847 : if (!NaClSignalContextIsUntrusted(natp, regs)) {
55 5749 : enum NaClUnwindCase unwind_case;
56 5749 : NaClGetRegistersForContextSwitch(natp, regs, &unwind_case);
57 5749 : }
58 5847 : } else {
59 5257 : NaClThreadContextToSignalContext(&natp->user, regs);
60 : }
61 11104 : }
62 :
63 10000 : int NaClAppThreadIsSuspendedInSyscall(struct NaClAppThread *natp) {
64 10000 : if ((natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) != 0) {
65 5728 : struct NaClSignalContext regs;
66 5728 : NaClAppThreadGetSuspendedRegistersInternal(natp, ®s);
67 5728 : return !NaClSignalContextIsUntrusted(natp, ®s);
68 : }
69 4272 : return 1;
70 10000 : }
71 :
72 1081 : void NaClAppThreadSetSuspendedRegisters(struct NaClAppThread *natp,
73 1081 : const struct NaClSignalContext *regs) {
74 : /*
75 : * We only allow modifying the register state if the thread was
76 : * suspended while executing untrusted code, not if the thread is
77 : * inside a NaCl syscall.
78 : */
79 1081 : if ((natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) != 0) {
80 99 : struct NaClSignalContext current_regs;
81 99 : NaClAppThreadGetSuspendedRegistersInternal(natp, ¤t_regs);
82 99 : if (NaClSignalContextIsUntrusted(natp, ¤t_regs)) {
83 78 : NaClAppThreadSetSuspendedRegistersInternal(natp, regs);
84 78 : } else {
85 21 : NaClLog(LOG_WARNING,
86 : "NaClAppThreadSetSuspendedRegisters: Registers not modified "
87 : "(thread suspended during trusted/untrusted context switch)\n");
88 : }
89 99 : } else {
90 982 : NaClLog(LOG_WARNING,
91 : "NaClAppThreadSetSuspendedRegisters: Registers not modified "
92 : "(thread suspended inside syscall)\n");
93 : }
94 1081 : }
95 :
96 18 : int NaClFaultedThreadQueueEnable(struct NaClApp *nap) {
97 : #if NACL_WINDOWS
98 : nap->faulted_thread_event = CreateEvent(NULL, TRUE, FALSE, NULL);
99 : if (nap->faulted_thread_event == NULL) {
100 : NaClLog(LOG_FATAL,
101 : "NaClFaultedThreadQueueEnable: Failed to create event object for "
102 : "faulted thread events\n");
103 : }
104 : #else
105 18 : int fds[2];
106 : #if NACL_LINUX
107 : int ret = pipe2(fds, O_CLOEXEC);
108 : #else
109 18 : int ret = pipe(fds);
110 : #endif
111 18 : if (ret < 0) {
112 0 : NaClLog(LOG_FATAL,
113 : "NaClFaultedThreadQueueEnable: Failed to allocate pipe for "
114 : "faulted thread events\n");
115 0 : }
116 18 : nap->faulted_thread_fd_read = fds[0];
117 18 : nap->faulted_thread_fd_write = fds[1];
118 : #endif
119 18 : nap->enable_faulted_thread_queue = 1;
120 18 : return NaClDebugExceptionHandlerEnsureAttached(nap);
121 : }
|