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 12186 : void NaClUntrustedThreadsSuspendAll(struct NaClApp *nap, int save_registers) {
19 : size_t index;
20 :
21 12186 : 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 24381 : for (index = 0; index < nap->threads.num_entries; index++) {
31 12195 : struct NaClAppThread *natp = NaClGetThreadMu(nap, (int) index);
32 12195 : if (natp != NULL) {
33 12194 : NaClUntrustedThreadSuspend(natp, save_registers);
34 : }
35 : }
36 12186 : }
37 :
38 12169 : void NaClUntrustedThreadsResumeAll(struct NaClApp *nap) {
39 : size_t index;
40 24344 : for (index = 0; index < nap->threads.num_entries; index++) {
41 12175 : struct NaClAppThread *natp = NaClGetThreadMu(nap, (int) index);
42 12175 : if (natp != NULL) {
43 12175 : NaClUntrustedThreadResume(natp);
44 : }
45 : }
46 :
47 12169 : NaClXMutexUnlock(&nap->threads_mu);
48 12169 : }
49 :
50 11105 : void NaClAppThreadGetSuspendedRegisters(struct NaClAppThread *natp,
51 : struct NaClSignalContext *regs) {
52 11105 : if ((natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) != 0) {
53 10492 : NaClAppThreadGetSuspendedRegistersInternal(natp, regs);
54 10492 : if (!NaClSignalContextIsUntrusted(natp, regs)) {
55 : enum NaClUnwindCase unwind_case;
56 10393 : NaClGetRegistersForContextSwitch(natp, regs, &unwind_case);
57 : }
58 : } else {
59 613 : NaClThreadContextToSignalContext(&natp->user, regs);
60 : }
61 11105 : }
62 :
63 10000 : int NaClAppThreadIsSuspendedInSyscall(struct NaClAppThread *natp) {
64 10000 : if ((natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) != 0) {
65 : struct NaClSignalContext regs;
66 9882 : NaClAppThreadGetSuspendedRegistersInternal(natp, ®s);
67 9882 : return !NaClSignalContextIsUntrusted(natp, ®s);
68 : }
69 118 : return 1;
70 : }
71 :
72 1080 : void NaClAppThreadSetSuspendedRegisters(struct NaClAppThread *natp,
73 : 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 1080 : if ((natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) != 0) {
80 : struct NaClSignalContext current_regs;
81 588 : NaClAppThreadGetSuspendedRegistersInternal(natp, ¤t_regs);
82 588 : if (NaClSignalContextIsUntrusted(natp, ¤t_regs)) {
83 77 : NaClAppThreadSetSuspendedRegistersInternal(natp, regs);
84 : } else {
85 511 : NaClLog(LOG_WARNING,
86 : "NaClAppThreadSetSuspendedRegisters: Registers not modified "
87 : "(thread suspended during trusted/untrusted context switch)\n");
88 : }
89 : } else {
90 492 : NaClLog(LOG_WARNING,
91 : "NaClAppThreadSetSuspendedRegisters: Registers not modified "
92 : "(thread suspended inside syscall)\n");
93 : }
94 1080 : }
95 :
96 20 : 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 : int fds[2];
106 : #if NACL_LINUX
107 20 : int ret = pipe2(fds, O_CLOEXEC);
108 : #else
109 : int ret = pipe(fds);
110 : #endif
111 20 : if (ret < 0) {
112 0 : NaClLog(LOG_FATAL,
113 : "NaClFaultedThreadQueueEnable: Failed to allocate pipe for "
114 : "faulted thread events\n");
115 : }
116 20 : nap->faulted_thread_fd_read = fds[0];
117 20 : nap->faulted_thread_fd_write = fds[1];
118 : #endif
119 20 : nap->enable_faulted_thread_queue = 1;
120 20 : return NaClDebugExceptionHandlerEnsureAttached(nap);
121 : }
|