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.h"
13 : #include "native_client/src/include/portability_io.h"
14 : #include "native_client/src/include/portability_string.h"
15 : #include "native_client/src/include/nacl_macros.h"
16 :
17 : #include "native_client/src/public/desc_metadata_types.h"
18 : #include "native_client/src/public/nacl_app.h"
19 : #include "native_client/src/public/secure_service.h"
20 :
21 : #include "native_client/src/shared/gio/gio.h"
22 : #include "native_client/src/shared/platform/nacl_check.h"
23 : #include "native_client/src/shared/platform/nacl_exit.h"
24 : #include "native_client/src/shared/platform/nacl_log.h"
25 : #include "native_client/src/shared/platform/nacl_sync.h"
26 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
27 : #include "native_client/src/shared/platform/nacl_time.h"
28 : #include "native_client/src/shared/srpc/nacl_srpc.h"
29 :
30 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
31 : #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
32 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
33 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
34 : #include "native_client/src/trusted/desc/nrd_xfer.h"
35 : #include "native_client/src/trusted/desc_cacheability/desc_cacheability.h"
36 : #include "native_client/src/trusted/fault_injection/fault_injection.h"
37 : #include "native_client/src/trusted/fault_injection/test_injection.h"
38 : #include "native_client/src/trusted/gio/gio_nacl_desc.h"
39 : #include "native_client/src/trusted/gio/gio_shm.h"
40 : #include "native_client/src/trusted/interval_multiset/nacl_interval_range_tree_intern.h"
41 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
42 : #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
43 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
44 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
45 : #include "native_client/src/trusted/service_runtime/include/sys/time.h"
46 : #include "native_client/src/trusted/service_runtime/nacl_app.h"
47 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
48 : #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
49 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
50 : #include "native_client/src/trusted/service_runtime/nacl_resource.h"
51 : #include "native_client/src/trusted/service_runtime/nacl_reverse_quota_interface.h"
52 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
53 : #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
54 : #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
55 : #include "native_client/src/trusted/service_runtime/name_service/default_name_service.h"
56 : #include "native_client/src/trusted/service_runtime/name_service/name_service.h"
57 : #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
58 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
59 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
60 : #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
61 : #include "native_client/src/trusted/simple_service/nacl_simple_rservice.h"
62 : #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
63 : #include "native_client/src/trusted/threading/nacl_thread_interface.h"
64 : #include "native_client/src/trusted/validator/validation_cache.h"
65 :
66 1240 : static int IsEnvironmentVariableSet(char const *env_name) {
67 1240 : return NULL != getenv(env_name);
68 : }
69 :
70 310 : static int ShouldEnableDyncodeSyscalls(void) {
71 310 : return !IsEnvironmentVariableSet("NACL_DISABLE_DYNCODE_SYSCALLS");
72 : }
73 :
74 310 : static int ShouldEnableDynamicLoading(void) {
75 310 : return !IsEnvironmentVariableSet("NACL_DISABLE_DYNAMIC_LOADING");
76 : }
77 :
78 310 : int NaClAppWithSyscallTableCtor(struct NaClApp *nap,
79 : struct NaClSyscallTableEntry *table) {
80 : struct NaClDescEffectorLdr *effp;
81 :
82 : /* Zero-initialize in case we miss any fields below. */
83 310 : memset(nap, 0, sizeof(*nap));
84 :
85 : /* The validation cache will be injected later, if it exists. */
86 310 : nap->validation_cache = NULL;
87 :
88 310 : nap->validator = NaClCreateValidator();
89 :
90 : /* Get the set of features that the CPU we're running on supports. */
91 : /* These may be adjusted later in sel_main.c for fixed-feature CPU mode. */
92 310 : nap->cpu_features = (NaClCPUFeatures *) malloc(
93 310 : nap->validator->CPUFeatureSize);
94 310 : if (NULL == nap->cpu_features) {
95 0 : goto cleanup_none;
96 : }
97 310 : nap->validator->GetCurrentCPUFeatures(nap->cpu_features);
98 310 : nap->fixed_feature_cpu_mode = 0;
99 :
100 310 : nap->addr_bits = NACL_MAX_ADDR_BITS;
101 :
102 310 : nap->stack_size = NACL_DEFAULT_STACK_MAX;
103 310 : nap->initial_nexe_max_code_bytes = 0;
104 :
105 310 : nap->mem_start = 0;
106 :
107 : #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
108 : && NACL_BUILD_SUBARCH == 32)
109 310 : nap->pcrel_thunk = 0;
110 310 : nap->pcrel_thunk_end = 0;
111 : #endif
112 : #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
113 : && NACL_BUILD_SUBARCH == 64)
114 : nap->nacl_syscall_addr = 0;
115 : nap->get_tls_fast_path1_addr = 0;
116 : nap->get_tls_fast_path2_addr = 0;
117 : #endif
118 :
119 310 : nap->static_text_end = 0;
120 310 : nap->dynamic_text_start = 0;
121 310 : nap->dynamic_text_end = 0;
122 310 : nap->rodata_start = 0;
123 310 : nap->data_start = 0;
124 310 : nap->data_end = 0;
125 :
126 310 : nap->initial_entry_pt = 0;
127 310 : nap->user_entry_pt = 0;
128 :
129 310 : if (!DynArrayCtor(&nap->threads, 2)) {
130 0 : goto cleanup_cpu_features;
131 : }
132 310 : if (!DynArrayCtor(&nap->desc_tbl, 2)) {
133 0 : goto cleanup_threads;
134 : }
135 310 : if (!NaClVmmapCtor(&nap->mem_map)) {
136 0 : goto cleanup_desc_tbl;
137 : }
138 :
139 310 : nap->mem_io_regions = (struct NaClIntervalMultiset *) malloc(
140 : sizeof(struct NaClIntervalRangeTree));
141 310 : if (NULL == nap->mem_io_regions) {
142 0 : goto cleanup_mem_map;
143 : }
144 :
145 310 : if (!NaClIntervalRangeTreeCtor((struct NaClIntervalRangeTree *)
146 310 : nap->mem_io_regions)) {
147 0 : free(nap->mem_io_regions);
148 0 : nap->mem_io_regions = NULL;
149 0 : goto cleanup_mem_map;
150 : }
151 :
152 310 : effp = (struct NaClDescEffectorLdr *) malloc(sizeof *effp);
153 310 : if (NULL == effp) {
154 0 : goto cleanup_mem_io_regions;
155 : }
156 310 : if (!NaClDescEffectorLdrCtor(effp, nap)) {
157 0 : goto cleanup_effp_free;
158 : }
159 310 : nap->effp = (struct NaClDescEffector *) effp;
160 :
161 310 : nap->enable_dyncode_syscalls = ShouldEnableDyncodeSyscalls();
162 310 : nap->use_shm_for_dynamic_text = ShouldEnableDynamicLoading();
163 310 : nap->text_shm = NULL;
164 310 : if (!NaClMutexCtor(&nap->dynamic_load_mutex)) {
165 0 : goto cleanup_effp_free;
166 : }
167 310 : nap->dynamic_page_bitmap = NULL;
168 :
169 310 : nap->dynamic_regions = NULL;
170 310 : nap->num_dynamic_regions = 0;
171 310 : nap->dynamic_regions_allocated = 0;
172 310 : nap->dynamic_delete_generation = 0;
173 :
174 310 : nap->dynamic_mapcache_offset = 0;
175 310 : nap->dynamic_mapcache_size = 0;
176 310 : nap->dynamic_mapcache_ret = 0;
177 :
178 310 : nap->service_port = NULL;
179 310 : nap->service_address = NULL;
180 310 : nap->secure_service_port = NULL;
181 310 : nap->secure_service_address = NULL;
182 310 : nap->bootstrap_channel = NULL;
183 310 : nap->secure_service = NULL;
184 310 : nap->main_exe_prevalidated = 0;
185 :
186 310 : nap->kernel_service = NULL;
187 310 : nap->resource_phase = NACL_RESOURCE_PHASE_START;
188 310 : if (!NaClResourceNaClAppInit(&nap->resources, nap)) {
189 0 : goto cleanup_dynamic_load_mutex;
190 : }
191 :
192 310 : if (!NaClMutexCtor(&nap->mu)) {
193 0 : goto cleanup_dynamic_load_mutex;
194 : }
195 310 : if (!NaClCondVarCtor(&nap->cv)) {
196 0 : goto cleanup_mu;
197 : }
198 :
199 : #if NACL_WINDOWS
200 : nap->vm_hole_may_exist = 0;
201 : nap->threads_launching = 0;
202 : #endif
203 :
204 310 : nap->syscall_table = table;
205 :
206 310 : nap->runtime_host_interface = NULL;
207 310 : nap->desc_quota_interface = NULL;
208 :
209 310 : nap->module_initialization_state = NACL_MODULE_UNINITIALIZED;
210 310 : nap->module_load_status = LOAD_STATUS_UNKNOWN;
211 :
212 310 : nap->name_service = (struct NaClNameService *) malloc(
213 : sizeof *nap->name_service);
214 310 : if (NULL == nap->name_service) {
215 0 : goto cleanup_cv;
216 : }
217 310 : if (!NaClNameServiceCtor(nap->name_service,
218 : NaClAddrSpSquattingThreadIfFactoryFunction,
219 : (void *) nap)) {
220 0 : free(nap->name_service);
221 0 : goto cleanup_cv;
222 : }
223 310 : nap->name_service_conn_cap = NaClDescRef(nap->name_service->
224 : base.base.bound_and_cap[1]);
225 310 : if (!NaClDefaultNameServiceInit(nap->name_service)) {
226 0 : goto cleanup_name_service;
227 : }
228 :
229 310 : nap->ignore_validator_result = 0;
230 310 : nap->skip_validator = 0;
231 310 : nap->validator_stub_out_mode = 0;
232 :
233 310 : if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_FILE_ACCESS")) {
234 0 : NaClInsecurelyBypassAllAclChecks();
235 0 : NaClLog(LOG_INFO, "DANGER: ENABLED FILE ACCESS\n");
236 : }
237 :
238 310 : nap->enable_list_mappings = 0;
239 310 : if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_LIST_MAPPINGS")) {
240 : /*
241 : * This syscall is not actually know to be dangerous, but is not yet
242 : * exposed by our public API.
243 : */
244 1 : NaClLog(LOG_INFO, "DANGER: ENABLED LIST_MAPPINGS\n");
245 1 : nap->enable_list_mappings = 1;
246 : }
247 310 : nap->pnacl_mode = 0;
248 :
249 310 : if (!NaClMutexCtor(&nap->threads_mu)) {
250 0 : goto cleanup_name_service;
251 : }
252 310 : nap->num_threads = 0;
253 310 : if (!NaClFastMutexCtor(&nap->desc_mu)) {
254 0 : goto cleanup_threads_mu;
255 : }
256 :
257 310 : nap->running = 0;
258 310 : nap->exit_status = -1;
259 :
260 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
261 310 : nap->code_seg_sel = 0;
262 310 : nap->data_seg_sel = 0;
263 : #endif
264 :
265 310 : nap->debug_stub_callbacks = NULL;
266 : #if NACL_WINDOWS
267 : nap->debug_stub_port = 0;
268 : #endif
269 310 : nap->main_nexe_desc = NULL;
270 310 : nap->irt_nexe_desc = NULL;
271 :
272 310 : nap->exception_handler = 0;
273 310 : if (!NaClMutexCtor(&nap->exception_mu)) {
274 0 : goto cleanup_desc_mu;
275 : }
276 310 : nap->enable_exception_handling = 0;
277 : #if NACL_WINDOWS
278 : nap->debug_exception_handler_state = NACL_DEBUG_EXCEPTION_HANDLER_NOT_STARTED;
279 : nap->attach_debug_exception_handler_func = NULL;
280 : #endif
281 310 : nap->enable_faulted_thread_queue = 0;
282 310 : nap->faulted_thread_count = 0;
283 : #if NACL_WINDOWS
284 : nap->faulted_thread_event = INVALID_HANDLE_VALUE;
285 : #else
286 310 : nap->faulted_thread_fd_read = -1;
287 310 : nap->faulted_thread_fd_write = -1;
288 : #endif
289 :
290 :
291 : #if NACL_LINUX || NACL_OSX
292 : /*
293 : * Try to pre-cache information that we can't obtain with the outer
294 : * sandbox on. If the outer sandbox has already been enabled, this
295 : * will just set sc_nprocessors_onln to -1, and it is the
296 : * responsibility of the caller to replace this with a sane value
297 : * after the Ctor returns.
298 : */
299 310 : nap->sc_nprocessors_onln = sysconf(_SC_NPROCESSORS_ONLN);
300 : #endif
301 :
302 310 : if (!NaClMutexCtor(&nap->futex_wait_list_mu)) {
303 0 : goto cleanup_exception_mu;
304 : }
305 310 : nap->futex_wait_list_head.next = &nap->futex_wait_list_head;
306 310 : nap->futex_wait_list_head.prev = &nap->futex_wait_list_head;
307 :
308 310 : return 1;
309 :
310 : cleanup_exception_mu:
311 0 : NaClMutexDtor(&nap->exception_mu);
312 : cleanup_desc_mu:
313 0 : NaClFastMutexDtor(&nap->desc_mu);
314 : cleanup_threads_mu:
315 0 : NaClMutexDtor(&nap->threads_mu);
316 : cleanup_name_service:
317 0 : NaClDescUnref(nap->name_service_conn_cap);
318 0 : NaClRefCountUnref((struct NaClRefCount *) nap->name_service);
319 : cleanup_cv:
320 0 : NaClCondVarDtor(&nap->cv);
321 : cleanup_mu:
322 0 : NaClMutexDtor(&nap->mu);
323 : cleanup_dynamic_load_mutex:
324 0 : NaClMutexDtor(&nap->dynamic_load_mutex);
325 : cleanup_effp_free:
326 0 : free(nap->effp);
327 : cleanup_mem_io_regions:
328 0 : NaClIntervalMultisetDelete(nap->mem_io_regions);
329 0 : nap->mem_io_regions = NULL;
330 : cleanup_mem_map:
331 0 : NaClVmmapDtor(&nap->mem_map);
332 : cleanup_desc_tbl:
333 0 : DynArrayDtor(&nap->desc_tbl);
334 : cleanup_threads:
335 0 : DynArrayDtor(&nap->threads);
336 : cleanup_cpu_features:
337 0 : free(nap->cpu_features);
338 : cleanup_none:
339 0 : return 0;
340 : }
341 :
342 309 : int NaClAppCtor(struct NaClApp *nap) {
343 309 : return NaClAppWithSyscallTableCtor(nap, nacl_syscall);
344 : }
345 :
346 283 : struct NaClApp *NaClAppCreate(void) {
347 283 : struct NaClApp *nap = malloc(sizeof(struct NaClApp));
348 283 : if (nap == NULL)
349 0 : NaClLog(LOG_FATAL, "Failed to allocate NaClApp\n");
350 283 : if (!NaClAppCtor(nap))
351 0 : NaClLog(LOG_FATAL, "NaClAppCtor() failed\n");
352 283 : return nap;
353 : }
354 :
355 : /*
356 : * unaligned little-endian load. precondition: nbytes should never be
357 : * more than 8.
358 : */
359 0 : static uint64_t NaClLoadMem(uintptr_t addr,
360 : size_t user_nbytes) {
361 0 : uint64_t value = 0;
362 :
363 0 : CHECK(0 != user_nbytes && user_nbytes <= 8);
364 :
365 : do {
366 0 : value = value << 8;
367 0 : value |= ((uint8_t *) addr)[--user_nbytes];
368 0 : } while (user_nbytes > 0);
369 0 : return value;
370 : }
371 :
372 : #define GENERIC_LOAD(bits) \
373 : static uint ## bits ## _t NaClLoad ## bits(uintptr_t addr) { \
374 : return (uint ## bits ## _t) NaClLoadMem(addr, sizeof(uint ## bits ## _t)); \
375 : }
376 :
377 : #if NACL_TARGET_SUBARCH == 32
378 0 : GENERIC_LOAD(32)
379 : #endif
380 0 : GENERIC_LOAD(64)
381 :
382 : #undef GENERIC_LOAD
383 :
384 : /*
385 : * unaligned little-endian store
386 : */
387 1138966 : static void NaClStoreMem(uintptr_t addr,
388 : size_t nbytes,
389 : uint64_t value) {
390 : size_t i;
391 :
392 1138966 : CHECK(nbytes <= 8);
393 :
394 4556698 : for (i = 0; i < nbytes; ++i) {
395 3417732 : ((uint8_t *) addr)[i] = (uint8_t) value;
396 3417732 : value = value >> 8;
397 : }
398 1138966 : }
399 :
400 : #define GENERIC_STORE(bits) \
401 : static void NaClStore ## bits(uintptr_t addr, \
402 : uint ## bits ## _t v) { \
403 : NaClStoreMem(addr, sizeof(uint ## bits ## _t), v); \
404 : }
405 :
406 569066 : GENERIC_STORE(16)
407 569900 : GENERIC_STORE(32)
408 0 : GENERIC_STORE(64)
409 :
410 : #undef GENERIC_STORE
411 :
412 569900 : struct NaClPatchInfo *NaClPatchInfoCtor(struct NaClPatchInfo *self) {
413 569900 : if (NULL != self) {
414 569900 : memset(self, 0, sizeof *self);
415 : }
416 569900 : return self;
417 : }
418 :
419 : /*
420 : * This function is called by NaClLoadTrampoline and NaClLoadSpringboard to
421 : * patch a single memory location specified in NaClPatchInfo structure.
422 : */
423 569900 : void NaClApplyPatchToMemory(struct NaClPatchInfo *patch) {
424 : size_t i;
425 : size_t offset;
426 : int64_t reloc;
427 : uintptr_t target_addr;
428 :
429 569900 : memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
430 :
431 569900 : reloc = patch->dst - patch->src;
432 :
433 :
434 569900 : for (i = 0; i < patch->num_abs64; ++i) {
435 0 : offset = patch->abs64[i].target - patch->src;
436 0 : target_addr = patch->dst + offset;
437 0 : NaClStore64(target_addr, patch->abs64[i].value);
438 : }
439 :
440 1139800 : for (i = 0; i < patch->num_abs32; ++i) {
441 569900 : offset = patch->abs32[i].target - patch->src;
442 569900 : target_addr = patch->dst + offset;
443 569900 : NaClStore32(target_addr, (uint32_t) patch->abs32[i].value);
444 : }
445 :
446 1138966 : for (i = 0; i < patch->num_abs16; ++i) {
447 569066 : offset = patch->abs16[i].target - patch->src;
448 569066 : target_addr = patch->dst + offset;
449 569066 : NaClStore16(target_addr, (uint16_t) patch->abs16[i].value);
450 : }
451 :
452 569900 : for (i = 0; i < patch->num_rel64; ++i) {
453 0 : offset = patch->rel64[i] - patch->src;
454 0 : target_addr = patch->dst + offset;
455 0 : NaClStore64(target_addr, NaClLoad64(target_addr) - reloc);
456 : }
457 :
458 : /*
459 : * rel32 is only supported on 32-bit architectures. The range of a relative
460 : * relocation in untrusted space is +/- 4GB. This can be represented as
461 : * an unsigned 32-bit value mod 2^32, which is handy on a 32 bit system since
462 : * all 32-bit pointer arithmetic is implicitly mod 2^32. On a 64 bit system,
463 : * however, pointer arithmetic is implicitly modulo 2^64, which isn't as
464 : * helpful for our purposes. We could simulate the 32-bit behavior by
465 : * explicitly modding all relative addresses by 2^32, but that seems like an
466 : * expensive way to save a few bytes per reloc.
467 : */
468 : #if NACL_TARGET_SUBARCH == 32
469 569900 : for (i = 0; i < patch->num_rel32; ++i) {
470 0 : offset = patch->rel32[i] - patch->src;
471 0 : target_addr = patch->dst + offset;
472 0 : NaClStore32(target_addr,
473 0 : (uint32_t) NaClLoad32(target_addr) - (int32_t) reloc);
474 : }
475 : #endif
476 569900 : }
477 :
478 :
479 : /*
480 : * Install syscall trampolines at all possible well-formed entry
481 : * points within the trampoline pages. Many of these syscalls will
482 : * correspond to unimplemented system calls and will just abort the
483 : * program.
484 : */
485 278 : void NaClLoadTrampoline(struct NaClApp *nap, enum NaClAslrMode aslr_mode) {
486 : int num_syscalls;
487 : int i;
488 : uintptr_t addr;
489 :
490 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
491 278 : if (!NaClMakePcrelThunk(nap, aslr_mode)) {
492 0 : NaClLog(LOG_FATAL, "NaClMakePcrelThunk failed!\n");
493 : }
494 : #else
495 : UNREFERENCED_PARAMETER(aslr_mode);
496 : #endif
497 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
498 : if (!NaClMakeDispatchAddrs(nap)) {
499 : NaClLog(LOG_FATAL, "NaClMakeDispatchAddrs failed!\n");
500 : }
501 : #endif
502 278 : NaClFillTrampolineRegion(nap);
503 :
504 : /*
505 : * Do not bother to fill in the contents of page 0, since we make it
506 : * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
507 : * anyway to help detect NULL pointer errors, and we might as well
508 : * not dirty the page.
509 : *
510 : * The last syscall entry point is used for springboard code.
511 : */
512 278 : num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR)
513 : / NACL_SYSCALL_BLOCK_SIZE) - 1;
514 :
515 278 : NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
516 :
517 569622 : for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
518 : i < num_syscalls;
519 569066 : ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
520 569066 : NaClPatchOneTrampoline(nap, addr);
521 : }
522 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
523 : NaClPatchOneTrampolineCall(nap->get_tls_fast_path1_addr,
524 : nap->mem_start + NACL_SYSCALL_START_ADDR
525 : + NACL_SYSCALL_BLOCK_SIZE * NACL_sys_tls_get);
526 : NaClPatchOneTrampolineCall(nap->get_tls_fast_path2_addr,
527 : nap->mem_start + NACL_SYSCALL_START_ADDR
528 : + (NACL_SYSCALL_BLOCK_SIZE *
529 : NACL_sys_second_tls_get));
530 : #endif
531 :
532 278 : NACL_TEST_INJECTION(ChangeTrampolines, (nap));
533 278 : }
534 :
535 131 : void NaClMemRegionPrinter(void *state,
536 : struct NaClVmmapEntry *entry) {
537 131 : struct Gio *gp = (struct Gio *) state;
538 :
539 131 : gprintf(gp, "\nPage %"NACL_PRIdPTR" (0x%"NACL_PRIxPTR")\n",
540 : entry->page_num, entry->page_num);
541 131 : gprintf(gp, "npages %"NACL_PRIdS" (0x%"NACL_PRIxS")\n", entry->npages,
542 : entry->npages);
543 131 : gprintf(gp, "start vaddr 0x%"NACL_PRIxPTR"\n",
544 131 : entry->page_num << NACL_PAGESHIFT);
545 131 : gprintf(gp, "end vaddr 0x%"NACL_PRIxPTR"\n",
546 131 : (entry->page_num + entry->npages) << NACL_PAGESHIFT);
547 131 : gprintf(gp, "prot 0x%08x\n", entry->prot);
548 131 : gprintf(gp, "%sshared/backed by a file\n",
549 131 : (NULL == entry->desc) ? "not " : "");
550 131 : }
551 :
552 22 : void NaClAppPrintDetails(struct NaClApp *nap,
553 : struct Gio *gp) {
554 22 : NaClXMutexLock(&nap->mu);
555 22 : gprintf(gp,
556 : "NaClAppPrintDetails((struct NaClApp *) 0x%08"NACL_PRIxPTR","
557 : "(struct Gio *) 0x%08"NACL_PRIxPTR")\n", (uintptr_t) nap,
558 : (uintptr_t) gp);
559 22 : gprintf(gp, "addr space size: 2**%"NACL_PRId32"\n", nap->addr_bits);
560 22 : gprintf(gp, "stack size: 0x%08"NACL_PRIx32"\n", nap->stack_size);
561 :
562 22 : gprintf(gp, "mem start addr: 0x%08"NACL_PRIxPTR"\n", nap->mem_start);
563 : /* 123456789012345678901234567890 */
564 :
565 22 : gprintf(gp, "static_text_end: 0x%08"NACL_PRIxPTR"\n", nap->static_text_end);
566 22 : gprintf(gp, "end-of-text: 0x%08"NACL_PRIxPTR"\n",
567 : NaClEndOfStaticText(nap));
568 22 : gprintf(gp, "rodata: 0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
569 22 : gprintf(gp, "data: 0x%08"NACL_PRIxPTR"\n", nap->data_start);
570 22 : gprintf(gp, "data_end: 0x%08"NACL_PRIxPTR"\n", nap->data_end);
571 22 : gprintf(gp, "break_addr: 0x%08"NACL_PRIxPTR"\n", nap->break_addr);
572 :
573 22 : gprintf(gp, "ELF initial entry point: 0x%08x\n", nap->initial_entry_pt);
574 22 : gprintf(gp, "ELF user entry point: 0x%08x\n", nap->user_entry_pt);
575 22 : gprintf(gp, "memory map:\n");
576 22 : NaClVmmapVisit(&nap->mem_map,
577 : NaClMemRegionPrinter,
578 : gp);
579 22 : NaClXMutexUnlock(&nap->mu);
580 22 : }
581 :
582 71564 : struct NaClDesc *NaClAppGetDescMu(struct NaClApp *nap,
583 : int d) {
584 : struct NaClDesc *result;
585 :
586 71564 : result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
587 71564 : if (NULL != result) {
588 71540 : NaClDescRef(result);
589 : }
590 :
591 71564 : return result;
592 : }
593 :
594 1840 : void NaClAppSetDescMu(struct NaClApp *nap,
595 : int d,
596 : struct NaClDesc *ndp) {
597 : struct NaClDesc *result;
598 :
599 1840 : result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
600 1840 : NaClDescSafeUnref(result);
601 :
602 1840 : if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
603 0 : NaClLog(LOG_FATAL,
604 : "NaClAppSetDesc: could not set descriptor %d to 0x%08"
605 : NACL_PRIxPTR"\n",
606 : d,
607 : (uintptr_t) ndp);
608 : }
609 1840 : }
610 :
611 278 : int32_t NaClAppSetDescAvailMu(struct NaClApp *nap,
612 : struct NaClDesc *ndp) {
613 : size_t pos;
614 :
615 278 : pos = DynArrayFirstAvail(&nap->desc_tbl);
616 :
617 278 : if (pos > INT32_MAX) {
618 0 : NaClLog(LOG_FATAL,
619 : ("NaClAppSetDescAvailMu: DynArrayFirstAvail returned a value"
620 : " that is greather than 2**31-1.\n"));
621 : }
622 :
623 278 : NaClAppSetDescMu(nap, (int) pos, ndp);
624 :
625 278 : return (int32_t) pos;
626 : }
627 :
628 70894 : struct NaClDesc *NaClAppGetDesc(struct NaClApp *nap,
629 : int d) {
630 : struct NaClDesc *res;
631 :
632 70894 : NaClFastMutexLock(&nap->desc_mu);
633 70894 : res = NaClAppGetDescMu(nap, d);
634 70894 : NaClFastMutexUnlock(&nap->desc_mu);
635 70894 : return res;
636 : }
637 :
638 899 : void NaClAppSetDesc(struct NaClApp *nap,
639 : int d,
640 : struct NaClDesc *ndp) {
641 899 : NaClFastMutexLock(&nap->desc_mu);
642 899 : NaClAppSetDescMu(nap, d, ndp);
643 899 : NaClFastMutexUnlock(&nap->desc_mu);
644 899 : }
645 :
646 278 : int32_t NaClAppSetDescAvail(struct NaClApp *nap,
647 : struct NaClDesc *ndp) {
648 : int32_t pos;
649 :
650 278 : NaClFastMutexLock(&nap->desc_mu);
651 278 : pos = NaClAppSetDescAvailMu(nap, ndp);
652 278 : NaClFastMutexUnlock(&nap->desc_mu);
653 :
654 278 : return pos;
655 : }
656 :
657 29422 : int NaClAddThreadMu(struct NaClApp *nap,
658 : struct NaClAppThread *natp) {
659 : size_t pos;
660 :
661 29422 : pos = DynArrayFirstAvail(&nap->threads);
662 :
663 29422 : if (!DynArraySet(&nap->threads, pos, natp)) {
664 0 : NaClLog(LOG_FATAL,
665 : "NaClAddThreadMu: DynArraySet at position %"NACL_PRIuS" failed\n",
666 : pos);
667 : }
668 29422 : ++nap->num_threads;
669 29422 : return (int) pos;
670 : }
671 :
672 5 : int NaClAddThread(struct NaClApp *nap,
673 : struct NaClAppThread *natp) {
674 : int pos;
675 :
676 5 : NaClXMutexLock(&nap->threads_mu);
677 5 : pos = NaClAddThreadMu(nap, natp);
678 5 : NaClXMutexUnlock(&nap->threads_mu);
679 :
680 5 : return pos;
681 : }
682 :
683 29367 : void NaClRemoveThreadMu(struct NaClApp *nap,
684 : int thread_num) {
685 29367 : if (NULL == DynArrayGet(&nap->threads, thread_num)) {
686 1 : NaClLog(LOG_FATAL,
687 : "NaClRemoveThreadMu:: thread to be removed is not in the table\n");
688 : }
689 29366 : if (nap->num_threads == 0) {
690 0 : NaClLog(LOG_FATAL,
691 : "NaClRemoveThreadMu:: num_threads cannot be 0!!!\n");
692 : }
693 29366 : --nap->num_threads;
694 29366 : if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
695 0 : NaClLog(LOG_FATAL,
696 : "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
697 : thread_num);
698 : }
699 29366 : }
700 :
701 3 : void NaClRemoveThread(struct NaClApp *nap,
702 : int thread_num) {
703 3 : NaClXMutexLock(&nap->threads_mu);
704 3 : NaClRemoveThreadMu(nap, thread_num);
705 2 : NaClXMutexUnlock(&nap->threads_mu);
706 2 : }
707 :
708 35401 : struct NaClAppThread *NaClGetThreadMu(struct NaClApp *nap,
709 : int thread_num) {
710 35401 : return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
711 : }
712 :
713 865 : void NaClAddHostDescriptor(struct NaClApp *nap,
714 : int host_os_desc,
715 : int flag,
716 : int nacl_desc) {
717 : struct NaClDescIoDesc *dp;
718 :
719 865 : NaClLog(4,
720 : "NaClAddHostDescriptor: host %d as nacl desc %d, flag 0x%x\n",
721 : host_os_desc,
722 : nacl_desc,
723 : flag);
724 865 : dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, flag));
725 865 : if (NULL == dp) {
726 0 : NaClLog(LOG_FATAL, "NaClAddHostDescriptor: NaClDescIoDescMake failed\n");
727 : }
728 865 : NaClAppSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
729 865 : }
730 :
731 2 : void NaClAddImcHandle(struct NaClApp *nap,
732 : NaClHandle h,
733 : int nacl_desc) {
734 : struct NaClDescImcDesc *dp;
735 :
736 2 : NaClLog(4,
737 : ("NaClAddImcHandle: importing NaClHandle %"NACL_PRIxPTR
738 : " as nacl desc %d\n"),
739 : (uintptr_t) h,
740 : nacl_desc);
741 2 : dp = (struct NaClDescImcDesc *) malloc(sizeof *dp);
742 2 : if (NACL_FI_ERROR_COND("NaClAddImcHandle__malloc", NULL == dp)) {
743 0 : NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
744 : }
745 2 : if (NACL_FI_ERROR_COND("NaClAddImcHandle__ctor",
746 : !NaClDescImcDescCtor(dp, h))) {
747 0 : NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
748 : " IMC descriptor object\n"));
749 : }
750 2 : NaClAppSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
751 2 : }
752 :
753 :
754 : static struct {
755 : int d;
756 : char const *env_name;
757 : int nacl_flags;
758 : int mode;
759 : } const g_nacl_redir_control[] = {
760 : { 0, "NACL_EXE_STDIN",
761 : NACL_ABI_O_RDONLY, 0, },
762 : { 1, "NACL_EXE_STDOUT",
763 : NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
764 : { 2, "NACL_EXE_STDERR",
765 : NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
766 : };
767 :
768 : /*
769 : * File redirection is impossible if an outer sandbox is in place.
770 : * For the command-line embedding, we sometimes have an outer sandbox:
771 : * on OSX, it is enabled after loading the file is loaded. On the
772 : * other hand, device redirection (DEBUG_ONLY:dev://postmessage) is
773 : * impossible until the reverse channel setup has occurred.
774 : *
775 : * Because of this, we run NaClProcessRedirControl twice: once to
776 : * process default inheritance, file redirection early on, and once
777 : * after the reverse channel is in place to handle the device
778 : * redirection. We try to hide knowledge about which redirection
779 : * control values can be handled in which phases by allowing the
780 : * NaClResourceOpen to fail, and only in the last phase do we check
781 : * that the redirection succeeded in *some* phase.
782 : */
783 292 : static void NaClProcessRedirControl(struct NaClApp *nap) {
784 :
785 : size_t ix;
786 : char const *env;
787 : struct NaClDesc *ndp;
788 :
789 1168 : for (ix = 0; ix < NACL_ARRAY_SIZE(g_nacl_redir_control); ++ix) {
790 876 : ndp = NULL;
791 876 : if (NULL != (env = getenv(g_nacl_redir_control[ix].env_name))) {
792 2 : NaClLog(4, "getenv(%s) -> %s\n", g_nacl_redir_control[ix].env_name, env);
793 2 : ndp = NaClResourceOpen((struct NaClResource *) &nap->resources,
794 : env,
795 : g_nacl_redir_control[ix].nacl_flags,
796 : g_nacl_redir_control[ix].mode);
797 2 : NaClLog(4, " NaClResourceOpen returned %"NACL_PRIxPTR"\n",
798 : (uintptr_t) ndp);
799 : }
800 :
801 876 : if (NULL != ndp) {
802 2 : NaClLog(4, "Setting descriptor %d\n", (int) ix);
803 2 : NaClAppSetDesc(nap, (int) ix, ndp);
804 874 : } else if (NACL_RESOURCE_PHASE_START == nap->resource_phase) {
805 : /*
806 : * Environment not set or redirect failed -- handle default inheritance.
807 : */
808 865 : NaClAddHostDescriptor(nap, DUP(g_nacl_redir_control[ix].d),
809 : g_nacl_redir_control[ix].nacl_flags, (int) ix);
810 : }
811 : }
812 292 : }
813 :
814 : /*
815 : * Process default descriptor inheritance. This means dup'ing
816 : * descriptors 0-2 and making them available to the NaCl App.
817 : *
818 : * When standard input is inherited, this could result in a NaCl
819 : * module competing for input from the terminal; for graphical /
820 : * browser plugin environments, this never is allowed to happen, and
821 : * having this is useful for debugging, and for potential standalone
822 : * text-mode applications of NaCl.
823 : *
824 : * TODO(bsy): consider whether default inheritance should occur only
825 : * in debug mode.
826 : */
827 289 : void NaClAppInitialDescriptorHookup(struct NaClApp *nap) {
828 :
829 289 : NaClLog(4, "Processing I/O redirection/inheritance from environment\n");
830 289 : nap->resource_phase = NACL_RESOURCE_PHASE_START;
831 289 : NaClProcessRedirControl(nap);
832 289 : NaClLog(4, "... done.\n");
833 289 : }
834 :
835 10 : void NaClCreateServiceSocket(struct NaClApp *nap) {
836 : struct NaClDesc *secure_pair[2];
837 : struct NaClDesc *pair[2];
838 :
839 10 : NaClLog(3, "Entered NaClCreateServiceSocket\n");
840 :
841 10 : if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__secure_boundsock",
842 : 0 != NaClCommonDescMakeBoundSock(secure_pair))) {
843 0 : NaClLog(LOG_FATAL, "Cound not create secure service socket\n");
844 : }
845 20 : NaClLog(4,
846 : "got bound socket at 0x%08"NACL_PRIxPTR", "
847 : "addr at 0x%08"NACL_PRIxPTR"\n",
848 10 : (uintptr_t) secure_pair[0],
849 10 : (uintptr_t) secure_pair[1]);
850 :
851 10 : NaClDescSafeUnref(nap->secure_service_port);
852 10 : nap->secure_service_port = secure_pair[0];
853 :
854 10 : NaClDescSafeUnref(nap->secure_service_address);
855 10 : nap->secure_service_address = secure_pair[1];
856 :
857 10 : if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__boundsock",
858 : 0 != NaClCommonDescMakeBoundSock(pair))) {
859 0 : NaClLog(LOG_FATAL, "Cound not create service socket\n");
860 : }
861 20 : NaClLog(4,
862 : "got bound socket at 0x%08"NACL_PRIxPTR", "
863 : "addr at 0x%08"NACL_PRIxPTR"\n",
864 10 : (uintptr_t) pair[0],
865 10 : (uintptr_t) pair[1]);
866 10 : NaClAppSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
867 10 : NaClAppSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
868 :
869 10 : NaClDescSafeUnref(nap->service_port);
870 :
871 10 : nap->service_port = pair[0];
872 10 : NaClDescRef(nap->service_port);
873 :
874 10 : NaClDescSafeUnref(nap->service_address);
875 :
876 10 : nap->service_address = pair[1];
877 10 : NaClDescRef(nap->service_address);
878 :
879 10 : NaClLog(4, "Leaving NaClCreateServiceSocket\n");
880 10 : }
881 :
882 : /*
883 : * Import the |inherited_desc| descriptor as an IMC handle, save a
884 : * reference to it at nap->bootstrap_channel, then send the
885 : * service_address over that channel.
886 : */
887 9 : void NaClSetUpBootstrapChannel(struct NaClApp *nap,
888 : NaClHandle inherited_desc) {
889 : struct NaClDescImcDesc *channel;
890 : struct NaClImcTypedMsgHdr hdr;
891 : struct NaClDesc *descs[2];
892 : ssize_t rv;
893 :
894 9 : NaClLog(4,
895 : "NaClSetUpBootstrapChannel(0x%08"NACL_PRIxPTR", %"NACL_PRIdPTR")\n",
896 : (uintptr_t) nap,
897 : (uintptr_t) inherited_desc);
898 :
899 9 : channel = (struct NaClDescImcDesc *) malloc(sizeof *channel);
900 9 : if (NULL == channel) {
901 0 : NaClLog(LOG_FATAL, "NaClSetUpBootstrapChannel: no memory\n");
902 : }
903 9 : if (!NaClDescImcDescCtor(channel, inherited_desc)) {
904 0 : NaClLog(LOG_FATAL,
905 : ("NaClSetUpBootstrapChannel: cannot construct IMC descriptor"
906 : " object for inherited descriptor %"NACL_PRIdPTR"\n"),
907 : (uintptr_t) inherited_desc);
908 0 : return;
909 : }
910 9 : if (NULL == nap->secure_service_address) {
911 0 : NaClLog(LOG_FATAL,
912 : "NaClSetUpBootstrapChannel: secure service address not set\n");
913 0 : return;
914 : }
915 9 : if (NULL == nap->service_address) {
916 0 : NaClLog(LOG_FATAL,
917 : "NaClSetUpBootstrapChannel: service address not set\n");
918 0 : return;
919 : }
920 : /*
921 : * service_address and service_port are set together.
922 : */
923 9 : descs[0] = nap->secure_service_address;
924 9 : descs[1] = nap->service_address;
925 :
926 9 : hdr.iov = (struct NaClImcMsgIoVec *) NULL;
927 9 : hdr.iov_length = 0;
928 9 : hdr.ndescv = descs;
929 9 : hdr.ndesc_length = NACL_ARRAY_SIZE(descs);
930 :
931 9 : rv = (*NACL_VTBL(NaClDesc, channel)->SendMsg)((struct NaClDesc *) channel,
932 : &hdr, 0);
933 9 : NaClXMutexLock(&nap->mu);
934 9 : if (NULL != nap->bootstrap_channel) {
935 0 : NaClLog(LOG_FATAL,
936 : "NaClSetUpBootstrapChannel: cannot have two bootstrap channels\n");
937 : }
938 9 : nap->bootstrap_channel = (struct NaClDesc *) channel;
939 9 : channel = NULL;
940 9 : NaClXMutexUnlock(&nap->mu);
941 :
942 9 : NaClLog(1,
943 : ("NaClSetUpBootstrapChannel: descriptor %"NACL_PRIdPTR
944 : ", error %"NACL_PRIdS"\n"),
945 : (uintptr_t) inherited_desc,
946 : rv);
947 9 : if (NACL_FI_ERROR_COND("NaClSetUpBootstrapChannel__SendMsg", 0 != rv)) {
948 0 : NaClLog(LOG_FATAL,
949 : "NaClSetUpBootstrapChannel: SendMsg failed, rv = %"NACL_PRIdS"\n",
950 : rv);
951 : }
952 : }
953 :
954 5 : NaClErrorCode NaClWaitForLoadModuleCommand(struct NaClApp *nap) {
955 : NaClErrorCode status;
956 :
957 5 : NaClLog(4, "NaClWaitForLoadModuleCommand started\n");
958 5 : NaClXMutexLock(&nap->mu);
959 15 : while (nap->module_initialization_state < NACL_MODULE_LOADED) {
960 5 : NaClXCondVarWait(&nap->cv, &nap->mu);
961 : }
962 5 : status = nap->module_load_status;
963 5 : NaClXMutexUnlock(&nap->mu);
964 5 : NaClLog(4, "NaClWaitForLoadModuleCommand finished\n");
965 :
966 5 : return status;
967 : }
968 :
969 277 : NaClErrorCode NaClWaitForLoadModuleStatus(struct NaClApp *nap) {
970 : NaClErrorCode status;
971 :
972 277 : NaClLog(4, "NaClWaitForLoadModuleStatus started\n");
973 277 : NaClXMutexLock(&nap->mu);
974 554 : while (LOAD_STATUS_UNKNOWN == (status = nap->module_load_status)) {
975 0 : NaClXCondVarWait(&nap->cv, &nap->mu);
976 : }
977 277 : NaClXMutexUnlock(&nap->mu);
978 277 : NaClLog(4, "NaClWaitForLoadModuleStatus finished\n");
979 :
980 277 : return status;
981 : }
982 :
983 278 : NaClErrorCode NaClWaitForStartModuleCommand(struct NaClApp *nap) {
984 : NaClErrorCode status;
985 :
986 278 : NaClLog(4, "NaClWaitForStartModuleCommand started\n");
987 278 : NaClXMutexLock(&nap->mu);
988 574 : while (nap->module_initialization_state < NACL_MODULE_STARTED) {
989 18 : NaClXCondVarWait(&nap->cv, &nap->mu);
990 : }
991 278 : status = nap->module_load_status;
992 278 : NaClXMutexUnlock(&nap->mu);
993 278 : NaClLog(4, "NaClWaitForStartModuleCommand finished\n");
994 :
995 278 : return status;
996 : }
997 :
998 11 : void NaClBlockIfCommandChannelExists(struct NaClApp *nap) {
999 11 : if (NULL != nap->secure_service) {
1000 : for (;;) {
1001 : struct nacl_abi_timespec req;
1002 0 : req.tv_sec = 1000;
1003 0 : req.tv_nsec = 0;
1004 0 : NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL);
1005 0 : }
1006 : }
1007 11 : }
1008 :
1009 9 : void NaClSecureCommandChannel(struct NaClApp *nap) {
1010 : struct NaClSecureService *secure_command_server;
1011 :
1012 9 : NaClLog(4, "Entered NaClSecureCommandChannel\n");
1013 :
1014 9 : secure_command_server = (struct NaClSecureService *) malloc(
1015 : sizeof *secure_command_server);
1016 9 : if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__malloc",
1017 : NULL == secure_command_server)) {
1018 0 : NaClLog(LOG_FATAL, "Out of memory for secure command channel\n");
1019 : }
1020 9 : if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__NaClSecureServiceCtor",
1021 : !NaClSecureServiceCtor(secure_command_server,
1022 : nap,
1023 : nap->secure_service_port,
1024 : nap->secure_service_address))) {
1025 0 : NaClLog(LOG_FATAL, "NaClSecureServiceCtor failed\n");
1026 : }
1027 9 : nap->secure_service = secure_command_server;
1028 :
1029 9 : NaClLog(4, "NaClSecureCommandChannel: starting service thread\n");
1030 9 : if (NACL_FI_ERROR_COND(
1031 : "NaClSecureCommandChannel__NaClSimpleServiceStartServiceThread",
1032 : !NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
1033 : secure_command_server))) {
1034 0 : NaClLog(LOG_FATAL,
1035 : "Could not start secure command channel service thread\n");
1036 : }
1037 :
1038 9 : NaClLog(4, "Leaving NaClSecureCommandChannel\n");
1039 9 : }
1040 :
1041 :
1042 288 : void NaClAppLoadModule(struct NaClApp *nap,
1043 : struct NaClDesc *nexe,
1044 : void (*load_cb)(void *instance_data,
1045 : NaClErrorCode status),
1046 : void *instance_data) {
1047 288 : NaClErrorCode status = LOAD_OK;
1048 :
1049 288 : NaClLog(4,
1050 : ("Entered NaClAppLoadModule: nap 0x%"NACL_PRIxPTR","
1051 : " nexe 0x%"NACL_PRIxPTR"\n"),
1052 : (uintptr_t) nap, (uintptr_t) nexe);
1053 : /*
1054 : * Ref was passed by value into |nexe| parameter, so up the refcount.
1055 : * Be sure to unref when the parameter's copy goes out of scope
1056 : * (when returning).
1057 : */
1058 288 : NaClDescRef(nexe);
1059 :
1060 : /*
1061 : * TODO(bsy): consider doing the processing below after sending the
1062 : * RPC reply to increase parallelism.
1063 : */
1064 288 : NaClXMutexLock(&nap->mu);
1065 288 : if (nap->module_initialization_state != NACL_MODULE_UNINITIALIZED) {
1066 0 : NaClLog(LOG_ERROR, "NaClAppLoadModule: repeated invocation\n");
1067 0 : status = LOAD_DUP_LOAD_MODULE;
1068 0 : NaClXMutexUnlock(&nap->mu);
1069 0 : if (NULL != load_cb) {
1070 0 : (*load_cb)(instance_data, status);
1071 : }
1072 0 : NaClDescUnref(nexe);
1073 0 : return;
1074 : }
1075 288 : nap->module_initialization_state = NACL_MODULE_LOADING;
1076 288 : NaClXCondVarBroadcast(&nap->cv);
1077 288 : NaClXMutexUnlock(&nap->mu);
1078 :
1079 288 : if (NULL != load_cb) {
1080 7 : (*load_cb)(instance_data, status);
1081 : }
1082 :
1083 288 : NaClXMutexLock(&nap->mu);
1084 :
1085 : /*
1086 : * Check and possibly mark the nexe binary as OK to attempt memory
1087 : * mapping. We first clear the safe-for-mmap flag -- if we do not
1088 : * trust the renderer to really send us a safe-to-mmap descriptor
1089 : * and have to query the validation cache, then we also do not want
1090 : * to trust the metadata flag value that originated from the
1091 : * renderer.
1092 : */
1093 288 : NaClDescMarkUnsafeForMmap(nexe);
1094 288 : NaClReplaceDescIfValidationCacheAssertsMappable(&nexe,
1095 : nap->validation_cache);
1096 : /* Transfer ownership from nexe to nap->main_nexe_desc. */
1097 288 : CHECK(nap->main_nexe_desc == NULL);
1098 288 : nap->main_nexe_desc = nexe;
1099 288 : nexe = NULL;
1100 :
1101 288 : status = NACL_FI_VAL("load_module", NaClErrorCode,
1102 : NaClAppLoadFile(nap->main_nexe_desc, nap));
1103 :
1104 286 : if (LOAD_OK != status) {
1105 10 : nap->module_load_status = status;
1106 10 : nap->module_initialization_state = NACL_MODULE_ERROR;
1107 10 : NaClXCondVarBroadcast(&nap->cv);
1108 : }
1109 286 : NaClXMutexUnlock(&nap->mu); /* NaClAppPrepareToLaunch takes mu */
1110 286 : if (LOAD_OK != status) {
1111 10 : NaClDescUnref(nap->main_nexe_desc);
1112 10 : nap->main_nexe_desc = NULL;
1113 10 : return;
1114 : }
1115 :
1116 : /***************************************************************************
1117 : * TODO(bsy): Remove/merge the code invoking NaClAppPrepareToLaunch
1118 : * and NaClGdbHook below with sel_main's main function. See comment
1119 : * there.
1120 : ***************************************************************************/
1121 :
1122 : /*
1123 : * Finish setting up the NaCl App.
1124 : */
1125 276 : status = NaClAppPrepareToLaunch(nap);
1126 :
1127 276 : NaClXMutexLock(&nap->mu);
1128 276 : nap->module_load_status = status;
1129 276 : nap->module_initialization_state = NACL_MODULE_LOADED;
1130 276 : NaClXCondVarBroadcast(&nap->cv);
1131 276 : NaClXMutexUnlock(&nap->mu);
1132 :
1133 : /* Give debuggers a well known point at which xlate_base is known. */
1134 276 : NaClGdbHook(nap);
1135 : }
1136 :
1137 3 : int NaClAppRuntimeHostSetup(struct NaClApp *nap,
1138 : struct NaClRuntimeHostInterface *host_itf) {
1139 3 : NaClErrorCode status = LOAD_OK;
1140 :
1141 3 : NaClLog(4,
1142 : ("Entered NaClAppRuntimeHostSetup, nap 0x%"NACL_PRIxPTR","
1143 : " host_itf 0x%"NACL_PRIxPTR"\n"),
1144 : (uintptr_t) nap, (uintptr_t) host_itf);
1145 :
1146 3 : NaClXMutexLock(&nap->mu);
1147 3 : if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1148 0 : NaClLog(LOG_ERROR, "NaClAppRuntimeHostSetup: too late\n");
1149 0 : status = LOAD_INTERNAL;
1150 0 : goto cleanup_status_mu;
1151 : }
1152 :
1153 3 : nap->runtime_host_interface = (struct NaClRuntimeHostInterface *)
1154 3 : NaClRefCountRef((struct NaClRefCount *) host_itf);
1155 :
1156 : /*
1157 : * Hook up runtime host enabled resources, e.g.,
1158 : * DEBUG_ONLY:dev://postmessage. NB: Resources specified by
1159 : * file:path should have been taken care of earlier, in
1160 : * NaClAppInitialDescriptorHookup.
1161 : */
1162 3 : nap->resource_phase = NACL_RESOURCE_PHASE_RUNTIME_HOST;
1163 3 : NaClLog(4, "Processing dev I/O redirection/inheritance from environment\n");
1164 3 : NaClProcessRedirControl(nap);
1165 3 : NaClLog(4, "... done.\n");
1166 :
1167 : cleanup_status_mu:
1168 3 : NaClXMutexUnlock(&nap->mu);
1169 3 : return (int) status;
1170 : }
1171 :
1172 3 : int NaClAppDescQuotaSetup(struct NaClApp *nap,
1173 : struct NaClDescQuotaInterface *quota_itf) {
1174 3 : NaClErrorCode status = LOAD_OK;
1175 :
1176 3 : NaClLog(4,
1177 : ("Entered NaClAppDescQuotaSetup, nap 0x%"NACL_PRIxPTR","
1178 : " quota_itf 0x%"NACL_PRIxPTR"\n"),
1179 : (uintptr_t) nap, (uintptr_t) quota_itf);
1180 :
1181 3 : NaClXMutexLock(&nap->mu);
1182 3 : if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1183 0 : NaClLog(LOG_ERROR, "NaClAppDescQuotaSetup: too late\n");
1184 0 : status = LOAD_INTERNAL;
1185 0 : goto cleanup_status_mu;
1186 : }
1187 :
1188 3 : nap->desc_quota_interface = (struct NaClDescQuotaInterface *)
1189 3 : NaClRefCountRef((struct NaClRefCount *) quota_itf);
1190 :
1191 : cleanup_status_mu:
1192 3 : NaClXMutexUnlock(&nap->mu);
1193 3 : return (int) status;
1194 : }
1195 :
1196 280 : void NaClAppStartModule(struct NaClApp *nap,
1197 : void (*start_cb)(void *instance_data,
1198 : NaClErrorCode status),
1199 : void *instance_data) {
1200 : NaClErrorCode status;
1201 :
1202 280 : NaClLog(4,
1203 : ("Entered NaClAppStartModule, nap 0x%"NACL_PRIxPTR","
1204 : " start_cb 0x%"NACL_PRIxPTR", instance_data 0x%"NACL_PRIxPTR"\n"),
1205 : (uintptr_t) nap, (uintptr_t) start_cb, (uintptr_t) instance_data);
1206 :
1207 : /*
1208 : * When module is loading, we have to block and wait till it is
1209 : * fully loaded before we can proceed with start module.
1210 : */
1211 280 : NaClXMutexLock(&nap->mu);
1212 280 : if (NACL_MODULE_LOADING == nap->module_initialization_state) {
1213 0 : while (NACL_MODULE_LOADED != nap->module_initialization_state) {
1214 0 : NaClXCondVarWait(&nap->cv, &nap->mu);
1215 : }
1216 : }
1217 280 : if (nap->module_initialization_state != NACL_MODULE_LOADED) {
1218 11 : if (NACL_MODULE_ERROR == nap->module_initialization_state) {
1219 10 : NaClLog(LOG_ERROR, "NaClAppStartModule: error loading module\n");
1220 10 : status = nap->module_load_status;
1221 1 : } else if (nap->module_initialization_state > NACL_MODULE_LOADED) {
1222 0 : NaClLog(LOG_ERROR, "NaClAppStartModule: repeated invocation\n");
1223 0 : status = LOAD_DUP_START_MODULE;
1224 1 : } else if (nap->module_initialization_state < NACL_MODULE_LOADED) {
1225 1 : NaClLog(LOG_ERROR, "NaClAppStartModule: module not loaded\n");
1226 1 : status = LOAD_INTERNAL;
1227 : }
1228 11 : NaClXMutexUnlock(&nap->mu);
1229 11 : if (NULL != start_cb) {
1230 0 : (*start_cb)(instance_data, status);
1231 : }
1232 291 : return;
1233 : }
1234 269 : status = nap->module_load_status;
1235 269 : nap->module_initialization_state = NACL_MODULE_STARTING;
1236 269 : NaClXCondVarBroadcast(&nap->cv);
1237 269 : NaClXMutexUnlock(&nap->mu);
1238 :
1239 269 : NaClLog(4, "NaClSecureChannelStartModule: load status %d\n", status);
1240 :
1241 : /*
1242 : * We need to invoke the callback now, before we signal the main thread
1243 : * to possibly start by setting the state to NACL_MODULE_STARTED, since
1244 : * in the case of failure the main thread may quickly exit; if the main
1245 : * thread does this before we sent the reply, than the plugin (or any
1246 : * other runtime host interface) will be left without an aswer. The
1247 : * NACL_MODULE_STARTING state is used as an intermediate state to prevent
1248 : * double invocations violating the protocol.
1249 : */
1250 269 : if (NULL != start_cb) {
1251 9 : (*start_cb)(instance_data, status);
1252 : }
1253 :
1254 269 : NaClXMutexLock(&nap->mu);
1255 269 : nap->module_initialization_state = NACL_MODULE_STARTED;
1256 269 : NaClXCondVarBroadcast(&nap->cv);
1257 269 : NaClXMutexUnlock(&nap->mu);
1258 : }
1259 :
1260 5 : void NaClAppShutdown(struct NaClApp *nap,
1261 : int exit_status) {
1262 5 : NaClLog(4, "NaClAppShutdown: nap 0x%"NACL_PRIxPTR
1263 : ", exit_status %d\n", (uintptr_t) nap, exit_status);
1264 :
1265 5 : NaClXMutexLock(&nap->mu);
1266 5 : nap->exit_status = exit_status;
1267 5 : NaClXMutexUnlock(&nap->mu);
1268 5 : if (NULL != nap->debug_stub_callbacks) {
1269 0 : nap->debug_stub_callbacks->process_exit_hook();
1270 : }
1271 5 : NaClExit(0);
1272 0 : }
1273 :
1274 : /*
1275 : * It is fine to have multiple I/O operations read from memory in Write
1276 : * or SendMsg like operations.
1277 : */
1278 91579 : void NaClVmIoWillStart(struct NaClApp *nap,
1279 : uint32_t addr_first_usr,
1280 : uint32_t addr_last_usr) {
1281 91579 : NaClXMutexLock(&nap->mu);
1282 91580 : (*nap->mem_io_regions->vtbl->AddInterval)(nap->mem_io_regions,
1283 : addr_first_usr,
1284 : addr_last_usr);
1285 91580 : NaClXMutexUnlock(&nap->mu);
1286 91580 : }
1287 :
1288 :
1289 91543 : void NaClVmIoHasEnded(struct NaClApp *nap,
1290 : uint32_t addr_first_usr,
1291 : uint32_t addr_last_usr) {
1292 91543 : NaClXMutexLock(&nap->mu);
1293 91578 : (*nap->mem_io_regions->vtbl->RemoveInterval)(nap->mem_io_regions,
1294 : addr_first_usr,
1295 : addr_last_usr);
1296 91578 : NaClXMutexUnlock(&nap->mu);
1297 91578 : }
1298 :
1299 94647 : void NaClVmIoPendingCheck_mu(struct NaClApp *nap,
1300 : uint32_t addr_first_usr,
1301 : uint32_t addr_last_usr) {
1302 94647 : if ((*nap->mem_io_regions->vtbl->OverlapsWith)(nap->mem_io_regions,
1303 : addr_first_usr,
1304 : addr_last_usr)) {
1305 2 : NaClLog(LOG_FATAL,
1306 : "NaClVmIoWillStart: program mem write race detected. ABORTING\n");
1307 : }
1308 94645 : }
1309 :
1310 : /*
1311 : * GDB's canonical overlay managment routine.
1312 : * We need its symbol in the symbol table so don't inline it.
1313 : * TODO(dje): add some explanation for the non-GDB person.
1314 : */
1315 : #if NACL_WINDOWS
1316 : __declspec(dllexport noinline)
1317 : #endif
1318 : #ifdef __GNUC__
1319 : __attribute__((noinline))
1320 : #endif
1321 280 : void _ovly_debug_event (void) {
1322 : #ifdef __GNUC__
1323 : /*
1324 : * The asm volatile is here as instructed by the GCC docs.
1325 : * It's not enough to declare a function noinline.
1326 : * GCC will still look inside the function to see if it's worth calling.
1327 : */
1328 280 : __asm__ volatile ("");
1329 : #elif NACL_WINDOWS
1330 : /*
1331 : * Visual Studio inlines empty functions even with noinline attribute,
1332 : * so we need a compile memory barrier to make this function not to be
1333 : * inlined. Also, it guarantees that nacl_global_xlate_base initialization
1334 : * is not reordered. This is important for gdb since it sets breakpoint on
1335 : * this function and reads nacl_global_xlate_base value.
1336 : */
1337 : _ReadWriteBarrier();
1338 : #endif
1339 280 : }
1340 :
1341 280 : static void StopForDebuggerInit (uintptr_t mem_start) {
1342 : /* Put xlate_base in a place where gdb can find it. */
1343 280 : nacl_global_xlate_base = mem_start;
1344 :
1345 280 : NaClSandboxMemoryStartForValgrind(mem_start);
1346 :
1347 280 : _ovly_debug_event();
1348 280 : }
1349 :
1350 280 : void NaClGdbHook(struct NaClApp const *nap) {
1351 280 : StopForDebuggerInit(nap->mem_start);
1352 280 : }
|