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 : /*
10 : * NaCl Simple/secure ELF loader (NaCl SEL).
11 : */
12 : #include "native_client/src/include/portability_io.h"
13 : #include "native_client/src/include/portability_string.h"
14 : #include "native_client/src/include/nacl_macros.h"
15 :
16 : #include "native_client/src/shared/gio/gio.h"
17 : #include "native_client/src/shared/platform/nacl_check.h"
18 : #include "native_client/src/shared/platform/nacl_exit.h"
19 : #include "native_client/src/shared/platform/nacl_log.h"
20 : #include "native_client/src/shared/platform/nacl_sync.h"
21 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
22 : #include "native_client/src/shared/platform/nacl_time.h"
23 : #include "native_client/src/shared/srpc/nacl_srpc.h"
24 :
25 :
26 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
27 : #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
28 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
29 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
30 : #include "native_client/src/trusted/desc/nrd_xfer.h"
31 :
32 : #include "native_client/src/trusted/fault_injection/fault_injection.h"
33 :
34 : #include "native_client/src/trusted/handle_pass/ldr_handle.h"
35 :
36 : #include "native_client/src/trusted/gio/gio_nacl_desc.h"
37 : #include "native_client/src/trusted/gio/gio_shm.h"
38 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
39 : #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
40 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
41 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
42 : #include "native_client/src/trusted/service_runtime/include/sys/time.h"
43 : #include "native_client/src/trusted/service_runtime/nacl_app.h"
44 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
45 : #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
46 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
47 : #include "native_client/src/trusted/service_runtime/nacl_resource.h"
48 : #include "native_client/src/trusted/service_runtime/nacl_reverse_quota_interface.h"
49 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
50 : #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
51 : #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
52 : #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
53 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
54 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
55 :
56 : #include "native_client/src/trusted/service_runtime/name_service/default_name_service.h"
57 : #include "native_client/src/trusted/service_runtime/name_service/name_service.h"
58 :
59 : #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
60 : #include "native_client/src/trusted/threading/nacl_thread_interface.h"
61 :
62 : #include "native_client/src/trusted/simple_service/nacl_simple_rservice.h"
63 : #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
64 :
65 : #include "native_client/src/trusted/threading/nacl_thread_interface.h"
66 :
67 38 : static int IsEnvironmentVariableSet(char const *env_name) {
68 38 : return NULL != getenv(env_name);
69 : }
70 :
71 19 : static int ShouldEnableDynamicLoading() {
72 19 : return !IsEnvironmentVariableSet("NACL_DISABLE_DYNAMIC_LOADING");
73 : }
74 :
75 : int NaClAppWithSyscallTableCtor(struct NaClApp *nap,
76 19 : struct NaClSyscallTableEntry *table) {
77 : struct NaClDescEffectorLdr *effp;
78 :
79 : /* Get the set of features that the CPU we're running on supports. */
80 19 : NaClGetCurrentCPUFeatures(&nap->cpu_features);
81 :
82 19 : nap->addr_bits = NACL_MAX_ADDR_BITS;
83 :
84 19 : nap->stack_size = NACL_DEFAULT_STACK_MAX;
85 :
86 19 : nap->aux_info = NULL;
87 :
88 19 : nap->mem_start = 0;
89 :
90 : #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
91 : && NACL_BUILD_SUBARCH == 32 && __PIC__)
92 19 : nap->pcrel_thunk = 0;
93 : #endif
94 : #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
95 : && NACL_BUILD_SUBARCH == 64)
96 : nap->dispatch_thunk = 0;
97 : nap->get_tls_fast_path = 0;
98 : #endif
99 :
100 19 : nap->static_text_end = 0;
101 19 : nap->dynamic_text_start = 0;
102 19 : nap->dynamic_text_end = 0;
103 19 : nap->rodata_start = 0;
104 19 : nap->data_start = 0;
105 19 : nap->data_end = 0;
106 :
107 19 : nap->initial_entry_pt = 0;
108 19 : nap->user_entry_pt = 0;
109 :
110 19 : if (!DynArrayCtor(&nap->threads, 2)) {
111 0 : goto cleanup_none;
112 : }
113 19 : if (!DynArrayCtor(&nap->desc_tbl, 2)) {
114 0 : goto cleanup_threads;
115 : }
116 19 : if (!NaClVmmapCtor(&nap->mem_map)) {
117 0 : goto cleanup_desc_tbl;
118 : }
119 :
120 19 : effp = (struct NaClDescEffectorLdr *) malloc(sizeof *effp);
121 19 : if (NULL == effp) {
122 0 : goto cleanup_mem_map;
123 : }
124 19 : if (!NaClDescEffectorLdrCtor(effp, nap)) {
125 0 : goto cleanup_effp_free;
126 : }
127 19 : nap->effp = (struct NaClDescEffector *) effp;
128 :
129 19 : nap->use_shm_for_dynamic_text = ShouldEnableDynamicLoading();
130 19 : nap->text_shm = NULL;
131 19 : if (!NaClMutexCtor(&nap->dynamic_load_mutex)) {
132 0 : goto cleanup_effp_dtor;
133 : }
134 19 : nap->dynamic_page_bitmap = NULL;
135 :
136 19 : nap->dynamic_regions = NULL;
137 19 : nap->num_dynamic_regions = 0;
138 19 : nap->dynamic_regions_allocated = 0;
139 19 : nap->dynamic_delete_generation = 0;
140 :
141 19 : nap->dynamic_mapcache_offset = 0;
142 19 : nap->dynamic_mapcache_size = 0;
143 19 : nap->dynamic_mapcache_ret = 0;
144 :
145 19 : nap->service_port = NULL;
146 19 : nap->service_address = NULL;
147 19 : nap->secure_service = NULL;
148 19 : nap->manifest_proxy = NULL;
149 19 : nap->kern_service = NULL;
150 19 : nap->resource_phase = NACL_RESOURCE_PHASE_START;
151 19 : if (!NaClResourceNaClAppInit(&nap->resources, nap)) {
152 0 : goto cleanup_dynamic_load_mutex;
153 : }
154 19 : nap->reverse_client = NULL;
155 19 : nap->reverse_channel_initialization_state =
156 : NACL_REVERSE_CHANNEL_UNINITIALIZED;
157 :
158 19 : if (!NaClMutexCtor(&nap->mu)) {
159 0 : goto cleanup_dynamic_load_mutex;
160 : }
161 19 : if (!NaClCondVarCtor(&nap->cv)) {
162 0 : goto cleanup_mu;
163 : }
164 :
165 19 : nap->vm_hole_may_exist = 0;
166 19 : nap->threads_launching = 0;
167 :
168 19 : nap->syscall_table = table;
169 :
170 19 : nap->module_load_status = LOAD_STATUS_UNKNOWN;
171 19 : nap->module_may_start = 0; /* only when secure_service != NULL */
172 :
173 19 : nap->name_service = (struct NaClNameService *) malloc(
174 : sizeof *nap->name_service);
175 19 : if (NULL == nap->name_service) {
176 0 : goto cleanup_cv;
177 : }
178 19 : if (!NaClNameServiceCtor(nap->name_service,
179 : NaClAddrSpSquattingThreadIfFactoryFunction,
180 : (void *) nap)) {
181 0 : free(nap->name_service);
182 0 : goto cleanup_cv;
183 : }
184 19 : nap->name_service_conn_cap = NaClDescRef(nap->name_service->
185 : base.base.bound_and_cap[1]);
186 19 : if (!NaClDefaultNameServiceInit(nap->name_service)) {
187 0 : goto cleanup_name_service;
188 : }
189 :
190 19 : nap->ignore_validator_result = 0;
191 19 : nap->skip_validator = 0;
192 19 : nap->validator_stub_out_mode = 0;
193 :
194 19 : if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_FILE_ACCESS")) {
195 0 : NaClInsecurelyBypassAllAclChecks();
196 0 : NaClLog(LOG_INFO, "DANGER: ENABLED FILE ACCESS\n");
197 : }
198 :
199 19 : if (!NaClMutexCtor(&nap->threads_mu)) {
200 0 : goto cleanup_name_service;
201 : }
202 19 : if (!NaClCondVarCtor(&nap->threads_cv)) {
203 0 : goto cleanup_threads_mu;
204 : }
205 19 : nap->num_threads = 0;
206 19 : if (!NaClMutexCtor(&nap->desc_mu)) {
207 0 : goto cleanup_threads_cv;
208 : }
209 :
210 19 : nap->running = 0;
211 19 : nap->exit_status = -1;
212 :
213 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
214 19 : nap->code_seg_sel = 0;
215 19 : nap->data_seg_sel = 0;
216 : #endif
217 :
218 19 : nap->enable_debug_stub = 0;
219 19 : nap->debug_stub_callbacks = NULL;
220 19 : nap->exception_handler = 0;
221 19 : if (!NaClMutexCtor(&nap->exception_mu)) {
222 0 : goto cleanup_desc_mu;
223 : }
224 19 : nap->enable_exception_handling = 0;
225 :
226 19 : return 1;
227 :
228 0 : cleanup_desc_mu:
229 0 : NaClMutexDtor(&nap->desc_mu);
230 0 : cleanup_threads_cv:
231 0 : NaClCondVarDtor(&nap->threads_cv);
232 0 : cleanup_threads_mu:
233 0 : NaClMutexDtor(&nap->threads_mu);
234 0 : cleanup_name_service:
235 0 : NaClDescUnref(nap->name_service_conn_cap);
236 0 : NaClRefCountUnref((struct NaClRefCount *) nap->name_service);
237 0 : cleanup_cv:
238 0 : NaClCondVarDtor(&nap->cv);
239 0 : cleanup_mu:
240 0 : NaClMutexDtor(&nap->mu);
241 0 : cleanup_dynamic_load_mutex:
242 0 : NaClMutexDtor(&nap->dynamic_load_mutex);
243 0 : cleanup_effp_dtor:
244 0 : (*nap->effp->vtbl->Dtor)(nap->effp);
245 0 : cleanup_effp_free:
246 0 : free(nap->effp);
247 0 : cleanup_mem_map:
248 0 : NaClVmmapDtor(&nap->mem_map);
249 0 : cleanup_desc_tbl:
250 0 : DynArrayDtor(&nap->desc_tbl);
251 0 : cleanup_threads:
252 0 : DynArrayDtor(&nap->threads);
253 0 : cleanup_none:
254 0 : return 0;
255 : }
256 :
257 19 : int NaClAppCtor(struct NaClApp *nap) {
258 19 : return NaClAppWithSyscallTableCtor(nap, nacl_syscall);
259 : }
260 :
261 0 : size_t NaClAlignPad(size_t val, size_t align) {
262 : /* align is always a power of 2, but we do not depend on it */
263 0 : if (!align) {
264 0 : NaClLog(4,
265 : "sel_ldr: NaClAlignPad, align == 0, at 0x%08"NACL_PRIxS"\n",
266 : val);
267 0 : return 0;
268 : }
269 0 : val = val % align;
270 0 : if (!val) return 0;
271 0 : return align - val;
272 : }
273 :
274 : /*
275 : * unaligned little-endian load. precondition: nbytes should never be
276 : * more than 8.
277 : */
278 : static uint64_t NaClLoadMem(uintptr_t addr,
279 3 : size_t user_nbytes) {
280 3 : uint64_t value = 0;
281 :
282 3 : CHECK(0 != user_nbytes && user_nbytes <= 8);
283 :
284 : do {
285 12 : value = value << 8;
286 12 : value |= ((uint8_t *) addr)[--user_nbytes];
287 12 : } while (user_nbytes > 0);
288 3 : return value;
289 : }
290 :
291 : #define GENERIC_LOAD(bits) \
292 : static uint ## bits ## _t NaClLoad ## bits(uintptr_t addr) { \
293 : return (uint ## bits ## _t) NaClLoadMem(addr, sizeof(uint ## bits ## _t)); \
294 : }
295 :
296 : #if NACL_TARGET_SUBARCH == 32
297 3 : GENERIC_LOAD(32)
298 : #endif
299 0 : GENERIC_LOAD(64)
300 :
301 : #undef GENERIC_LOAD
302 :
303 : /*
304 : * unaligned little-endian store
305 : */
306 : static void NaClStoreMem(uintptr_t addr,
307 : size_t nbytes,
308 12291 : uint64_t value) {
309 : size_t i;
310 :
311 12291 : CHECK(nbytes <= 8);
312 :
313 49179 : for (i = 0; i < nbytes; ++i) {
314 36888 : ((uint8_t *) addr)[i] = (uint8_t) value;
315 36888 : value = value >> 8;
316 : }
317 12291 : }
318 :
319 : #define GENERIC_STORE(bits) \
320 : static void NaClStore ## bits(uintptr_t addr, \
321 : uint ## bits ## _t v) { \
322 : NaClStoreMem(addr, sizeof(uint ## bits ## _t), v); \
323 : }
324 :
325 6138 : GENERIC_STORE(16)
326 6153 : GENERIC_STORE(32)
327 0 : GENERIC_STORE(64)
328 :
329 : #undef GENERIC_STORE
330 :
331 6147 : struct NaClPatchInfo *NaClPatchInfoCtor(struct NaClPatchInfo *self) {
332 6147 : if (NULL != self) {
333 6147 : memset(self, 0, sizeof *self);
334 : }
335 6147 : return self;
336 : }
337 :
338 : /*
339 : * This function is called by NaClLoadTrampoline and NaClLoadSpringboard to
340 : * patch a single memory location specified in NaClPatchInfo structure.
341 : */
342 6150 : void NaClApplyPatchToMemory(struct NaClPatchInfo *patch) {
343 : size_t i;
344 : size_t offset;
345 : int64_t reloc;
346 : uintptr_t target_addr;
347 :
348 6150 : memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
349 :
350 6150 : reloc = patch->dst - patch->src;
351 :
352 :
353 6150 : for (i = 0; i < patch->num_abs64; ++i) {
354 0 : offset = patch->abs64[i].target - patch->src;
355 0 : target_addr = patch->dst + offset;
356 0 : NaClStore64(target_addr, patch->abs64[i].value);
357 : }
358 :
359 12300 : for (i = 0; i < patch->num_abs32; ++i) {
360 6150 : offset = patch->abs32[i].target - patch->src;
361 6150 : target_addr = patch->dst + offset;
362 6150 : NaClStore32(target_addr, (uint32_t) patch->abs32[i].value);
363 : }
364 :
365 12288 : for (i = 0; i < patch->num_abs16; ++i) {
366 6138 : offset = patch->abs16[i].target - patch->src;
367 6138 : target_addr = patch->dst + offset;
368 6138 : NaClStore16(target_addr, (uint16_t) patch->abs16[i].value);
369 : }
370 :
371 6150 : for (i = 0; i < patch->num_rel64; ++i) {
372 0 : offset = patch->rel64[i] - patch->src;
373 0 : target_addr = patch->dst + offset;
374 0 : NaClStore64(target_addr, NaClLoad64(target_addr) - reloc);
375 : }
376 :
377 : /*
378 : * rel32 is only supported on 32-bit architectures. The range of a relative
379 : * relocation in untrusted space is +/- 4GB. This can be represented as
380 : * an unsigned 32-bit value mod 2^32, which is handy on a 32 bit system since
381 : * all 32-bit pointer arithmetic is implicitly mod 2^32. On a 64 bit system,
382 : * however, pointer arithmetic is implicitly modulo 2^64, which isn't as
383 : * helpful for our purposes. We could simulate the 32-bit behavior by
384 : * explicitly modding all relative addresses by 2^32, but that seems like an
385 : * expensive way to save a few bytes per reloc.
386 : */
387 : #if NACL_TARGET_SUBARCH == 32
388 6153 : for (i = 0; i < patch->num_rel32; ++i) {
389 3 : offset = patch->rel32[i] - patch->src;
390 3 : target_addr = patch->dst + offset;
391 3 : NaClStore32(target_addr,
392 : (uint32_t) NaClLoad32(target_addr) - (int32_t) reloc);
393 : }
394 : #endif
395 6150 : }
396 :
397 :
398 : /*
399 : * Install syscall trampolines at all possible well-formed entry
400 : * points within the trampoline pages. Many of these syscalls will
401 : * correspond to unimplemented system calls and will just abort the
402 : * program.
403 : */
404 3 : void NaClLoadTrampoline(struct NaClApp *nap) {
405 : int num_syscalls;
406 : int i;
407 : uintptr_t addr;
408 :
409 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 && __PIC__
410 3 : if (!NaClMakePcrelThunk(nap)) {
411 0 : NaClLog(LOG_FATAL, "NaClMakePcrelThunk failed!\n");
412 : }
413 : #endif
414 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
415 : if (!NaClMakeDispatchThunk(nap)) {
416 : NaClLog(LOG_FATAL, "NaClMakeDispatchThunk failed!\n");
417 : }
418 : #endif
419 3 : NaClFillTrampolineRegion(nap);
420 :
421 : /*
422 : * Do not bother to fill in the contents of page 0, since we make it
423 : * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
424 : * anyway to help detect NULL pointer errors, and we might as well
425 : * not dirty the page.
426 : *
427 : * The last syscall entry point is used for springboard code.
428 : */
429 3 : num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR)
430 : / NACL_SYSCALL_BLOCK_SIZE) - 1;
431 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
432 : /*
433 : * Use one last entry to tell the debugger address of the nacl_user variable.
434 : */
435 3 : num_syscalls--;
436 3 : NaClPatchDebuggerInfo(nap);
437 : #endif
438 :
439 3 : NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
440 :
441 : #if defined(NACL_TARGET_ARM_THUMB2_MODE)
442 : CHECK(0 != ((nap->user_entry_pt | nap->initial_entry_pt) & 0x1));
443 : /*
444 : * Thumb trampolines start 2 bytes before the aligned syscall address used
445 : * by ordinary ARM. We initialize this by adding 0xe to the start address
446 : * of each trampoline. Because the last start address would actually start
447 : * into user code above, this allows one fewer trampolines than in ARM.
448 : */
449 : for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR + 0xe;
450 : i < num_syscalls - 1;
451 : ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
452 : NaClPatchOneTrampoline(nap, addr);
453 : }
454 : #else
455 3 : for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
456 6144 : i < num_syscalls;
457 6138 : ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
458 6138 : NaClPatchOneTrampoline(nap, addr);
459 : }
460 : #endif
461 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
462 : NaClPatchOneTrampolineCall(nap->get_tls_fast_path,
463 : nap->mem_start + NACL_SYSCALL_START_ADDR
464 : + NACL_SYSCALL_BLOCK_SIZE * NACL_sys_tls_get);
465 : #endif
466 3 : }
467 :
468 : void NaClMemRegionPrinter(void *state,
469 0 : struct NaClVmmapEntry *entry) {
470 0 : struct Gio *gp = (struct Gio *) state;
471 :
472 0 : gprintf(gp, "\nPage %"NACL_PRIdPTR" (0x%"NACL_PRIxPTR")\n",
473 : entry->page_num, entry->page_num);
474 0 : gprintf(gp, "npages %"NACL_PRIdS" (0x%"NACL_PRIxS")\n", entry->npages,
475 : entry->npages);
476 0 : gprintf(gp, "start vaddr 0x%"NACL_PRIxPTR"\n",
477 : entry->page_num << NACL_PAGESHIFT);
478 0 : gprintf(gp, "end vaddr 0x%"NACL_PRIxPTR"\n",
479 : (entry->page_num + entry->npages) << NACL_PAGESHIFT);
480 0 : gprintf(gp, "prot 0x%08x\n", entry->prot);
481 0 : gprintf(gp, "%sshared/backed by a file\n",
482 : (NULL == entry->nmop) ? "not " : "");
483 0 : }
484 :
485 : void NaClAppPrintDetails(struct NaClApp *nap,
486 0 : struct Gio *gp) {
487 0 : NaClXMutexLock(&nap->mu);
488 0 : gprintf(gp,
489 : "NaClAppPrintDetails((struct NaClApp *) 0x%08"NACL_PRIxPTR","
490 : "(struct Gio *) 0x%08"NACL_PRIxPTR")\n", (uintptr_t) nap,
491 : (uintptr_t) gp);
492 0 : gprintf(gp, "addr space size: 2**%"NACL_PRId32"\n", nap->addr_bits);
493 0 : gprintf(gp, "stack size: 0x%08"NACL_PRIx32"\n", nap->stack_size);
494 :
495 0 : gprintf(gp, "mem start addr: 0x%08"NACL_PRIxPTR"\n", nap->mem_start);
496 : /* 123456789012345678901234567890 */
497 :
498 0 : gprintf(gp, "static_text_end: 0x%08"NACL_PRIxPTR"\n", nap->static_text_end);
499 0 : gprintf(gp, "end-of-text: 0x%08"NACL_PRIxPTR"\n",
500 : NaClEndOfStaticText(nap));
501 0 : gprintf(gp, "rodata: 0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
502 0 : gprintf(gp, "data: 0x%08"NACL_PRIxPTR"\n", nap->data_start);
503 0 : gprintf(gp, "data_end: 0x%08"NACL_PRIxPTR"\n", nap->data_end);
504 0 : gprintf(gp, "break_addr: 0x%08"NACL_PRIxPTR"\n", nap->break_addr);
505 :
506 0 : gprintf(gp, "ELF initial entry point: 0x%08x\n", nap->initial_entry_pt);
507 0 : gprintf(gp, "ELF user entry point: 0x%08x\n", nap->user_entry_pt);
508 0 : gprintf(gp, "memory map:\n");
509 0 : NaClVmmapVisit(&nap->mem_map,
510 : NaClMemRegionPrinter,
511 : gp);
512 0 : NaClXMutexUnlock(&nap->mu);
513 0 : }
514 :
515 : struct NaClDesc *NaClGetDescMu(struct NaClApp *nap,
516 213 : int d) {
517 : struct NaClDesc *result;
518 :
519 213 : result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
520 213 : if (NULL != result) {
521 202 : NaClDescRef(result);
522 : }
523 :
524 213 : return result;
525 : }
526 :
527 : void NaClSetDescMu(struct NaClApp *nap,
528 : int d,
529 76 : struct NaClDesc *ndp) {
530 : struct NaClDesc *result;
531 :
532 76 : result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
533 76 : NaClDescSafeUnref(result);
534 :
535 76 : if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
536 0 : NaClLog(LOG_FATAL,
537 : "NaClSetDesc: could not set descriptor %d to 0x%08"
538 : NACL_PRIxPTR"\n",
539 : d,
540 : (uintptr_t) ndp);
541 : }
542 76 : }
543 :
544 : int32_t NaClSetAvailMu(struct NaClApp *nap,
545 15 : struct NaClDesc *ndp) {
546 : size_t pos;
547 :
548 15 : pos = DynArrayFirstAvail(&nap->desc_tbl);
549 :
550 15 : if (pos > INT32_MAX) {
551 0 : NaClLog(LOG_FATAL,
552 : ("NaClSetAvailMu: DynArrayFirstAvail returned a value"
553 : " that is greather than 2**31-1.\n"));
554 : }
555 :
556 15 : NaClSetDescMu(nap, (int) pos, ndp);
557 :
558 15 : return (int32_t) pos;
559 : }
560 :
561 : struct NaClDesc *NaClGetDesc(struct NaClApp *nap,
562 187 : int d) {
563 : struct NaClDesc *res;
564 :
565 187 : NaClXMutexLock(&nap->desc_mu);
566 187 : res = NaClGetDescMu(nap, d);
567 187 : NaClXMutexUnlock(&nap->desc_mu);
568 187 : return res;
569 : }
570 :
571 : void NaClSetDesc(struct NaClApp *nap,
572 : int d,
573 40 : struct NaClDesc *ndp) {
574 40 : NaClXMutexLock(&nap->desc_mu);
575 40 : NaClSetDescMu(nap, d, ndp);
576 40 : NaClXMutexUnlock(&nap->desc_mu);
577 40 : }
578 :
579 : int32_t NaClSetAvail(struct NaClApp *nap,
580 15 : struct NaClDesc *ndp) {
581 : int32_t pos;
582 :
583 15 : NaClXMutexLock(&nap->desc_mu);
584 15 : pos = NaClSetAvailMu(nap, ndp);
585 15 : NaClXMutexUnlock(&nap->desc_mu);
586 :
587 15 : return pos;
588 : }
589 :
590 : int NaClAddThreadMu(struct NaClApp *nap,
591 8 : struct NaClAppThread *natp) {
592 : size_t pos;
593 :
594 8 : pos = DynArrayFirstAvail(&nap->threads);
595 :
596 8 : if (!DynArraySet(&nap->threads, pos, natp)) {
597 0 : NaClLog(LOG_FATAL,
598 : "NaClAddThreadMu: DynArraySet at position %"NACL_PRIuS" failed\n",
599 : pos);
600 : }
601 8 : ++nap->num_threads;
602 8 : return (int) pos;
603 : }
604 :
605 : int NaClAddThread(struct NaClApp *nap,
606 5 : struct NaClAppThread *natp) {
607 : int pos;
608 :
609 5 : NaClXMutexLock(&nap->threads_mu);
610 5 : pos = NaClAddThreadMu(nap, natp);
611 5 : NaClXMutexUnlock(&nap->threads_mu);
612 :
613 5 : return pos;
614 : }
615 :
616 : void NaClRemoveThreadMu(struct NaClApp *nap,
617 6 : int thread_num) {
618 6 : if (NULL == DynArrayGet(&nap->threads, thread_num)) {
619 1 : NaClLog(LOG_FATAL,
620 : "NaClRemoveThreadMu:: thread to be removed is not in the table\n");
621 : }
622 5 : if (nap->num_threads == 0) {
623 0 : NaClLog(LOG_FATAL,
624 : "NaClRemoveThreadMu:: num_threads cannot be 0!!!\n");
625 : }
626 5 : --nap->num_threads;
627 5 : if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
628 0 : NaClLog(LOG_FATAL,
629 : "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
630 : thread_num);
631 : }
632 5 : }
633 :
634 : void NaClRemoveThread(struct NaClApp *nap,
635 3 : int thread_num) {
636 3 : NaClXMutexLock(&nap->threads_mu);
637 3 : NaClRemoveThreadMu(nap, thread_num);
638 2 : NaClXCondVarBroadcast(&nap->threads_cv);
639 2 : NaClXMutexUnlock(&nap->threads_mu);
640 2 : }
641 :
642 : struct NaClAppThread *NaClGetThreadMu(struct NaClApp *nap,
643 7 : int thread_num) {
644 7 : return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
645 : }
646 :
647 : void NaClAddHostDescriptor(struct NaClApp *nap,
648 : int host_os_desc,
649 : int flag,
650 36 : int nacl_desc) {
651 : struct NaClDescIoDesc *dp;
652 :
653 36 : NaClLog(4,
654 : "NaClAddHostDescriptor: host %d as nacl desc %d, flag 0x%x\n",
655 : host_os_desc,
656 : nacl_desc,
657 : flag);
658 36 : dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, flag));
659 36 : if (NULL == dp) {
660 0 : NaClLog(LOG_FATAL, "NaClAddHostDescriptor: NaClDescIoDescMake failed\n");
661 : }
662 36 : NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
663 36 : }
664 :
665 : void NaClAddImcHandle(struct NaClApp *nap,
666 : NaClHandle h,
667 0 : int nacl_desc) {
668 : struct NaClDescImcDesc *dp;
669 :
670 0 : NaClLog(4,
671 : ("NaClAddImcHandle: importing NaClHandle %"NACL_PRIxPTR
672 : " as nacl desc %d\n"),
673 : (uintptr_t) h,
674 : nacl_desc);
675 0 : dp = (struct NaClDescImcDesc *) malloc(sizeof *dp);
676 0 : if (NULL == dp) {
677 0 : NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
678 : }
679 0 : if (!NaClDescImcDescCtor(dp, h)) {
680 0 : NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
681 : " IMC descriptor object\n"));
682 : }
683 0 : NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
684 0 : }
685 :
686 :
687 12 : static void NaClProcessRedirControl(struct NaClApp *nap) {
688 : static struct {
689 : int d;
690 : char const *env_name;
691 : int nacl_flags;
692 : int mode;
693 : } redir_control[] = {
694 : { 0, "NACL_EXE_STDIN",
695 : NACL_ABI_O_RDONLY, 0, },
696 : { 1, "NACL_EXE_STDOUT",
697 : NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
698 : { 2, "NACL_EXE_STDERR",
699 : NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
700 : };
701 :
702 : size_t ix;
703 : char const *env;
704 : struct NaClDesc *ndp;
705 :
706 48 : for (ix = 0; ix < NACL_ARRAY_SIZE(redir_control); ++ix) {
707 36 : if (NULL != (env = getenv(redir_control[ix].env_name))) {
708 0 : NaClLog(4, "getenv(%s) -> %s\n", redir_control[ix].env_name, env);
709 0 : ndp = NaClResourceOpen((struct NaClResource *) &nap->resources,
710 : env,
711 : redir_control[ix].nacl_flags,
712 : redir_control[ix].mode);
713 0 : NaClLog(4, " NaClResourceOpen returned %"NACL_PRIxPTR"\n",
714 : (uintptr_t) ndp);
715 0 : if (NULL != ndp) {
716 0 : NaClLog(4, "Setting descriptor %d\n", (int) ix);
717 0 : NaClSetDesc(nap, (int) ix, ndp);
718 0 : ndp = NULL;
719 : }
720 36 : } else if (NACL_RESOURCE_PHASE_START == nap->resource_phase) {
721 : /*
722 : * Environment not set -- handle default inheritance.
723 : */
724 36 : NaClAddHostDescriptor(nap, DUP(redir_control[ix].d),
725 : redir_control[ix].nacl_flags, (int) ix);
726 : }
727 : }
728 12 : }
729 :
730 : /*
731 : * Process default descriptor inheritance. This means dup'ing
732 : * descriptors 0-2 and making them available to the NaCl App.
733 : *
734 : * When standard input is inherited, this could result in a NaCl
735 : * module competing for input from the terminal; for graphical /
736 : * browser plugin environments, this never is allowed to happen, and
737 : * having this is useful for debugging, and for potential standalone
738 : * text-mode applications of NaCl.
739 : *
740 : * TODO(bsy): consider whether default inheritance should occur only
741 : * in debug mode.
742 : */
743 12 : void NaClAppInitialDescriptorHookup(struct NaClApp *nap) {
744 :
745 12 : NaClLog(4, "Processing I/O redirection/inheritance from environment\n");
746 12 : nap->resource_phase = NACL_RESOURCE_PHASE_START;
747 12 : NaClProcessRedirControl(nap);
748 12 : NaClLog(4, "... done.\n");
749 12 : }
750 :
751 : void NaClAppVmmapUpdate(struct NaClApp *nap,
752 : uintptr_t page_num,
753 : size_t npages,
754 : int prot,
755 : struct NaClMemObj *nmop,
756 0 : int remove) {
757 0 : NaClXMutexLock(&nap->mu);
758 0 : NaClVmmapUpdate(&nap->mem_map,
759 : page_num,
760 : npages,
761 : prot,
762 : nmop,
763 : remove);
764 0 : NaClXMutexUnlock(&nap->mu);
765 0 : }
766 :
767 : uintptr_t NaClAppVmmapFindSpace(struct NaClApp *nap,
768 0 : int num_pages) {
769 : uintptr_t rv;
770 :
771 0 : NaClXMutexLock(&nap->mu);
772 0 : rv = NaClVmmapFindSpace(&nap->mem_map,
773 : num_pages);
774 0 : NaClXMutexUnlock(&nap->mu);
775 0 : return rv;
776 : }
777 :
778 : uintptr_t NaClAppVmmapFindMapSpace(struct NaClApp *nap,
779 0 : int num_pages) {
780 : uintptr_t rv;
781 :
782 0 : NaClXMutexLock(&nap->mu);
783 0 : rv = NaClVmmapFindMapSpace(&nap->mem_map,
784 : num_pages);
785 0 : NaClXMutexUnlock(&nap->mu);
786 0 : return rv;
787 : }
788 :
789 1 : void NaClCreateServiceSocket(struct NaClApp *nap) {
790 : struct NaClDesc *pair[2];
791 :
792 1 : NaClLog(3, "Entered NaClCreateServiceSocket\n");
793 1 : if (0 != NaClCommonDescMakeBoundSock(pair)) {
794 0 : NaClLog(LOG_FATAL, "Cound not create service socket\n");
795 : }
796 1 : NaClLog(4,
797 : "got bound socket at 0x%08"NACL_PRIxPTR", "
798 : "addr at 0x%08"NACL_PRIxPTR"\n",
799 : (uintptr_t) pair[0],
800 : (uintptr_t) pair[1]);
801 1 : NaClSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
802 1 : NaClSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
803 :
804 1 : NaClDescSafeUnref(nap->service_port);
805 :
806 1 : nap->service_port = pair[0];
807 1 : NaClDescRef(nap->service_port);
808 :
809 1 : NaClDescSafeUnref(nap->service_address);
810 :
811 1 : nap->service_address = pair[1];
812 1 : NaClDescRef(nap->service_address);
813 1 : NaClLog(4, "Leaving NaClCreateServiceSocket\n");
814 1 : }
815 :
816 : void NaClSendServiceAddressTo(struct NaClApp *nap,
817 0 : int desc) {
818 : struct NaClDesc *channel;
819 : struct NaClImcTypedMsgHdr hdr;
820 : ssize_t rv;
821 :
822 0 : NaClLog(4,
823 : "NaClSendServiceAddressTo(0x%08"NACL_PRIxPTR", %d)\n",
824 : (uintptr_t) nap,
825 : desc);
826 :
827 0 : channel = NaClGetDesc(nap, desc);
828 0 : if (NULL == channel) {
829 0 : NaClLog(LOG_FATAL,
830 : "NaClSendServiceAddressTo: descriptor %d not in open file table\n",
831 : desc);
832 0 : return;
833 : }
834 0 : if (NULL == nap->service_address) {
835 0 : NaClLog(LOG_FATAL,
836 : "NaClSendServiceAddressTo: service address not set\n");
837 0 : return;
838 : }
839 : /*
840 : * service_address and service_port are set together.
841 : */
842 :
843 0 : hdr.iov = (struct NaClImcMsgIoVec *) NULL;
844 0 : hdr.iov_length = 0;
845 0 : hdr.ndescv = &nap->service_address;
846 0 : hdr.ndesc_length = 1;
847 :
848 0 : rv = NaClImcSendTypedMessage(channel, &hdr, 0);
849 :
850 0 : NaClDescUnref(channel);
851 0 : channel = NULL;
852 :
853 0 : NaClLog(1,
854 : "NaClSendServiceAddressTo: descriptor %d, error %"NACL_PRIdS"\n",
855 : desc,
856 : rv);
857 : }
858 :
859 : static void NaClSecureChannelShutdownRpc(
860 : struct NaClSrpcRpc *rpc,
861 : struct NaClSrpcArg **in_args,
862 : struct NaClSrpcArg **out_args,
863 0 : struct NaClSrpcClosure *done) {
864 : UNREFERENCED_PARAMETER(rpc);
865 : UNREFERENCED_PARAMETER(in_args);
866 : UNREFERENCED_PARAMETER(out_args);
867 : UNREFERENCED_PARAMETER(done);
868 :
869 0 : NaClLog(4, "NaClSecureChannelShutdownRpc (hard_shutdown), exiting\n");
870 0 : NaClExit(0);
871 : /* Return is never reached, so no need to invoke (*done->Run)(done). */
872 0 : }
873 :
874 : /*
875 : * This RPC is invoked by the plugin when the nexe is downloaded as a
876 : * stream and not as a file. The only arguments are a handle to a
877 : * shared memory object that contains the nexe.
878 : */
879 : static void NaClLoadModuleRpc(struct NaClSrpcRpc *rpc,
880 : struct NaClSrpcArg **in_args,
881 : struct NaClSrpcArg **out_args,
882 0 : struct NaClSrpcClosure *done) {
883 : struct NaClApp *nap =
884 0 : (struct NaClApp *) rpc->channel->server_instance_data;
885 0 : struct NaClDesc *nexe_binary = in_args[0]->u.hval;
886 : struct NaClGioShm gio_shm;
887 : struct NaClGioNaClDesc gio_desc;
888 0 : struct Gio *load_src = NULL;
889 : struct nacl_abi_stat stbuf;
890 : char *aux;
891 : int rval;
892 0 : NaClErrorCode suberr = LOAD_INTERNAL;
893 : size_t rounded_size;
894 :
895 : UNREFERENCED_PARAMETER(out_args);
896 :
897 0 : NaClLog(4, "NaClLoadModuleRpc: entered\n");
898 :
899 0 : rpc->result = NACL_SRPC_RESULT_INTERNAL;
900 :
901 0 : aux = strdup(in_args[1]->arrays.str);
902 0 : if (NULL == aux) {
903 0 : rpc->result = NACL_SRPC_RESULT_NO_MEMORY;
904 0 : goto cleanup;
905 : }
906 0 : NaClLog(4, "Received aux_info: %s\n", aux);
907 :
908 0 : switch (NACL_VTBL(NaClDesc, nexe_binary)->typeTag) {
909 : case NACL_DESC_SHM:
910 : /*
911 : * We don't know the actual size of the nexe, but it should not
912 : * matter. The shared memory object's size is rounded up to at
913 : * least 4K, and we can map it in with uninitialized data (should be
914 : * zero filled) at the end.
915 : */
916 0 : NaClLog(4, "NaClLoadModuleRpc: finding shm size\n");
917 :
918 0 : rval = (*NACL_VTBL(NaClDesc, nexe_binary)->
919 : Fstat)(nexe_binary, &stbuf);
920 0 : if (0 != rval) {
921 0 : goto cleanup;
922 : }
923 :
924 0 : rounded_size = (size_t) stbuf.nacl_abi_st_size;
925 :
926 0 : NaClLog(4, "NaClLoadModuleRpc: shm size 0x%"NACL_PRIxS"\n", rounded_size);
927 :
928 0 : if (!NaClGioShmCtor(&gio_shm, nexe_binary, rounded_size)) {
929 0 : rpc->result = NACL_SRPC_RESULT_NO_MEMORY;
930 0 : goto cleanup;
931 : }
932 0 : load_src = (struct Gio *) &gio_shm;
933 0 : break;
934 :
935 : case NACL_DESC_HOST_IO:
936 0 : NaClLog(4, "NaClLoadModuleRpc: creating Gio from NaClDescHostDesc\n");
937 :
938 0 : if (!NaClGioNaClDescCtor(&gio_desc, nexe_binary)) {
939 0 : rpc->result = NACL_SRPC_RESULT_NO_MEMORY;
940 0 : goto cleanup;
941 : }
942 0 : load_src = (struct Gio *) &gio_desc;
943 0 : break;
944 :
945 : case NACL_DESC_INVALID:
946 : case NACL_DESC_DIR:
947 : case NACL_DESC_CONN_CAP:
948 : case NACL_DESC_CONN_CAP_FD:
949 : case NACL_DESC_BOUND_SOCKET:
950 : case NACL_DESC_CONNECTED_SOCKET:
951 : case NACL_DESC_SYSV_SHM:
952 : case NACL_DESC_MUTEX:
953 : case NACL_DESC_CONDVAR:
954 : case NACL_DESC_SEMAPHORE:
955 : case NACL_DESC_SYNC_SOCKET:
956 : case NACL_DESC_TRANSFERABLE_DATA_SOCKET:
957 : case NACL_DESC_IMC_SOCKET:
958 : case NACL_DESC_QUOTA:
959 : case NACL_DESC_DEVICE_RNG:
960 : case NACL_DESC_DEVICE_POSTMESSAGE:
961 : /* Unsupported stuff */
962 0 : rpc->result = NACL_SRPC_RESULT_APP_ERROR;
963 0 : goto cleanup;
964 : }
965 :
966 : /*
967 : * do not use default case label, to make sure that the compiler
968 : * will generate a warning with -Wswitch-enum for new entries in
969 : * NaClDescTypeTag introduced in nacl_desc_base.h for which there is no
970 : * corresponding entry here. instead, we pretend that fall-through
971 : * from the switch is possible.
972 : */
973 0 : if (NULL == load_src) {
974 0 : NaClLog(LOG_FATAL, "nexe_binary's typeTag has unsupported value: %d\n",
975 : NACL_VTBL(NaClDesc, nexe_binary)->typeTag);
976 : }
977 :
978 : /*
979 : * TODO(bsy): consider doing the processing below after sending the
980 : * RPC reply to increase parallelism.
981 : */
982 :
983 0 : NaClXMutexLock(&nap->mu);
984 :
985 0 : if (LOAD_STATUS_UNKNOWN != nap->module_load_status) {
986 0 : NaClLog(LOG_ERROR, "Repeated LoadModule RPC, or platform qual error?!?\n");
987 0 : if (LOAD_OK == nap->module_load_status) {
988 0 : NaClLog(LOG_ERROR, "LoadModule when module_load_status is LOAD_OK?!?\n");
989 0 : suberr = LOAD_DUP_LOAD_MODULE;
990 0 : nap->module_load_status = suberr;
991 : } else {
992 0 : suberr = nap->module_load_status;
993 : }
994 0 : rpc->result = NACL_SRPC_RESULT_OK;
995 0 : NaClXCondVarBroadcast(&nap->cv);
996 0 : goto cleanup_status_mu;
997 : }
998 :
999 0 : free(nap->aux_info);
1000 0 : nap->aux_info = aux;
1001 :
1002 0 : suberr = NACL_FI_VAL("load_module", NaClErrorCode,
1003 : NaClAppLoadFile(load_src, nap));
1004 0 : (*NACL_VTBL(Gio, load_src)->Close)(load_src);
1005 0 : (*NACL_VTBL(Gio, load_src)->Dtor)(load_src);
1006 :
1007 0 : if (LOAD_OK != suberr) {
1008 0 : nap->module_load_status = suberr;
1009 0 : rpc->result = NACL_SRPC_RESULT_OK;
1010 0 : NaClXCondVarBroadcast(&nap->cv);
1011 : }
1012 :
1013 0 : cleanup_status_mu:
1014 0 : NaClXMutexUnlock(&nap->mu); /* NaClAppPrepareToLaunch takes mu */
1015 0 : if (LOAD_OK != suberr) {
1016 0 : goto cleanup;
1017 : }
1018 :
1019 : /***************************************************************************
1020 : * TODO(bsy): Remove/merge the code invoking NaClAppPrepareToLaunch
1021 : * and NaClGdbHook below with sel_main's main function. See comment
1022 : * there.
1023 : ***************************************************************************/
1024 :
1025 : /*
1026 : * Finish setting up the NaCl App.
1027 : */
1028 0 : suberr = NaClAppPrepareToLaunch(nap);
1029 :
1030 0 : NaClXMutexLock(&nap->mu);
1031 :
1032 0 : nap->module_load_status = suberr;
1033 0 : rpc->result = NACL_SRPC_RESULT_OK;
1034 :
1035 0 : NaClXCondVarBroadcast(&nap->cv);
1036 0 : NaClXMutexUnlock(&nap->mu);
1037 :
1038 : /* Give debuggers a well known point at which xlate_base is known. */
1039 0 : NaClGdbHook(nap);
1040 :
1041 0 : cleanup:
1042 :
1043 0 : NaClDescUnref(nexe_binary);
1044 0 : nexe_binary = NULL;
1045 0 : (*done->Run)(done);
1046 0 : }
1047 :
1048 : #if NACL_WINDOWS && !defined(NACL_STANDALONE)
1049 : /*
1050 : * This RPC is invoked by the plugin as part of the initialization process and
1051 : * provides the NaCl process with a socket address that can later be used for
1052 : * pid to process handle mapping queries. This is required to enable IMC handle
1053 : * passing inside the Chrome sandbox.
1054 : */
1055 : static void NaClInitHandlePassingRpc(struct NaClSrpcRpc *rpc,
1056 : struct NaClSrpcArg **in_args,
1057 : struct NaClSrpcArg **out_args,
1058 : struct NaClSrpcClosure *done) {
1059 : struct NaClApp *nap = (struct NaClApp *) rpc->channel->server_instance_data;
1060 : NaClSrpcImcDescType handle_passing_socket_address = in_args[0]->u.hval;
1061 : DWORD renderer_pid = in_args[1]->u.ival;
1062 : NaClHandle renderer_handle = (NaClHandle)in_args[2]->u.ival;
1063 : UNREFERENCED_PARAMETER(out_args);
1064 : if (!NaClHandlePassLdrCtor(handle_passing_socket_address,
1065 : renderer_pid,
1066 : renderer_handle)) {
1067 : rpc->result = NACL_SRPC_RESULT_APP_ERROR;
1068 : } else {
1069 : rpc->result = NACL_SRPC_RESULT_OK;
1070 : }
1071 : (*done->Run)(done);
1072 : }
1073 : #endif
1074 :
1075 0 : NaClErrorCode NaClWaitForLoadModuleStatus(struct NaClApp *nap) {
1076 : NaClErrorCode status;
1077 :
1078 0 : NaClXMutexLock(&nap->mu);
1079 0 : while (LOAD_STATUS_UNKNOWN == (status = nap->module_load_status)) {
1080 0 : NaClXCondVarWait(&nap->cv, &nap->mu);
1081 : }
1082 0 : NaClXMutexUnlock(&nap->mu);
1083 0 : return status;
1084 : }
1085 :
1086 : static void NaClSecureChannelStartModuleRpc(struct NaClSrpcRpc *rpc,
1087 : struct NaClSrpcArg **in_args,
1088 : struct NaClSrpcArg **out_args,
1089 0 : struct NaClSrpcClosure *done) {
1090 : /*
1091 : * let module start if module is okay; otherwise report error (e.g.,
1092 : * ABI version mismatch).
1093 : */
1094 0 : struct NaClApp *nap = (struct NaClApp *) rpc->channel->server_instance_data;
1095 : NaClErrorCode status;
1096 :
1097 : UNREFERENCED_PARAMETER(in_args);
1098 :
1099 0 : NaClLog(4,
1100 : "NaClSecureChannelStartModuleRpc started, nap 0x%"NACL_PRIxPTR"\n",
1101 : (uintptr_t) nap);
1102 :
1103 0 : status = NaClWaitForLoadModuleStatus(nap);
1104 :
1105 0 : NaClLog(4, "NaClSecureChannelStartModuleRpc: load status %d\n", status);
1106 :
1107 0 : out_args[0]->u.ival = status;
1108 0 : rpc->result = NACL_SRPC_RESULT_OK;
1109 :
1110 0 : NaClLog(4, "NaClSecureChannelStartModuleRpc running closure\n");
1111 0 : (*done->Run)(done);
1112 : /*
1113 : * The RPC reply is now sent. This has to occur before we signal
1114 : * the main thread to possibly start, since in the case of a failure
1115 : * the main thread may quickly exit. If the main thread does this
1116 : * before we sent the RPC reply, then the plugin will be left
1117 : * without an answer.
1118 : */
1119 :
1120 0 : NaClXMutexLock(&nap->mu);
1121 0 : if (nap->module_may_start) {
1122 0 : NaClLog(LOG_ERROR, "Duplicate StartModule RPC?!?\n");
1123 0 : status = LOAD_DUP_START_MODULE;
1124 : } else {
1125 0 : nap->module_may_start = 1;
1126 : }
1127 0 : NaClLog(4, "NaClSecureChannelStartModuleRpc: broadcasting\n");
1128 0 : NaClXCondVarBroadcast(&nap->cv);
1129 0 : NaClXMutexUnlock(&nap->mu);
1130 :
1131 0 : NaClLog(4, "NaClSecureChannelStartModuleRpc exiting\n");
1132 0 : }
1133 :
1134 : static void NaClSecureChannelLog(struct NaClSrpcRpc *rpc,
1135 : struct NaClSrpcArg **in_args,
1136 : struct NaClSrpcArg **out_args,
1137 0 : struct NaClSrpcClosure *done) {
1138 0 : int severity = in_args[0]->u.ival;
1139 0 : char *msg = in_args[1]->arrays.str;
1140 :
1141 : UNREFERENCED_PARAMETER(out_args);
1142 :
1143 0 : NaClLog(5, "NaClSecureChannelLog started\n");
1144 0 : NaClLog(severity, "%s\n", msg);
1145 0 : NaClLog(5, "NaClSecureChannelLog finished\n");
1146 0 : rpc->result = NACL_SRPC_RESULT_OK;
1147 0 : (*done->Run)(done);
1148 0 : }
1149 :
1150 0 : NaClErrorCode NaClWaitForStartModuleCommand(struct NaClApp *nap) {
1151 : NaClErrorCode status;
1152 :
1153 0 : NaClLog(4, "NaClWaitForStartModuleCommand started\n");
1154 0 : NaClXMutexLock(&nap->mu);
1155 0 : while (!nap->module_may_start) {
1156 0 : NaClXCondVarWait(&nap->cv, &nap->mu);
1157 0 : NaClLog(4,
1158 : "NaClWaitForStartModuleCommand: awaken, module_may_start %d\n",
1159 : nap->module_may_start);
1160 : }
1161 0 : status = nap->module_load_status;
1162 0 : NaClXMutexUnlock(&nap->mu);
1163 0 : NaClLog(4, "NaClWaitForStartModuleCommand finished\n");
1164 :
1165 0 : return status;
1166 : }
1167 :
1168 8 : void NaClBlockIfCommandChannelExists(struct NaClApp *nap) {
1169 8 : if (NULL != nap->secure_service) {
1170 : for (;;) {
1171 : struct nacl_abi_timespec req;
1172 0 : req.tv_sec = 1000;
1173 0 : req.tv_nsec = 0;
1174 0 : NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL);
1175 0 : }
1176 : }
1177 8 : }
1178 :
1179 :
1180 : /*
1181 : * Secure command channels.
1182 : */
1183 :
1184 : struct NaClSecureService {
1185 : struct NaClSimpleService base;
1186 : struct NaClApp *nap;
1187 : };
1188 :
1189 : struct NaClSimpleServiceVtbl const kNaClSecureServiceVtbl;
1190 :
1191 :
1192 : struct NaClConnectionHandler {
1193 : struct NaClConnectionHandler *next;
1194 :
1195 : /* used by NaClSimpleRevServiceClient's ClientCallback fn */
1196 : void (*handler)(
1197 : void *state,
1198 : struct NaClThreadInterface *tif,
1199 : struct NaClDesc *conn);
1200 : void *state;
1201 : };
1202 :
1203 : struct NaClSecureReverseClient {
1204 : struct NaClSimpleRevClient base;
1205 : struct NaClApp *nap;
1206 :
1207 : struct NaClMutex mu;
1208 :
1209 : struct NaClConnectionHandler *queue_head;
1210 : struct NaClConnectionHandler **queue_insert;
1211 : };
1212 :
1213 : struct NaClSimpleRevClientVtbl const kNaClSecureReverseClientVtbl;
1214 :
1215 :
1216 : int NaClSecureServiceCtor(struct NaClSecureService *self,
1217 : struct NaClSrpcHandlerDesc const *srpc_handlers,
1218 0 : struct NaClApp *nap) {
1219 0 : NaClLog(4,
1220 : "Entered NaClSecureServiceCtor: self 0x%"NACL_PRIxPTR"\n",
1221 : (uintptr_t) self);
1222 0 : if (!NaClSimpleServiceWithSocketCtor(&self->base,
1223 : srpc_handlers,
1224 : NaClThreadInterfaceThreadFactory,
1225 : (void *) NULL,
1226 : nap->service_port,
1227 : nap->service_address)) {
1228 0 : goto failure_simple_ctor;
1229 : }
1230 0 : self->nap = nap;
1231 :
1232 0 : NACL_VTBL(NaClRefCount, self) =
1233 : (struct NaClRefCountVtbl *) &kNaClSecureServiceVtbl;
1234 0 : return 1;
1235 0 : failure_simple_ctor:
1236 0 : return 0;
1237 : }
1238 :
1239 0 : void NaClSecureServiceDtor(struct NaClRefCount *vself) {
1240 0 : struct NaClSecureService *self = (struct NaClSecureService *) vself;
1241 :
1242 0 : NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl const *)
1243 : &kNaClSimpleServiceVtbl;
1244 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
1245 0 : }
1246 :
1247 : /*
1248 : * The first connection is performed by this callback handler. This
1249 : * spawns a client thread that will bootstrap the other connections by
1250 : * stashing the connection represented by |conn| to make reverse RPCs
1251 : * to ask the peer to connect to us. No thread is spawned; we just
1252 : * wrap access to the connection with a lock.
1253 : *
1254 : * Subsequent connection callbacks will pass the connection to the
1255 : * actual thread that made the connection request using |conn|
1256 : * received in the first connection.
1257 : */
1258 : static void NaClSecureReverseClientCallback(
1259 : void *state,
1260 : struct NaClThreadInterface *tif,
1261 0 : struct NaClDesc *new_conn) {
1262 : struct NaClSecureReverseClient *self =
1263 0 : (struct NaClSecureReverseClient *) state;
1264 0 : struct NaClApp *nap = self->nap;
1265 :
1266 : UNREFERENCED_PARAMETER(tif);
1267 :
1268 0 : NaClLog(4, "Entered NaClSecureReverseClientCallback\n");
1269 :
1270 0 : NaClLog(4, " self=0x%"NACL_PRIxPTR"\n", (uintptr_t) self);
1271 0 : NaClLog(4, " nap=0x%"NACL_PRIxPTR"\n", (uintptr_t) nap);
1272 0 : NaClXMutexLock(&nap->mu);
1273 :
1274 0 : if (NACL_REVERSE_CHANNEL_INITIALIZATION_STARTED !=
1275 : nap->reverse_channel_initialization_state) {
1276 : /*
1277 : * The reverse channel connection capability is used to make the
1278 : * RPC that invokes this callback (this callback is invoked on a
1279 : * reverse channel connect), so the plugin wants to initialize the
1280 : * reverse channel and in particular the state must be either be
1281 : * in-progress or finished.
1282 : */
1283 0 : NaClLog(LOG_FATAL, "Reverse channel already initialized\n");
1284 : }
1285 0 : if (!NaClSrpcClientCtor(&nap->reverse_channel, new_conn)) {
1286 0 : NaClLog(LOG_FATAL, "Reverse channel SRPC Client Ctor failed\n");
1287 : }
1288 0 : nap->reverse_quota_interface = (struct NaClReverseQuotaInterface *)
1289 : malloc(sizeof *nap->reverse_quota_interface);
1290 0 : if (NULL == nap->reverse_quota_interface ||
1291 : !NaClReverseQuotaInterfaceCtor(nap->reverse_quota_interface, nap)) {
1292 0 : NaClLog(LOG_FATAL, "Reverse quota interface Ctor failed\n");
1293 : }
1294 0 : nap->reverse_channel_initialization_state = NACL_REVERSE_CHANNEL_INITIALIZED;
1295 :
1296 0 : NaClXCondVarBroadcast(&nap->cv);
1297 0 : NaClXMutexUnlock(&nap->mu);
1298 :
1299 0 : NaClLog(4, "Leaving NaClSecureReverseClientCallback\n");
1300 0 : }
1301 :
1302 : /* fwd */
1303 : int NaClSecureReverseClientCtor(
1304 : struct NaClSecureReverseClient *self,
1305 : void (*client_callback)(
1306 : void *, struct NaClThreadInterface *, struct NaClDesc *),
1307 : void *state,
1308 : struct NaClApp *nap);
1309 :
1310 : static void NaClSecureReverseClientSetup(struct NaClSrpcRpc *rpc,
1311 : struct NaClSrpcArg **in_args,
1312 : struct NaClSrpcArg **out_args,
1313 0 : struct NaClSrpcClosure *done) {
1314 : struct NaClApp *nap =
1315 0 : (struct NaClApp *) rpc->channel->server_instance_data;
1316 : struct NaClSecureReverseClient *rev;
1317 :
1318 : UNREFERENCED_PARAMETER(in_args);
1319 0 : NaClLog(4, "Entered NaClSecureReverseClientSetup\n");
1320 :
1321 0 : NaClXMutexLock(&nap->mu);
1322 0 : if (NULL != nap->reverse_client) {
1323 0 : NaClLog(LOG_FATAL, "Double reverse setup RPC\n");
1324 : }
1325 0 : if (NACL_REVERSE_CHANNEL_UNINITIALIZED !=
1326 : nap->reverse_channel_initialization_state) {
1327 0 : NaClLog(LOG_FATAL,
1328 : "Reverse channel initialization state not uninitialized\n");
1329 : }
1330 0 : nap->reverse_channel_initialization_state =
1331 : NACL_REVERSE_CHANNEL_INITIALIZATION_STARTED;
1332 : /* the reverse connection is still coming */
1333 0 : rev = (struct NaClSecureReverseClient *) malloc(sizeof *rev);
1334 0 : if (NULL == rev) {
1335 0 : rpc->result = NACL_SRPC_RESULT_APP_ERROR;
1336 0 : goto done;
1337 : }
1338 0 : NaClLog(4,
1339 : "NaClSecureReverseClientSetup: invoking"
1340 : " NaClSecureReverseClientCtor\n");
1341 0 : if (!NaClSecureReverseClientCtor(rev,
1342 : NaClSecureReverseClientCallback,
1343 : (void *) rev,
1344 : nap)) {
1345 0 : free(rev);
1346 0 : rpc->result = NACL_SRPC_RESULT_APP_ERROR;
1347 0 : goto done;
1348 : }
1349 0 : nap->reverse_client = (struct NaClSecureReverseClient *) NaClRefCountRef(
1350 : (struct NaClRefCount *) rev);
1351 0 : out_args[0]->u.hval = NaClDescRef(rev->base.bound_and_cap[1]);
1352 0 : rpc->result = NACL_SRPC_RESULT_OK;
1353 :
1354 : /*
1355 : * Hook up reverse-channel enabled resources, e.g.,
1356 : * DEBUG_ONLY:dev://postmessage. NB: Resources specified by
1357 : * file:path should have been taken care of earlier, in
1358 : * NaClAppInitialDescriptorHookup.
1359 : */
1360 0 : nap->resource_phase = NACL_RESOURCE_PHASE_REV_CHAN;
1361 0 : NaClLog(4, "Processing dev I/O redirection/inheritance from environment\n");
1362 0 : NaClProcessRedirControl(nap);
1363 0 : NaClLog(4, "... done.\n");
1364 :
1365 : /*
1366 : * Service thread takes the reference rev.
1367 : */
1368 0 : if (!NaClSimpleRevClientStartServiceThread(&rev->base)) {
1369 0 : NaClLog(LOG_FATAL, "Could not start reverse service thread\n");
1370 : }
1371 :
1372 0 : done:
1373 0 : NaClXMutexUnlock(&nap->mu);
1374 0 : (*done->Run)(done);
1375 0 : NaClLog(4, "Leaving NaClSecureReverseClientSetup\n");
1376 0 : }
1377 :
1378 : /*
1379 : * Only called at startup and thereafter by the reverse secure
1380 : * channel, with |self| locked.
1381 : */
1382 : static
1383 : int NaClSecureReverseClientInsertHandler_mu(
1384 : struct NaClSecureReverseClient *self,
1385 : void (*h)(void *,
1386 : struct NaClThreadInterface *,
1387 : struct NaClDesc *),
1388 0 : void *d) {
1389 : struct NaClConnectionHandler *entry;
1390 :
1391 0 : NaClLog(4,
1392 : ("NaClSecureReverseClientInsertHandler_mu: h 0x%"NACL_PRIxPTR","
1393 : " d 0x%"NACL_PRIxPTR"\n"),
1394 : (uintptr_t) h,
1395 : (uintptr_t) d);
1396 0 : entry = (struct NaClConnectionHandler *) malloc(sizeof *entry);
1397 0 : if (NULL == entry) {
1398 0 : return 0;
1399 : }
1400 0 : entry->handler = h;
1401 0 : entry->state = d;
1402 0 : entry->next = (struct NaClConnectionHandler *) NULL;
1403 0 : *self->queue_insert = entry;
1404 0 : self->queue_insert = &entry->next;
1405 :
1406 0 : return 1;
1407 : }
1408 :
1409 : /*
1410 : * Caller must set up handler before issuing connection request RPC on
1411 : * nap->reverse_channel, since otherwise the connection handler queue
1412 : * may be empty and the connect code would abort. Because the connect
1413 : * doesn't wait for a handler, we don't need a condvar.
1414 : *
1415 : * We do not need to serialize on the handlers, since the
1416 : * RPC-server/IMC-client implementation should not distinguish one
1417 : * connection from another: it is okay for two handlers to be
1418 : * inserted, and two connection request RPCs to be preformed
1419 : * (sequentially, since they are over a single channel), and have the
1420 : * server side spawn threads that asynchronously connect twice, in the
1421 : * "incorrect" order, etc.
1422 : */
1423 : int NaClSecureReverseClientInsertHandler(
1424 : struct NaClSecureReverseClient *self,
1425 : void (*handler)(
1426 : void *handlr_state,
1427 : struct NaClThreadInterface *thread_if,
1428 : struct NaClDesc *new_conn),
1429 0 : void *handler_state) {
1430 : int retval;
1431 :
1432 0 : NaClXMutexLock(&self->mu);
1433 0 : retval = NaClSecureReverseClientInsertHandler_mu(self,
1434 : handler, handler_state);
1435 0 : NaClXMutexUnlock(&self->mu);
1436 0 : return retval;
1437 : }
1438 :
1439 : static
1440 : struct NaClConnectionHandler *NaClSecureReverseClientPopHandler(
1441 0 : struct NaClSecureReverseClient *self) {
1442 : struct NaClConnectionHandler *head;
1443 :
1444 0 : NaClLog(4, "Entered NaClSecureReverseClientPopHandler, acquiring lock\n");
1445 0 : NaClXMutexLock(&self->mu);
1446 0 : NaClLog(4, "NaClSecureReverseClientPopHandler, got lock\n");
1447 0 : head = self->queue_head;
1448 0 : if (NULL == head) {
1449 0 : NaClLog(LOG_FATAL,
1450 : "NaClSecureReverseClientPopHandler: empty handler queue\n");
1451 : }
1452 0 : if (NULL == (self->queue_head = head->next)) {
1453 0 : NaClLog(4, "NaClSecureReverseClientPopHandler, last elt patch up\n");
1454 0 : self->queue_insert = &self->queue_head;
1455 : }
1456 0 : NaClLog(4, "NaClSecureReverseClientPopHandler, unlocking\n");
1457 0 : NaClXMutexUnlock(&self->mu);
1458 :
1459 0 : head->next = NULL;
1460 0 : NaClLog(4,
1461 : ("Leaving NaClSecureReverseClientPopHandler:"
1462 : " returning %"NACL_PRIxPTR"\n"),
1463 : (uintptr_t) head);
1464 0 : return head;
1465 : }
1466 :
1467 : static
1468 : void NaClSecureReverseClientInternalCallback(
1469 : void *state,
1470 : struct NaClThreadInterface *tif,
1471 0 : struct NaClDesc *conn) {
1472 : struct NaClSecureReverseClient *self =
1473 0 : (struct NaClSecureReverseClient *) state;
1474 : struct NaClConnectionHandler *hand_ptr;
1475 :
1476 : UNREFERENCED_PARAMETER(tif);
1477 0 : NaClLog(4, "Entered NaClSecureReverseClientInternalCallback\n");
1478 0 : hand_ptr = NaClSecureReverseClientPopHandler(self);
1479 0 : NaClLog(4, " got callback object %"NACL_PRIxPTR"\n", (uintptr_t) hand_ptr);
1480 0 : NaClLog(4,
1481 : " callback:0x%"NACL_PRIxPTR"(0x%"NACL_PRIxPTR",0x%"NACL_PRIxPTR")\n",
1482 : (uintptr_t) hand_ptr->handler,
1483 : (uintptr_t) hand_ptr->state,
1484 : (uintptr_t) conn);
1485 0 : (*hand_ptr->handler)(hand_ptr->state, tif, conn);
1486 0 : NaClLog(4, "NaClSecureReverseClientInternalCallback: freeing memory\n");
1487 0 : free(hand_ptr);
1488 0 : NaClLog(4, "Leaving NaClSecureReverseClientInternalCallback\n");
1489 0 : }
1490 :
1491 : /*
1492 : * Require an initial connection handler in the Ctor, so that it's
1493 : * obvious that a reverse client needs to accept an IMC connection
1494 : * from the server to get things bootstrapped.
1495 : */
1496 : int NaClSecureReverseClientCtor(
1497 : struct NaClSecureReverseClient *self,
1498 : void (*client_callback)(
1499 : void *, struct NaClThreadInterface*, struct NaClDesc *),
1500 : void *state,
1501 0 : struct NaClApp *nap) {
1502 0 : NaClLog(4,
1503 : ("Entered NaClSecureReverseClientCtor, self 0x%"NACL_PRIxPTR","
1504 : " nap 0x%"NACL_PRIxPTR"\n"),
1505 : (uintptr_t) self,
1506 : (uintptr_t) nap);
1507 0 : if (!NaClSimpleRevClientCtor(&self->base,
1508 : NaClSecureReverseClientInternalCallback,
1509 : (void *) self,
1510 : NaClThreadInterfaceThreadFactory,
1511 : (void *) NULL)) {
1512 0 : goto failure_simple_ctor;
1513 : }
1514 0 : NaClLog(4, "NaClSecureReverseClientCtor: Mutex\n");
1515 0 : if (!NaClMutexCtor(&self->mu)) {
1516 0 : goto failure_mutex_ctor;
1517 : }
1518 0 : self->nap = nap;
1519 0 : self->queue_head = (struct NaClConnectionHandler *) NULL;
1520 0 : self->queue_insert = &self->queue_head;
1521 :
1522 0 : NACL_VTBL(NaClRefCount, self) =
1523 : (struct NaClRefCountVtbl *) &kNaClSecureReverseClientVtbl;
1524 :
1525 0 : NaClLog(4, "NaClSecureReverseClientCtor: InsertHandler\n");
1526 0 : if (!NaClSecureReverseClientInsertHandler(self,
1527 : client_callback,
1528 : state)) {
1529 0 : goto failure_handler_insert;
1530 : }
1531 :
1532 0 : NaClLog(4, "Leaving NaClSecureReverseClientCtor\n");
1533 0 : return 1;
1534 :
1535 0 : failure_handler_insert:
1536 0 : NaClLog(4, "NaClSecureReverseClientCtor: InsertHandler failed\n");
1537 0 : NACL_VTBL(NaClRefCount, self) =
1538 : (struct NaClRefCountVtbl *) &kNaClSimpleRevClientVtbl;
1539 :
1540 0 : self->nap = NULL;
1541 0 : self->queue_insert = (struct NaClConnectionHandler **) NULL;
1542 0 : NaClMutexDtor(&self->mu);
1543 :
1544 0 : failure_mutex_ctor:
1545 0 : NaClLog(4, "NaClSecureReverseClientCtor: Mutex failed\n");
1546 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
1547 0 : failure_simple_ctor:
1548 0 : NaClLog(4, "Leaving NaClSecureReverseClientCtor\n");
1549 0 : return 0;
1550 : }
1551 :
1552 0 : void NaClSecureReverseClientDtor(struct NaClRefCount *vself) {
1553 : struct NaClSecureReverseClient *self =
1554 0 : (struct NaClSecureReverseClient *) vself;
1555 :
1556 : struct NaClConnectionHandler *entry;
1557 : struct NaClConnectionHandler *next;
1558 :
1559 0 : for (entry = self->queue_head; NULL != entry; entry = next) {
1560 0 : next = entry->next;
1561 0 : free(entry);
1562 : }
1563 0 : NaClMutexDtor(&self->mu);
1564 :
1565 0 : NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl const *)
1566 : &kNaClSimpleRevClientVtbl;
1567 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
1568 0 : }
1569 :
1570 : int NaClSecureServiceConnectionFactory(
1571 : struct NaClSimpleService *vself,
1572 : struct NaClDesc *conn,
1573 0 : struct NaClSimpleServiceConnection **out) {
1574 : struct NaClSecureService *self =
1575 0 : (struct NaClSecureService *) vself;
1576 :
1577 : /* our instance_data is not connection specific */
1578 0 : return NaClSimpleServiceConnectionFactoryWithInstanceData(
1579 : vself, conn, (void *) self->nap, out);
1580 : }
1581 :
1582 0 : int NaClSecureServiceAcceptAndSpawnHandler(struct NaClSimpleService *vself) {
1583 : int rv;
1584 :
1585 0 : NaClLog(4,
1586 : "NaClSecureServiceAcceptAndSpawnHandler: invoking base class vfn\n");
1587 0 : rv = (*kNaClSimpleServiceVtbl.AcceptAndSpawnHandler)(vself);
1588 0 : if (0 != rv) {
1589 0 : NaClLog(LOG_FATAL,
1590 : "Secure channel AcceptAndSpawnHandler returned %d\n",
1591 : rv);
1592 : }
1593 0 : NaClThreadExit(0);
1594 : /*
1595 : * NOTREACHED The port is now to be used by untrusted code: all
1596 : * subsequent connections are handled there.
1597 : */
1598 0 : return rv;
1599 : }
1600 :
1601 : void NaClSecureServiceRpcHandler(struct NaClSimpleService *vself,
1602 0 : struct NaClSimpleServiceConnection *vconn) {
1603 :
1604 0 : NaClLog(4, "NaClSecureChannelThread started\n");
1605 0 : (*kNaClSimpleServiceVtbl.RpcHandler)(vself, vconn);
1606 0 : NaClLog(4, "NaClSecureChannelThread: channel closed, exiting.\n");
1607 0 : NaClExit(0);
1608 0 : }
1609 :
1610 : struct NaClSimpleServiceVtbl const kNaClSecureServiceVtbl = {
1611 : {
1612 : NaClSecureServiceDtor,
1613 : },
1614 : NaClSecureServiceConnectionFactory,
1615 : NaClSimpleServiceAcceptConnection,
1616 : NaClSecureServiceAcceptAndSpawnHandler,
1617 : NaClSecureServiceRpcHandler,
1618 : };
1619 :
1620 : struct NaClSimpleRevClientVtbl const kNaClSecureReverseClientVtbl = {
1621 : {
1622 : NaClSecureReverseClientDtor,
1623 : },
1624 : };
1625 :
1626 :
1627 0 : void NaClSecureCommandChannel(struct NaClApp *nap) {
1628 : struct NaClSecureService *secure_command_server;
1629 :
1630 : static struct NaClSrpcHandlerDesc const secure_handlers[] = {
1631 : { "hard_shutdown::", NaClSecureChannelShutdownRpc, },
1632 : { "start_module::i", NaClSecureChannelStartModuleRpc, },
1633 : { "log:is:", NaClSecureChannelLog, },
1634 : { "load_module:hs:", NaClLoadModuleRpc, },
1635 : #if NACL_WINDOWS && !defined(NACL_STANDALONE)
1636 : { "init_handle_passing:hii:", NaClInitHandlePassingRpc, },
1637 : #endif
1638 : { "reverse_setup::h", NaClSecureReverseClientSetup, },
1639 : /* add additional calls here. upcall set up? start module signal? */
1640 : { (char const *) NULL, (NaClSrpcMethod) NULL, },
1641 : };
1642 :
1643 0 : NaClLog(4, "Entered NaClSecureCommandChannel\n");
1644 :
1645 0 : secure_command_server = (struct NaClSecureService *) malloc(
1646 : sizeof *secure_command_server);
1647 0 : if (NULL == secure_command_server) {
1648 0 : NaClLog(LOG_FATAL, "Out of memory for secure command channel\n");
1649 : }
1650 0 : if (!NaClSecureServiceCtor(secure_command_server, secure_handlers, nap)) {
1651 0 : NaClLog(LOG_FATAL, "NaClSecureServiceCtor failed\n");
1652 : }
1653 0 : nap->secure_service = secure_command_server;
1654 :
1655 0 : NaClLog(4, "NaClSecureCommandChannel: starting service thread\n");
1656 0 : if (!NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
1657 : secure_command_server)) {
1658 0 : NaClLog(LOG_FATAL,
1659 : "Could not start secure command channel service thread\n");
1660 : }
1661 :
1662 0 : NaClLog(4, "Leaving NaClSecureCommandChannel\n");
1663 0 : }
1664 :
1665 :
1666 9 : void NaClVmHoleWaitToStartThread(struct NaClApp *nap) {
1667 9 : NaClXMutexLock(&nap->mu);
1668 :
1669 : /* ensure no virtual memory hole may appear */
1670 18 : while (nap->vm_hole_may_exist) {
1671 0 : NaClXCondVarWait(&nap->cv, &nap->mu);
1672 : }
1673 :
1674 9 : ++nap->threads_launching;
1675 9 : NaClXMutexUnlock(&nap->mu);
1676 : /*
1677 : * NB: Dropped lock, so many threads launching can starve VM
1678 : * operations. If this becomes a problem in practice, we can use a
1679 : * reader/writer lock so that a waiting writer will block new
1680 : * readers.
1681 : */
1682 9 : }
1683 :
1684 9 : void NaClVmHoleThreadStackIsSafe(struct NaClApp *nap) {
1685 9 : NaClXMutexLock(&nap->mu);
1686 :
1687 9 : if (0 == --nap->threads_launching) {
1688 : /*
1689 : * Wake up the threads waiting to do VM operations.
1690 : */
1691 6 : NaClXCondVarBroadcast(&nap->cv);
1692 : }
1693 :
1694 9 : NaClXMutexUnlock(&nap->mu);
1695 9 : }
1696 :
1697 : /*
1698 : * GDB's canonical overlay managment routine.
1699 : * We need its symbol in the symbol table so don't inline it.
1700 : * TODO(dje): add some explanation for the non-GDB person.
1701 : */
1702 : #if NACL_WINDOWS
1703 : __declspec(dllexport,noinline)
1704 : #endif
1705 : #ifdef __GNUC__
1706 : __attribute__((noinline))
1707 : #endif
1708 11 : void _ovly_debug_event (void) {
1709 : #ifdef __GNUC__
1710 : /*
1711 : * The asm volatile is here as instructed by the GCC docs.
1712 : * It's not enough to declare a function noinline.
1713 : * GCC will still look inside the function to see if it's worth calling.
1714 : */
1715 11 : __asm__ volatile ("");
1716 : #elif NACL_WINDOWS
1717 : /*
1718 : * Visual Studio inlines empty functions even with noinline attribute,
1719 : * so we need a compile memory barrier to make this function not to be
1720 : * inlined. Also, it guarantees that nacl_global_xlate_base initialization
1721 : * is not reordered. This is important for gdb since it sets breakpoint on
1722 : * this function and reads nacl_global_xlate_base value.
1723 : */
1724 : _ReadWriteBarrier();
1725 : #endif
1726 11 : }
1727 :
1728 11 : static void StopForDebuggerInit (uintptr_t mem_start) {
1729 : /* Put xlate_base in a place where gdb can find it. */
1730 11 : nacl_global_xlate_base = mem_start;
1731 :
1732 11 : NaClSandboxMemoryStartForValgrind(mem_start);
1733 :
1734 11 : _ovly_debug_event();
1735 11 : }
1736 :
1737 11 : void NaClGdbHook(struct NaClApp const *nap) {
1738 11 : StopForDebuggerInit(nap->mem_start);
1739 11 : }
|