Merge branch 'upstream'
[nativeclient.git] / service_runtime / sel_ldr.c
blob67921972169f4b61d5df40f6edea4a58d947a1ba
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl Simple/secure ELF loader (NaCl SEL).
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
40 #include "native_client/service_runtime/sel_ldr.h"
42 #include "native_client/intermodule_comm/nacl_imc_c.h"
44 #include "native_client/service_runtime/nacl_config.h"
45 #include "native_client/service_runtime/nacl_check.h"
46 #include "native_client/service_runtime/nacl_desc_base.h"
47 #include "native_client/service_runtime/nacl_desc_conn_cap.h"
48 #include "native_client/service_runtime/nacl_desc_effector_cleanup.h"
49 #include "native_client/service_runtime/nacl_desc_imc.h"
50 #include "native_client/service_runtime/nacl_desc_io.h"
51 #include "native_client/service_runtime/nacl_globals.h"
52 #include "native_client/service_runtime/nacl_syscall_common.h"
53 #include "native_client/service_runtime/nacl_sync_checked.h"
55 #include "native_client/service_runtime/sel_memory.h"
56 #include "native_client/service_runtime/sel_util.h"
57 #include "native_client/service_runtime/sel_addrspace.h"
58 #include "native_client/service_runtime/sel_rt.h"
60 #include "native_client/service_runtime/nacl_syscall_asm_symbols.h"
62 #include "native_client/service_runtime/nrd_xfer_lib/nrd_xfer.h"
63 #include "native_client/service_runtime/nrd_xfer_lib/nrd_xfer_effector.h"
65 #include "native_client/service_runtime/tramp.h"
66 #include "native_client/service_runtime/springboard.h"
68 #include "native_client/service_runtime/include/bits/nacl_syscalls.h"
70 #include "native_client/tools/libsrpc/nacl_srpc.h"
72 #if NACL_WINDOWS
73 # include <io.h>
74 #endif
76 int NaClAppCtor(struct NaClApp *nap)
78 NACL_THREAD_CHECK;
80 nap->addr_bits = NACL_MAX_ADDR_BITS;
82 nap->max_data_alloc = NACL_DEFAULT_ALLOC_MAX;
83 nap->stack_size = NACL_DEFAULT_STACK_MAX;
85 nap->data_mem_start = 0;
86 nap->code_mem_start = 0;
87 nap->text_region_end = 0;
88 nap->data_end = 0;
90 nap->entry_pt = 0;
92 if (!DynArrayCtor(&nap->threads, 2)) {
93 goto cleanup_none;
95 if (!DynArrayCtor(&nap->desc_tbl, 2)) {
96 goto cleanup_threads;
98 if (!NaClVmmapCtor(&nap->mem_map)) {
99 goto cleanup_desc_tbl;
102 nap->phdrs = NULL;
103 nap->service_port = NULL;
104 nap->service_address = NULL;
105 nap->secure_channel = NULL;
107 if (!NaClMutexCtor(&nap->mu)) {
108 goto cleanup_mem_map;
110 if (!NaClCondVarCtor(&nap->cv)) {
111 goto cleanup_mu;
114 nap->origin = (char *) NULL;
115 nap->module_load_status = LOAD_STATUS_UNKNOWN;
116 nap->module_may_start = 0; /* only when secure_channel != NULL */
118 nap->restrict_to_main_thread = 1;
120 if (!NaClSyncQueueCtor(&nap->work_queue)) {
121 goto cleanup_cv;
124 if (!NaClMutexCtor(&nap->threads_mu)) {
125 goto cleanup_work_queue;
127 if (!NaClCondVarCtor(&nap->threads_cv)) {
128 goto cleanup_threads_mu;
130 nap->num_threads = 0;
131 if (!NaClMutexCtor(&nap->desc_mu)) {
132 goto cleanup_threads_cv;
135 nap->running = 0;
136 nap->exit_status = -1;
138 nap->code_seg_sel = 0;
139 nap->data_seg_sel = 0;
141 nap->freeze_thread_ops = 0;
143 return 1;
145 #if 0
146 cleanup_desc_mu:
147 NaClMutexDtor(&nap->desc_mu);
148 #endif
149 cleanup_threads_cv:
150 NaClCondVarDtor(&nap->threads_cv);
151 cleanup_threads_mu:
152 NaClMutexDtor(&nap->threads_mu);
153 cleanup_work_queue:
154 NaClSyncQueueDtor(&nap->work_queue);
155 cleanup_cv:
156 NaClCondVarDtor(&nap->cv);
157 cleanup_mu:
158 NaClMutexDtor(&nap->mu);
159 cleanup_mem_map:
160 NaClVmmapDtor(&nap->mem_map);
161 cleanup_desc_tbl:
162 DynArrayDtor(&nap->desc_tbl);
163 cleanup_threads:
164 DynArrayDtor(&nap->threads);
165 cleanup_none:
166 return 0;
169 void NaClAppDtor(struct NaClApp *nap)
171 int i;
172 struct NaClDesc *ndp;
173 struct NaClAppThread *natp;
175 NaClLog(2,
176 "NaClAppDtor: there are %d threads alive; thread table size %d\n",
177 nap->num_threads,
178 nap->threads.num_entries);
179 for (i = 0; i < nap->threads.num_entries; ++i) {
180 int refcount;
181 enum NaClThreadState state;
183 NaClLog(2, "Checking thread %d\n", i);
184 if (NULL == (natp = NaClGetThreadMu(nap, i))) {
185 continue;
187 NaClLog(2, "Extracting state for thread %d\n", i);
188 NaClXMutexLock(&natp->mu);
189 state = natp->state;
190 NaClLog(2, "state %d\n", state);
191 NaClXMutexUnlock(&natp->mu);
193 NaClRemoveThreadMu(nap, i);
194 refcount = NaClAppThreadDecRef(natp);
196 if (state != NACL_APP_THREAD_DEAD) {
197 NaClLog(LOG_WARNING,
198 ("NaClAppDtor: thread %d still running when NaCl app"
199 " is being destroyed?!?\n"),
202 if (refcount != 0) {
203 NaClLog(LOG_WARNING,
204 ("NaClAppDtor: thread %d refcount not 0 when NaCl app"
205 " is being destroyed?!?\n"),
210 for (i = 0; i < nap->desc_tbl.num_entries; ++i) {
211 ndp = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, i);
212 if (NULL != ndp) {
213 NaClDescUnref(ndp);
217 NaClMutexDtor(&nap->desc_mu);
218 NaClMutexDtor(&nap->threads_mu);
219 NaClCondVarDtor(&nap->threads_cv);
220 NaClSyncQueueDtor(&nap->work_queue);
221 free(nap->origin);
222 nap->origin = (char *) NULL;
223 NaClCondVarDtor(&nap->cv);
224 NaClMutexDtor(&nap->mu);
226 NaClAppFreeAllMemory(nap);
228 NaClVmmapDtor(&nap->mem_map);
230 DynArrayDtor(&nap->desc_tbl);
231 DynArrayDtor(&nap->threads);
233 return;
236 size_t NaClAlignPad(size_t val,
237 size_t align)
239 /* align is always a power of 2, but we do not depend on it */
240 if (!align) {
241 NaClLog(0,
242 "sel_ldr: NaClAlignPad, align == 0, at 0x%08"PRIxS"\n",
243 val);
244 return 0;
246 val = val % align;
247 if (!val) return 0;
248 return align - val;
252 * unaligned little-endian load
254 uint32_t NaClLoad32(uintptr_t addr)
256 uint8_t *p = (uint8_t *) addr;
258 return p[0] | (p[1] << 8) | (p[2] << 16) | p[3] << 24;
262 * unaligned little-endian store
264 void NaClStore32(uintptr_t addr,
265 uint32_t v)
267 uint8_t *p = (uint8_t *) addr;
269 p[0] = (uint8_t) (v >> 0);
270 p[1] = (uint8_t) (v >> 8);
271 p[2] = (uint8_t) (v >> 16);
272 p[3] = (uint8_t) (v >> 24);
275 uint16_t NaClLoad16(uintptr_t addr)
277 uint8_t *p = (uint8_t *) addr;
279 return p[0] | (p[1] << 8);
282 void NaClStore16(uintptr_t addr,
283 uint16_t v)
285 uint8_t *p = (uint8_t *) addr;
287 p[0] = (uint8_t) (v >> 0);
288 p[1] = (uint8_t) (v >> 8);
292 * target is an absolute address in the source region. the patch code
293 * will figure out the corresponding address in the destination region
294 * and modify as appropriate. this makes it easier to specify, since
295 * the target is typically the address of some symbol from the source
296 * template.
298 struct NaClPatch {
299 uint32_t target, value;
302 struct NaClPatchInfo {
303 uintptr_t dst;
304 uintptr_t src;
305 size_t nbytes;
306 uintptr_t *rel32;
307 size_t num_rel32;
308 struct NaClPatch *abs32;
309 size_t num_abs32;
310 struct NaClPatch *abs16;
311 size_t num_abs16;
314 void NaClPatchMemory(struct NaClPatchInfo *patch)
316 size_t i;
317 size_t offset;
318 size_t reloc;
319 uintptr_t target_addr;
321 memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
323 reloc = patch->dst - patch->src;
325 for (i = 0; i < patch->num_rel32; ++i) {
326 offset = patch->rel32[i] - patch->src;
327 target_addr = patch->dst + offset;
328 NaClStore32(target_addr, NaClLoad32(target_addr) - reloc);
331 for (i = 0; i < patch->num_abs32; ++i) {
332 offset = patch->abs32[i].target - patch->src;
333 target_addr = patch->dst + offset;
334 NaClStore32(target_addr, patch->abs32[i].value);
337 for (i = 0; i < patch->num_abs16; ++i) {
338 offset = patch->abs16[i].target - patch->src;
339 target_addr = patch->dst + offset;
340 NaClStore16(target_addr, patch->abs16[i].value);
345 * Install a syscall trampoline at target_addr. NB: Thread-safe.
347 void NaClPatchOneTrampoline(struct NaClApp *nap,
348 uintptr_t target_addr)
350 struct NaClPatchInfo patch_info;
352 struct NaClPatch patch16[1];
353 struct NaClPatch patch32[2];
355 patch16[0].target = ((uintptr_t) &NaCl_tramp_cseg_patch) - 2;
356 patch16[0].value = nacl_global_cs;
358 patch_info.abs16 = patch16;
359 patch_info.num_abs16 = sizeof patch16/sizeof patch16[0];
361 patch_info.rel32 = 0;
362 patch_info.num_rel32 = 0;
364 patch32[0].target = ((uintptr_t) &NaCl_tramp_cseg_patch) - 6;
365 patch32[0].value = (uintptr_t) NaClSyscallSeg;
367 patch32[1].target = ((uintptr_t) &NaCl_tramp_dseg_patch) - 4;
368 patch32[1].value = nacl_global_ds; /* opens the data sandbox */
370 patch_info.abs32 = patch32;
371 patch_info.num_abs32 = sizeof patch32/sizeof patch32[0];
373 patch_info.dst = target_addr;
374 patch_info.src = (uintptr_t) &NaCl_trampoline_seg_code;
375 patch_info.nbytes = ((uintptr_t) &NaCl_trampoline_seg_end
376 - (uintptr_t) &NaCl_trampoline_seg_code);
378 NaClPatchMemory(&patch_info);
382 * Install syscall trampolines at all possible well-formed entry
383 * points within the trampoline pages. Many of these syscalls will
384 * correspond to unimplemented system calls and will just abort the
385 * program.
387 void NaClLoadTrampoline(struct NaClApp *nap)
389 int num_syscalls;
390 int i;
391 uintptr_t addr;
393 /* fill trampoline region with HLT */
394 memset((void *) nap->code_mem_start, NACL_HALT_OPCODE, NACL_TRAMPOLINE_SIZE);
397 * Do not bother to fill in the contents of page 0, since we make it
398 * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
399 * anyway to help detect NULL pointer errors, and we might as well
400 * not dirty the page.
402 * The last syscall entry point is used for springboard code.
404 num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR)
405 / NACL_SYSCALL_BLOCK_SIZE) - 1;
407 NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
409 for (i = 0, addr = nap->code_mem_start + NACL_SYSCALL_START_ADDR;
410 i < num_syscalls;
411 ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
412 NaClPatchOneTrampoline(nap, addr);
417 void NaClLoadSpringboard(struct NaClApp *nap)
420 * patch in springboard.S code into space in place of
421 * the last syscall in the trampoline region.
423 struct NaClPatchInfo patch_info;
424 struct NaClPatch abs32;
426 patch_info.rel32 = 0;
427 patch_info.num_rel32 = 0;
428 patch_info.abs32 = &abs32;
429 patch_info.num_abs32 = 0;
430 patch_info.abs16 = 0;
431 patch_info.num_abs16 = 0;
433 nap->springboard_addr = NACL_TRAMPOLINE_END - nap->align_boundary;
435 patch_info.dst = nap->code_mem_start + nap->springboard_addr;
436 patch_info.src = (uintptr_t) &NaCl_springboard;
437 patch_info.nbytes = ((uintptr_t) &NaCl_springboard_end
438 - (uintptr_t) &NaCl_springboard);
440 NaClPatchMemory(&patch_info);
442 nap->springboard_addr++; /* skip the hlt */
445 void NaClMemRegionPrinter(void *state,
446 struct NaClVmmapEntry *entry) {
447 struct Gio *gp = (struct Gio *) state;
449 gprintf(gp, "\nPage %d (0x%x)\n", entry->page_num, entry->page_num);
450 gprintf(gp, "npages %d (0x%x)\n", entry->npages, entry->npages);
451 gprintf(gp, "prot 0x%08x\n", entry->prot);
452 gprintf(gp, "%sshared/backed by a file\n",
453 (NULL == entry->nmop) ? "not " : "");
456 void NaClAppPrintDetails(struct NaClApp *nap,
457 struct Gio *gp)
459 NaClXMutexLock(&nap->mu);
460 gprintf(gp,
461 "NaClAppPrintDetails((struct NaClApp *) 0x%08x,"
462 "(struct Gio *) 0x%08x)\n", (uintptr_t) nap, (uintptr_t) gp);
463 gprintf(gp, "addr space size: 2**%d\n", nap->addr_bits);
464 gprintf(gp, "max data alloc: 0x%08x\n", nap->max_data_alloc);
465 gprintf(gp, "stack size: 0x%08x\n", nap->stack_size);
467 gprintf(gp, "data mem start addr: 0x%08x\n", nap->data_mem_start);
468 gprintf(gp, "code mem start addr: 0x%08x\n", nap->code_mem_start);
469 /* 123456789012345678901234567890 */
471 gprintf(gp, "text_region_end: 0x%08x\n", nap->text_region_end);
472 gprintf(gp, "data_end: 0x%08x\n", nap->data_end);
473 gprintf(gp, "break_addr: 0x%08x\n", nap->break_addr);
475 gprintf(gp, "ELF entry point: 0x%08x\n", nap->entry_pt);
476 gprintf(gp, "memory map:\n");
477 NaClVmmapVisit(&nap->mem_map,
478 NaClMemRegionPrinter,
479 gp);
480 NaClXMutexUnlock(&nap->mu);
483 /* deprecated */
484 char const *NaClAppLoadErrorString(NaClErrorCode errcode) {
485 NaClLog(0, "Deprecated NaClAppLoadErrorString interface used\n");
486 return NaClErrorString(errcode);
489 char const *NaClErrorString(NaClErrorCode errcode)
491 switch (errcode) {
492 case LOAD_OK:
493 return "Ok";
494 case LOAD_STATUS_UNKNOWN:
495 return "Load status unknown (load incomplete)";
496 case LOAD_UNSUPPORTED_OS_PLATFORM:
497 return "Operating system platform is not supported";
498 case LOAD_INTERNAL:
499 return "Internal error";
500 case LOAD_READ_ERROR:
501 return "Cannot read file";
502 case LOAD_BAD_ELF_MAGIC:
503 return "Bad ELF header magic number";
504 case LOAD_NOT_32_BIT:
505 return "Not a 32-bit ELF file";
506 case LOAD_BAD_ABI:
507 return "ELF file has unexpected OS ABI";
508 case LOAD_NOT_EXEC:
509 return "ELF file type not executable";
510 case LOAD_BAD_MACHINE:
511 return "ELF file for wrong architecture";
512 case LOAD_BAD_ELF_VERS:
513 return "ELF version mismatch";
514 case LOAD_TOO_MANY_SECT:
515 return "Too many section headers";
516 case LOAD_BAD_SECT:
517 return "ELF bad sections";
518 case LOAD_NO_MEMORY:
519 return "Insufficient memory to load file";
520 case LOAD_SECT_HDR:
521 return "ELF section header string table load error";
522 case LOAD_ADDR_SPACE_TOO_SMALL:
523 return "Address space too small";
524 case LOAD_ADDR_SPACE_TOO_BIG:
525 return "Address space too big";
526 case LOAD_DATA_OVERLAPS_STACK_SECTION:
527 return ("Memory \"hole\" between end of BSS and start of stack"
528 " is negative in size");
529 case LOAD_UNLOADABLE:
530 return "Error during loading";
531 case LOAD_BAD_ELF_TEXT:
532 return "ELF file contains no text segment";
533 case LOAD_TEXT_SEG_TOO_BIG:
534 return "ELF file text segment too large";
535 case LOAD_DATA_SEG_TOO_BIG:
536 return "ELF file data segment(s) too large";
537 case LOAD_MPROTECT_FAIL:
538 return "Cannot protect pages";
539 case LOAD_MADVISE_FAIL:
540 return "Cannot release unused data segment";
541 case LOAD_TOO_MANY_SYMBOL_STR:
542 return "Malformed ELF file: too many string tables";
543 case LOAD_SYMTAB_ENTRY_TOO_SMALL:
544 return "Symbol table entry too small";
545 case LOAD_NO_SYMTAB:
546 return "No symbol table";
547 case LOAD_NO_SYMTAB_STRINGS:
548 return "No string table for symbols";
549 case LOAD_SYMTAB_ENTRY:
550 return "Error entering new symbol into symbol table";
551 case LOAD_UNKNOWN_SYMBOL_TYPE:
552 return "Unknown symbol type";
553 case LOAD_SYMTAB_DUP:
554 return "Duplicate entry in symbol table";
555 case LOAD_REL_ERROR:
556 return "Bad relocation read error";
557 case LOAD_REL_UNIMPL:
558 return "Relocation type unimplemented";
559 case LOAD_UNDEF_SYMBOL:
560 return "Undefined external symbol";
561 case LOAD_BAD_SYMBOL_DATA:
562 return "Bad symbol table data";
563 case LOAD_BAD_FILE:
564 return "ELF file not accessible";
565 case LOAD_BAD_ENTRY:
566 return "Bad symbol table entry: not a text symbol/entry point";
567 case LOAD_SEGMENT_OUTSIDE_ADDRSPACE:
568 return ("ELF executable contains a segment which lies outside"
569 " the assigned address space");
570 case LOAD_DUP_SEGMENT:
571 return ("ELF executable contains a duplicate segment"
572 " (please run objdump to see which)");
573 case LOAD_SEGMENT_BAD_LOC:
574 return "ELF executable text/rodata segment has wrong starting address";
575 case LOAD_BAD_SEGMENT:
576 return "ELF executable contains an unexpected/unallowed segment/flags";
577 case LOAD_REQUIRED_SEG_MISSING:
578 return "ELF executable missing a required segment (text)";
579 case LOAD_SEGMENT_BAD_PARAM:
580 return "ELF executable segment header parameter error";
581 case SRT_NO_SEG_SEL:
582 return "Service Runtime: cannot allocate segment selector";
586 * do not use default case label, to make sure that the compiler
587 * will generate a warning with -Wswitch-enum for new codes
588 * introduced in nacl_error_codes.h for which there is no
589 * corresponding entry here. instead, we pretend that fall-through
590 * from the switch is possible. (otherwise -W complains control
591 * reaches end of non-void function.)
593 return "BAD ERROR CODE";
596 struct NaClDesc *NaClGetDescMu(struct NaClApp *nap,
597 int d)
599 struct NaClDesc *result;
601 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
602 if (NULL != result) {
603 NaClDescRef(result);
606 return result;
609 void NaClSetDescMu(struct NaClApp *nap,
610 int d,
611 struct NaClDesc *ndp)
613 struct NaClDesc *result;
615 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
616 if (NULL != result) {
617 NaClDescUnref(result);
619 if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
620 NaClLog(LOG_FATAL,
621 "NaClSetDesc: could not set descriptor %d to 0x%08"PRIxPTR"\n",
623 (uintptr_t) ndp);
627 int NaClSetAvailMu(struct NaClApp *nap,
628 struct NaClDesc *ndp)
630 int pos;
632 pos = DynArrayFirstAvail(&nap->desc_tbl);
633 if (pos < 0) {
634 NaClLog(LOG_FATAL,
635 ("NaClSetAvailMu: DynArrayFirstAvail returned a negative"
636 " number as first available position\n"));
638 NaClSetDescMu(nap, pos, ndp);
640 return pos;
643 struct NaClDesc *NaClGetDesc(struct NaClApp *nap,
644 int d)
646 struct NaClDesc *res;
648 NaClXMutexLock(&nap->desc_mu);
649 res = NaClGetDescMu(nap, d);
650 NaClXMutexUnlock(&nap->desc_mu);
651 return res;
654 void NaClSetDesc(struct NaClApp *nap,
655 int d,
656 struct NaClDesc *ndp)
658 NaClXMutexLock(&nap->desc_mu);
659 NaClSetDescMu(nap, d, ndp);
660 NaClXMutexUnlock(&nap->desc_mu);
663 int NaClSetAvail(struct NaClApp *nap,
664 struct NaClDesc *ndp)
666 int pos;
668 NaClXMutexLock(&nap->desc_mu);
669 pos = NaClSetAvailMu(nap, ndp);
670 NaClXMutexUnlock(&nap->desc_mu);
672 return pos;
675 int NaClAddThreadMu(struct NaClApp *nap,
676 struct NaClAppThread *natp)
678 int pos;
680 pos = DynArrayFirstAvail(&nap->threads);
681 if (pos < 0) {
682 NaClLog(LOG_FATAL,
683 ("NaClAddThreadMu: DynArrayFirstAvail returned a negative"
684 " number as first available position\n"));
686 if (!DynArraySet(&nap->threads, pos, natp)) {
687 NaClLog(LOG_FATAL,
688 "NaClAddThreadMu: DynArraySet at position %d failed\n",
689 pos);
691 ++nap->num_threads;
692 return pos;
695 int NaClAddThread(struct NaClApp *nap,
696 struct NaClAppThread *natp)
698 int pos;
700 NaClXMutexLock(&nap->threads_mu);
701 pos = NaClAddThreadMu(nap, natp);
702 NaClXMutexUnlock(&nap->threads_mu);
704 return pos;
708 * Assumes thread_num is valid.
710 void NaClRemoveThreadMu(struct NaClApp *nap,
711 int thread_num)
713 --nap->num_threads;
714 if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
715 NaClLog(LOG_FATAL,
716 "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
717 thread_num);
721 void NaClRemoveThread(struct NaClApp *nap,
722 int thread_num)
724 NaClXMutexLock(&nap->threads_mu);
725 NaClRemoveThreadMu(nap, thread_num);
726 NaClXCondVarBroadcast(&nap->threads_cv);
727 NaClXMutexUnlock(&nap->threads_mu);
730 struct NaClAppThread *NaClGetThreadMu(struct NaClApp *nap,
731 int thread_num)
733 return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
736 void NaClAddHostDescriptor(struct NaClApp *nap,
737 int host_os_desc,
738 int mode,
739 int nacl_desc)
741 struct NaClDescIoDesc *dp;
743 dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, mode));
744 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
747 void NaClAddImcHandle(struct NaClApp *nap,
748 NaClHandle h,
749 int nacl_desc)
751 struct NaClDescImcDesc *dp;
753 dp = malloc(sizeof *dp);
754 if (NULL == dp) {
755 NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
757 if (!NaClDescImcDescCtor(dp, h)) {
758 NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
759 " IMC descriptor object\n"));
761 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
764 void NaClAddImcAddr(struct NaClApp *nap,
765 struct NaClSocketAddress const *addr,
766 int nacl_desc)
768 struct NaClDescConnCap *dp;
770 dp = malloc(sizeof *dp);
771 if (NULL == dp) {
772 NaClLog(LOG_FATAL, "NaClAddImcAddr: no memory\n");
774 if (!NaClDescConnCapCtor(dp, addr)) {
775 NaClLog(LOG_FATAL, ("NaClAddImcAddr: canot construct"
776 " connection capability object\n"));
778 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
781 void NaClAppVmmapUpdate(struct NaClApp *nap,
782 uintptr_t page_num,
783 size_t npages,
784 int prot,
785 struct NaClMemObj *nmop,
786 int remove)
788 NaClXMutexLock(&nap->mu);
789 NaClVmmapUpdate(&nap->mem_map,
790 page_num,
791 npages,
792 prot,
793 nmop,
794 remove);
795 NaClXMutexUnlock(&nap->mu);
798 uintptr_t NaClAppVmmapFindSpace(struct NaClApp *nap,
799 int num_pages)
801 int rv;
803 NaClXMutexLock(&nap->mu);
804 rv = NaClVmmapFindSpace(&nap->mem_map,
805 num_pages);
806 NaClXMutexUnlock(&nap->mu);
807 return rv;
810 uintptr_t NaClAppVmmapFindMapSpace(struct NaClApp *nap,
811 int num_pages)
813 int rv;
815 NaClXMutexLock(&nap->mu);
816 rv = NaClVmmapFindMapSpace(&nap->mem_map,
817 num_pages);
818 NaClXMutexUnlock(&nap->mu);
819 return rv;
822 void NaClCreateServiceSocket(struct NaClApp *nap)
824 struct NaClDesc *pair[2];
826 NaClLog(3, "Entered NaClCreateServiceSocket\n");
827 NaClCommonDescMakeBoundSock(pair);
828 NaClLog(4,
829 "got bound socket at 0x%08"PRIxPTR", addr at 0x%08"PRIxPTR"\n",
830 (uintptr_t) pair[0],
831 (uintptr_t) pair[1]);
832 NaClSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
833 NaClSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
834 if (NULL != nap->service_port) {
835 NaClDescUnref(nap->service_port);
837 nap->service_port = pair[0];
838 NaClDescRef(nap->service_port);
839 if (NULL != nap->service_address) {
840 NaClDescUnref(nap->service_address);
842 nap->service_address = pair[1];
843 NaClDescRef(nap->service_address);
844 NaClLog(4, "Leaving NaClCreateServiceSocket\n");
847 void NaClSendServiceAddressTo(struct NaClApp *nap,
848 int desc)
850 struct NaClDesc *channel;
851 struct NaClImcTypedMsgHdr hdr;
852 int rv;
854 struct NaClNrdXferEffector nnxep;
856 NaClLog(4,
857 "NaClSendServiceAddressTo(0x%08"PRIxPTR", %d)\n",
858 (uintptr_t) nap,
859 desc);
861 channel = NaClGetDesc(nap, desc);
862 if (NULL == channel) {
863 NaClLog(LOG_FATAL,
864 "NaClSendServiceAddressTo: descriptor %d not in open file table\n",
865 desc);
866 /* NOTREACHED */
867 return;
869 if (NULL == nap->service_address) {
870 NaClLog(LOG_FATAL,
871 "NaClSendServiceAddressTo: service address not set\n");
872 /* NOTREACHED */
873 return;
876 * service_address and service_port are set together.
878 (void) NaClNrdXferEffectorCtor(&nnxep, nap->service_port);
880 hdr.iov = (struct NaClImcMsgIoVec *) NULL;
881 hdr.iov_length = 0;
882 hdr.ndescv = &nap->service_address;
883 hdr.ndesc_length = 1;
885 rv = NaClImcSendTypedMessage(channel,
886 (struct NaClDescEffector *) &nnxep,
887 &hdr, 0);
889 NaClDescUnref(channel);
890 channel = NULL;
892 (*nnxep.base.vtbl->Dtor)((struct NaClDescEffector *) &nnxep);
894 NaClLog(1,
895 "NaClSendServiceAddressTo: descriptor %d, error %d\n",
896 desc,
897 rv);
900 static int NaClSecureChannelShutdownRpc(struct NaClSrpcChannel *chan,
901 struct NaClSrpcArg **in_args,
902 struct NaClSrpcArg **out_args)
904 NaClLog(LOG_INFO, "NaClSecureChannelShutdownRpc (hard_shutdown)\n");
905 _exit(0);
908 static int NaClSecureChannelSetOriginRpc(struct NaClSrpcChannel *chan,
909 struct NaClSrpcArg **in_args,
910 struct NaClSrpcArg **out_args)
912 struct NaClApp *nap = (struct NaClApp *) chan->server_instance_data;
914 free(nap->origin);
915 nap->origin = strdup(in_args[0]->u.sval);
916 NaClLog(LOG_INFO, "NaClSecureChannelSetOriginRpc: origin %s\n", nap->origin);
917 return NACL_SRPC_RESULT_OK;
920 static int NaClSecureChannelStartModuleRpc(struct NaClSrpcChannel *chan,
921 struct NaClSrpcArg **in_args,
922 struct NaClSrpcArg **out_args)
925 * let module start if module is okay; otherwise report error (e.g.,
926 * ABI version mismatch).
928 struct NaClApp *nap = (struct NaClApp *) chan->server_instance_data;
929 NaClErrorCode status;
931 NaClLog(LOG_INFO, "NaClSecureChannelStartModuleRpc started\n");
932 NaClXMutexLock(&nap->mu);
933 while (LOAD_STATUS_UNKNOWN == (status = nap->module_load_status)) {
934 NaClCondVarWait(&nap->cv, &nap->mu);
936 nap->module_may_start = 1;
937 NaClXCondVarBroadcast(&nap->cv);
938 NaClXMutexUnlock(&nap->mu);
939 out_args[0]->u.ival = status;
940 NaClLog(LOG_INFO, "NaClSecureChannelStartModuleRpc finished\n");
941 return NACL_SRPC_RESULT_OK;
944 void NaClWaitForModuleStartStatusCall(struct NaClApp *nap)
946 NaClLog(LOG_INFO, "NaClWaitForModuleStartStatusCall started\n");
947 NaClXMutexLock(&nap->mu);
948 while (!nap->module_may_start) {
949 NaClXCondVarWait(&nap->cv, &nap->mu);
951 NaClXMutexUnlock(&nap->mu);
952 NaClLog(LOG_INFO, "NaClWaitForModuleStartStatusCall finished\n");
955 void WINAPI NaClSecureChannelThread(void *state)
957 struct NaClApp *nap = (struct NaClApp *) state;
959 static struct NaClSrpcHandlerDesc secure_handlers[] = {
960 { "hard_shutdown::", NaClSecureChannelShutdownRpc, },
961 { "start_module::i", NaClSecureChannelStartModuleRpc, },
962 { "set_origin:s:", NaClSecureChannelSetOriginRpc, },
963 /* add additional calls here. upcall set up? start module signal? */
964 { (char const *) NULL, (int (*)(struct NaClSrpcChannel *,
965 struct NaClSrpcArg **,
966 struct NaClSrpcArg **)) 0, },
969 NaClLog(LOG_INFO, "NaClSecureChannelThread started\n");
971 (void) NaClSrpcServerLoopImcDesc(nap->secure_channel,
972 secure_handlers,
973 nap);
974 NaClLog(LOG_INFO, "NaClSecureChannelThread: channel closed, exiting.\n");
975 _exit(0);
978 void NaClSecureCommandChannel(struct NaClApp *nap)
980 struct NaClNrdXferEffector nnxep;
981 int status;
983 NaClLog(LOG_INFO, "Waiting for secure command channel connect\n");
984 (void) NaClNrdXferEffectorCtor(&nnxep, nap->service_port);
986 * this block until the plugin connects
988 status = ((*nap->service_port->vtbl->AcceptConn)
989 (nap->service_port,
990 (struct NaClDescEffector *) &nnxep));
991 if (status < 0) {
992 NaClLog(LOG_FATAL,
993 "NaClSecureCommandChannel: unable to establish channel\n");
995 nap->secure_channel = NaClNrdXferEffectorTakeDesc(&nnxep);
997 (*nnxep.base.vtbl->Dtor)((struct NaClDescEffector *) &nnxep);
999 * Spawn secure channel thread.
1001 NaClThreadCtor(&nap->secure_channel_thr,
1002 NaClSecureChannelThread,
1003 nap,
1004 NACL_KERN_STACK_SIZE);
1005 NaClLog(LOG_INFO, "NaClSecureCommandChannel: thread spawned, continuing\n");
1008 void NaClDumpServiceAddressTo(struct NaClApp *nap,
1009 int desc)
1011 NaClLog(4,
1012 "NaClDumpServiceAddressTo(0x%08"PRIxPTR", %d)\n",
1013 (uintptr_t) nap,
1014 desc);
1015 if (NULL == nap->service_address) {
1016 NaClLog(LOG_FATAL,
1017 "NaClDumpServiceAddressTo: service address not set\n");
1018 /* NOTREACHED */
1019 return;
1021 if (sizeof ((struct NaClDescConnCap *) nap->service_address)->cap.path
1022 != write(desc,
1023 ((struct NaClDescConnCap *) nap->service_address)->cap.path,
1024 sizeof
1025 ((struct NaClDescConnCap *) nap->service_address)->cap.path)) {
1026 NaClLog(LOG_FATAL,
1027 "NaClDumpServiceAddressTo: could not send service address\n");
1031 struct NaClFreeState {
1032 struct NaClApp *nap;
1033 struct NaClDescEffector *effp;
1034 uintptr_t partial;
1035 size_t pbytes;
1038 static void NaClAppFreeWalker(void *state,
1039 struct NaClVmmapEntry *entry)
1041 struct NaClFreeState *p = (struct NaClFreeState *) state;
1042 uintptr_t sysaddr;
1043 size_t nbytes;
1045 NaClLog(3,
1046 ("NaClAppFreeWalker: p->partial = 0x%08"PRIxPTR","
1047 " p->pbytes = 0x%08"PRIxS"\n"),
1048 p->partial, p->pbytes);
1049 NaClLog(3,
1050 (" entry->page_num = 0x%"PRIxPTR", entry->npages = 0x%"PRIxS","
1051 " entry->nmop = 0x%08"PRIxPTR"\n"),
1052 entry->page_num, entry->npages, (uintptr_t) entry->nmop);
1053 sysaddr = NaClUserToSysAddrNullOkay(p->nap,
1054 entry->page_num << NACL_PAGESHIFT);
1055 nbytes = entry->npages << NACL_PAGESHIFT;
1056 if (NULL == entry->nmop) {
1057 if (0 != p->pbytes) {
1058 /* partial exists, accumulate and try to free */
1059 if (p->partial + p->pbytes != sysaddr) {
1060 NaClLog(LOG_FATAL,
1061 ("Partial allocation pages not contiguous?!?"
1062 " Partial start 0x%08"PRIxPTR", length 0x%"PRIxS";"
1063 " next start 0x%08"PRIxPTR"\n"),
1064 p->partial, p->pbytes, sysaddr);
1066 p->pbytes += nbytes;
1067 if (NaClRoundHostAllocPage(p->pbytes) == p->pbytes) {
1068 NaCl_page_free((void *) p->partial, p->pbytes);
1069 p->partial = 0;
1070 p->pbytes = 0;
1071 } else {
1072 NaClLog(3, "Partial accummulated 0x%08"PRIxPTR", 0x%"PRIxS"\n",
1073 p->partial, p->pbytes);
1075 } else {
1076 /* free if we can; else accumulate */
1077 if (NaClRoundHostAllocPage(nbytes) == nbytes) {
1078 NaCl_page_free((void *) sysaddr, nbytes);
1079 } else {
1080 p->partial = sysaddr;
1081 p->pbytes = nbytes;
1084 } else {
1085 uintptr_t user_address = entry->page_num << NACL_PAGESHIFT;
1086 if (NaClRoundAllocPage(user_address) != user_address) {
1087 NaClLog(LOG_FATAL,
1088 ("descriptor backed memory does not start"
1089 " at allocation boundary, addr: 0x%08"PRIxPTR"\n"),
1090 user_address);
1092 if (NaClRoundHostAllocPage(nbytes) != nbytes) {
1093 NaClLog(LOG_FATAL,
1094 ("descriptor backed memory size not allocation granularity:"
1095 " 0x%"PRIxS"\n"),
1096 nbytes);
1098 (*entry->nmop->ndp->vtbl->UnmapUnsafe)(entry->nmop->ndp,
1099 p->effp,
1100 (void *) sysaddr,
1101 nbytes);
1105 void NaClAppFreeAllMemory(struct NaClApp *nap)
1107 struct NaClFreeState state;
1108 struct NaClDescEffectorCleanup eff;
1110 state.nap = nap;
1111 state.effp = (struct NaClDescEffector *) &eff;
1112 state.partial = 0;
1113 state.pbytes = 0;
1115 NaClDescEffectorCleanupCtor(&eff);
1116 NaClVmmapVisit(&nap->mem_map, NaClAppFreeWalker, &state);
1117 (*eff.base.vtbl->Dtor)(&eff.base);