Fix file permissions: set executable bit
[nativeclient.git] / service_runtime / sel_ldr.c
blob5afbe59b2e21d97499b46c733ee07c0f554269d4
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 #if NACL_WINDOWS
71 # include <io.h>
72 #endif
74 int NaClAppCtor(struct NaClApp *nap)
76 NACL_THREAD_CHECK;
78 nap->addr_bits = NACL_MAX_ADDR_BITS;
80 nap->max_data_alloc = NACL_DEFAULT_ALLOC_MAX;
81 nap->stack_size = NACL_DEFAULT_STACK_MAX;
83 nap->mem_start = 0;
84 nap->text_region_bytes = 0;
85 nap->tls_start = 0;
86 nap->tls_size = 0;
87 nap->data_end = 0;
89 nap->entry_pt = 0;
91 if (!DynArrayCtor(&nap->threads, 2)) {
92 goto cleanup_none;
94 if (!DynArrayCtor(&nap->desc_tbl, 2)) {
95 goto cleanup_threads;
97 if (!NaClVmmapCtor(&nap->mem_map)) {
98 goto cleanup_desc_tbl;
101 nap->phdrs = NULL;
102 nap->service_port = NULL;
103 nap->service_address = NULL;
105 if (!NaClMutexCtor(&nap->mu)) {
106 goto cleanup_mem_map;
108 if (!NaClCondVarCtor(&nap->cv)) {
109 goto cleanup_mu;
112 nap->restrict_to_main_thread = 1;
114 if (!NaClSyncQueueCtor(&nap->work_queue)) {
115 goto cleanup_cv;
118 if (!NaClMutexCtor(&nap->threads_mu)) {
119 goto cleanup_work_queue;
121 if (!NaClCondVarCtor(&nap->threads_cv)) {
122 goto cleanup_threads_mu;
124 nap->num_threads = 0;
125 if (!NaClMutexCtor(&nap->desc_mu)) {
126 goto cleanup_threads_cv;
129 nap->running = 0;
130 nap->exit_status = -1;
132 nap->code_seg_sel = 0;
133 nap->data_seg_sel = 0;
135 nap->freeze_thread_ops = 0;
137 return 1;
139 #if 0
140 cleanup_desc_mu:
141 NaClMutexDtor(&nap->desc_mu);
142 #endif
143 cleanup_threads_cv:
144 NaClCondVarDtor(&nap->threads_cv);
145 cleanup_threads_mu:
146 NaClMutexDtor(&nap->threads_mu);
147 cleanup_work_queue:
148 NaClSyncQueueDtor(&nap->work_queue);
149 cleanup_cv:
150 NaClCondVarDtor(&nap->cv);
151 cleanup_mu:
152 NaClMutexDtor(&nap->mu);
153 cleanup_mem_map:
154 NaClVmmapDtor(&nap->mem_map);
155 cleanup_desc_tbl:
156 DynArrayDtor(&nap->desc_tbl);
157 cleanup_threads:
158 DynArrayDtor(&nap->threads);
159 cleanup_none:
160 return 0;
163 void NaClAppDtor(struct NaClApp *nap)
165 int i;
166 struct NaClDesc *ndp;
167 struct NaClAppThread *natp;
169 NaClLog(2,
170 "NaClAppDtor: there are %d threads alive; thread table size %d\n",
171 nap->num_threads,
172 nap->threads.num_entries);
173 for (i = 0; i < nap->threads.num_entries; ++i) {
174 int refcount;
175 enum NaClThreadState state;
177 NaClLog(2, "Checking thread %d\n", i);
178 if (NULL == (natp = NaClGetThreadMu(nap, i))) {
179 continue;
181 NaClLog(2, "Extracting state for thread %d\n", i);
182 NaClXMutexLock(&natp->mu);
183 state = natp->state;
184 NaClLog(2, "state %d\n", state);
185 NaClXMutexUnlock(&natp->mu);
187 NaClRemoveThreadMu(nap, i);
188 refcount = NaClAppThreadDecRef(natp);
190 if (state != NACL_APP_THREAD_DEAD) {
191 NaClLog(LOG_WARNING,
192 ("NaClAppDtor: thread %d still running when NaCl app"
193 " is being destroyed?!?\n"),
196 if (refcount != 0) {
197 NaClLog(LOG_WARNING,
198 ("NaClAppDtor: thread %d refcount not 0 when NaCl app"
199 " is being destroyed?!?\n"),
204 for (i = 0; i < nap->desc_tbl.num_entries; ++i) {
205 ndp = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, i);
206 if (NULL != ndp) {
207 NaClDescUnref(ndp);
211 NaClMutexDtor(&nap->desc_mu);
212 NaClMutexDtor(&nap->threads_mu);
213 NaClCondVarDtor(&nap->threads_cv);
214 NaClSyncQueueDtor(&nap->work_queue);
215 NaClCondVarDtor(&nap->cv);
216 NaClMutexDtor(&nap->mu);
218 NaClAppFreeAllMemory(nap);
220 NaClVmmapDtor(&nap->mem_map);
222 DynArrayDtor(&nap->desc_tbl);
223 DynArrayDtor(&nap->threads);
225 return;
228 size_t NaClAlignPad(size_t val,
229 size_t align)
231 /* align is always a power of 2, but we do not depend on it */
232 if (!align) {
233 NaClLog(0,
234 "sel_ldr: NaClAlignPad, align == 0, at 0x%08x\n",
235 val);
236 return 0;
238 val = val % align;
239 if (!val) return 0;
240 return align - val;
244 * unaligned little-endian load
246 uint32_t NaClLoad32(uintptr_t addr)
248 uint8_t *p = (uint8_t *) addr;
250 return p[0] | (p[1] << 8) | (p[2] << 16) | p[3] << 24;
254 * unaligned little-endian store
256 void NaClStore32(uintptr_t addr,
257 uint32_t v)
259 uint8_t *p = (uint8_t *) addr;
261 p[0] = (uint8_t) (v >> 0);
262 p[1] = (uint8_t) (v >> 8);
263 p[2] = (uint8_t) (v >> 16);
264 p[3] = (uint8_t) (v >> 24);
267 uint16_t NaClLoad16(uintptr_t addr)
269 uint8_t *p = (uint8_t *) addr;
271 return p[0] | (p[1] << 8);
274 void NaClStore16(uintptr_t addr,
275 uint16_t v)
277 uint8_t *p = (uint8_t *) addr;
279 p[0] = (uint8_t) (v >> 0);
280 p[1] = (uint8_t) (v >> 8);
284 * target is an absolute address in the source region. the patch code
285 * will figure out the corresponding address in the destination region
286 * and modify as appropriate. this makes it easier to specify, since
287 * the target is typically the address of some symbol from the source
288 * template.
290 struct NaClPatch {
291 uint32_t target, value;
294 struct NaClPatchInfo {
295 uintptr_t dst;
296 uintptr_t src;
297 size_t nbytes;
298 uintptr_t *rel32;
299 size_t num_rel32;
300 struct NaClPatch *abs32;
301 size_t num_abs32;
302 struct NaClPatch *abs16;
303 size_t num_abs16;
306 void NaClPatchMemory(struct NaClPatchInfo *patch)
308 size_t i;
309 size_t offset;
310 size_t reloc;
311 uintptr_t target_addr;
313 memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
315 reloc = patch->dst - patch->src;
317 for (i = 0; i < patch->num_rel32; ++i) {
318 offset = patch->rel32[i] - patch->src;
319 target_addr = patch->dst + offset;
320 NaClStore32(target_addr, NaClLoad32(target_addr) - reloc);
323 for (i = 0; i < patch->num_abs32; ++i) {
324 offset = patch->abs32[i].target - patch->src;
325 target_addr = patch->dst + offset;
326 NaClStore32(target_addr, patch->abs32[i].value);
329 for (i = 0; i < patch->num_abs16; ++i) {
330 offset = patch->abs16[i].target - patch->src;
331 target_addr = patch->dst + offset;
332 NaClStore16(target_addr, patch->abs16[i].value);
337 * Install a syscall trampoline at target_addr. NB: Thread-safe.
339 void NaClPatchOneTrampoline(struct NaClApp *nap,
340 uintptr_t target_addr)
342 struct NaClPatchInfo patch_info;
344 struct NaClPatch patch16[1];
345 struct NaClPatch patch32[2];
347 patch16[0].target = ((uintptr_t) &NaCl_tramp_cseg_patch) - 2;
348 patch16[0].value = nacl_global_cs;
350 patch_info.abs16 = patch16;
351 patch_info.num_abs16 = sizeof patch16/sizeof patch16[0];
353 patch_info.rel32 = 0;
354 patch_info.num_rel32 = 0;
356 patch32[0].target = ((uintptr_t) &NaCl_tramp_cseg_patch) - 6;
357 patch32[0].value = (uintptr_t) NaClSyscallSeg;
359 patch32[1].target = ((uintptr_t) &NaCl_tramp_dseg_patch) - 4;
360 patch32[1].value = nacl_global_ds; /* opens the data sandbox */
362 patch_info.abs32 = patch32;
363 patch_info.num_abs32 = sizeof patch32/sizeof patch32[0];
365 patch_info.dst = target_addr;
366 patch_info.src = (uintptr_t) &NaCl_trampoline_seg_code;
367 patch_info.nbytes = ((uintptr_t) &NaCl_trampoline_seg_end
368 - (uintptr_t) &NaCl_trampoline_seg_code);
370 NaClPatchMemory(&patch_info);
374 * Install syscall trampolines at all possible well-formed entry
375 * points within the trampoline pages. Many of these syscalls will
376 * correspond to unimplemented system calls and will just abort the
377 * program.
379 void NaClLoadTrampoline(struct NaClApp *nap)
381 int num_syscalls;
382 int i;
383 uintptr_t addr;
385 /* fill trampoline region with HLT */
386 memset((void *) nap->mem_start, NACL_HALT_OPCODE, NACL_TRAMPOLINE_SIZE);
389 * Do not bother to fill in the contents of page 0, since we make it
390 * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
391 * anyway to help detect NULL pointer errors, and we might as well
392 * not dirty the page.
394 * The last syscall entry point is used for springboard code.
396 num_syscalls = ((NACL_TRAMPOLINE_SIZE - NACL_SYSCALL_START_ADDR)
397 / NACL_SYSCALL_BLOCK_SIZE) - 1;
399 NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
401 for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
402 i < num_syscalls;
403 ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
404 NaClPatchOneTrampoline(nap, addr);
409 void NaClLoadSpringboard(struct NaClApp *nap)
412 * patch in springboard.S code into space in place of
413 * the last syscall in the trampoline region.
415 struct NaClPatchInfo patch_info;
416 struct NaClPatch abs32;
418 patch_info.rel32 = 0;
419 patch_info.num_rel32 = 0;
420 patch_info.abs32 = &abs32;
421 patch_info.num_abs32 = 0;
422 patch_info.abs16 = 0;
423 patch_info.num_abs16 = 0;
425 nap->springboard_addr = NACL_TRAMPOLINE_SIZE - nap->align_boundary;
427 patch_info.dst = nap->mem_start + nap->springboard_addr;
428 patch_info.src = (uintptr_t) &NaCl_springboard;
429 patch_info.nbytes = ((uintptr_t) &NaCl_springboard_end
430 - (uintptr_t) &NaCl_springboard);
432 NaClPatchMemory(&patch_info);
434 nap->springboard_addr++; /* skip the hlt */
437 void NaClMemRegionPrinter(void *state,
438 struct NaClVmmapEntry *entry) {
439 struct Gio *gp = (struct Gio *) state;
441 gprintf(gp, "\nPage %d (0x%x)\n", entry->page_num, entry->page_num);
442 gprintf(gp, "npages %d (0x%x)\n", entry->npages, entry->npages);
443 gprintf(gp, "prot 0x%08x\n", entry->prot);
444 gprintf(gp, "%sshared/backed by a file\n",
445 (NULL == entry->nmop) ? "not " : "");
448 void NaClAppPrintDetails(struct NaClApp *nap,
449 struct Gio *gp)
451 gprintf(gp,
452 "NaClAppPrintDetails((struct NaClApp *) 0x%08x,"
453 "(struct Gio *) 0x%08x)\n", (uintptr_t) nap, (uintptr_t) gp);
454 gprintf(gp, "addr space size: 2**%d\n", nap->addr_bits);
455 gprintf(gp, "max data alloc: 0x%08x\n", nap->max_data_alloc);
456 gprintf(gp, "stack size: 0x%08x\n", nap->stack_size);
458 gprintf(gp, "mem start addr: 0x%08x\n", nap->mem_start);
459 /* 123456789012345678901234567890 */
461 gprintf(gp, "text_region_bytes: 0x%08x\n", nap->text_region_bytes);
462 gprintf(gp, "tls_start: 0x%08x\n", nap->tls_start);
463 gprintf(gp, "tls_size: 0x%08x\n", nap->tls_size);
464 gprintf(gp, "data_end: 0x%08x\n", nap->data_end);
465 gprintf(gp, "break_addr: 0x%08x\n", nap->break_addr);
467 gprintf(gp, "ELF entry point: 0x%08x\n", nap->entry_pt);
468 gprintf(gp, "memory map:\n");
469 NaClVmmapVisit(&nap->mem_map,
470 NaClMemRegionPrinter,
471 gp);
474 /* deprecated */
475 char const *NaClAppLoadErrorString(NaClErrorCode errcode) {
476 NaClLog(0, "Deprecated NaClAppLoadErrorString interface used\n");
477 return NaClErrorString(errcode);
480 char const *NaClErrorString(NaClErrorCode errcode)
482 switch (errcode) {
483 case LOAD_OK:
484 return "Ok";
485 case LOAD_INTERNAL:
486 return "Internal error";
487 case LOAD_READ_ERROR:
488 return "Cannot read file";
489 case LOAD_BAD_ELF_MAGIC:
490 return "Bad ELF header magic number";
491 case LOAD_NOT_32_BIT:
492 return "Not a 32-bit ELF file";
493 case LOAD_BAD_ABI:
494 return "ELF file has unexpected OS ABI";
495 case LOAD_NOT_EXEC:
496 return "ELF file type not executable";
497 case LOAD_BAD_MACHINE:
498 return "ELF file for wrong architecture";
499 case LOAD_BAD_ELF_VERS:
500 return "ELF version mismatch";
501 case LOAD_TOO_MANY_SECT:
502 return "Too many section headers";
503 case LOAD_BAD_SECT:
504 return "ELF bad sections";
505 case LOAD_NO_MEMORY:
506 return "Insufficient memory to load file";
507 case LOAD_SECT_HDR:
508 return "ELF section header string table load error";
509 case LOAD_ADDR_SPACE_TOO_SMALL:
510 return "Address space too small";
511 case LOAD_ADDR_SPACE_TOO_BIG:
512 return "Address space too big";
513 case LOAD_DATA_OVERLAPS_STACK_SECTION:
514 return ("Memory \"hole\" between end of BSS and start of stack"
515 " is negative in size");
516 case LOAD_UNLOADABLE:
517 return "Error during loading";
518 case LOAD_BAD_ELF_TEXT:
519 return "ELF file contains no text segment";
520 case LOAD_TEXT_SEG_TOO_BIG:
521 return "ELF file text segment too large";
522 case LOAD_DATA_SEG_TOO_BIG:
523 return "ELF file data segment(s) too large";
524 case LOAD_MPROTECT_FAIL:
525 return "Cannot protect pages";
526 case LOAD_MADVISE_FAIL:
527 return "Cannot release unused data segment";
528 case LOAD_TOO_MANY_SYMBOL_STR:
529 return "Malformed ELF file: too many string tables";
530 case LOAD_SYMTAB_ENTRY_TOO_SMALL:
531 return "Symbol table entry too small";
532 case LOAD_NO_SYMTAB:
533 return "No symbol table";
534 case LOAD_NO_SYMTAB_STRINGS:
535 return "No string table for symbols";
536 case LOAD_SYMTAB_ENTRY:
537 return "Error entering new symbol into symbol table";
538 case LOAD_UNKNOWN_SYMBOL_TYPE:
539 return "Unknown symbol type";
540 case LOAD_SYMTAB_DUP:
541 return "Duplicate entry in symbol table";
542 case LOAD_REL_ERROR:
543 return "Bad relocation read error";
544 case LOAD_REL_UNIMPL:
545 return "Relocation type unimplemented";
546 case LOAD_UNDEF_SYMBOL:
547 return "Undefined external symbol";
548 case LOAD_BAD_SYMBOL_DATA:
549 return "Bad symbol table data";
550 case LOAD_BAD_FILE:
551 return "ELF file not accessible";
552 case LOAD_BAD_ENTRY:
553 return "Bad symbol table entry: not a text symbol/entry point";
554 case LOAD_SEGMENT_OUTSIDE_ADDRSPACE:
555 return ("ELF executable contains a segment which lies outside"
556 " the assigned address space");
557 case LOAD_DUP_SEGMENT:
558 return ("ELF executable contains a duplicate segment"
559 " (please run objdump to see which)");
560 case LOAD_SEGMENT_BAD_LOC:
561 return "ELF executable text/rodata segment has wrong starting address";
562 case LOAD_BAD_SEGMENT:
563 return "ELF executable contains an unexpected/unallowed segment/flags";
564 case LOAD_REQUIRED_SEG_MISSING:
565 return "ELF executable missing a required segment (text)";
566 case LOAD_SEGMENT_BAD_PARAM:
567 return "ELF executable segment header parameter error";
569 * TODO: need to split rpc return types from other returns or...
571 #if 0
572 case RPC_OK:
573 return "RPC returned OK";
574 case RPC_INTERNAL:
575 return "Internal error in RPC code";
576 case RPC_BAD_SERVICE_DISCOVERY:
577 return "Bad RPC service discovery RPC call";
578 case RPC_BAD_RPC_NUMBER:
579 return "Bad RPC number";
580 case RPC_IN_ARG_TYPE_MISMATCH:
581 return "Input argument type mismatch";
582 case RPC_OUT_ARG_TYPE_MISMATCH:
583 return "Output argument type mismatch";
584 case RPC_NO_MEMORY:
585 return "Out of memory for RPC arglist";
586 case RPC_APP_ERROR:
587 return "RPC application-level error";
588 case RPC_STRING_OUTPUT:
589 return "RPC cannot have C string as output";
590 #endif
591 case SRT_NO_SEG_SEL:
592 return "Service Runtime: cannot allocate segment selector";
596 * do not use default case label, to make sure that the compiler
597 * will generate a warning with -Wswitch-enum for new codes
598 * introduced in nacl_error_codes.h for which there is no
599 * corresponding entry here. instead, we pretend that fall-through
600 * from the switch is possible. (otherwise -W complains control
601 * reaches end of non-void function.)
603 return "BAD ERROR CODE";
606 struct NaClDesc *NaClGetDescMu(struct NaClApp *nap,
607 int d)
609 struct NaClDesc *result;
611 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
612 if (NULL != result) {
613 NaClDescRef(result);
616 return result;
619 void NaClSetDescMu(struct NaClApp *nap,
620 int d,
621 struct NaClDesc *ndp)
623 struct NaClDesc *result;
625 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
626 if (NULL != result) {
627 NaClDescUnref(result);
629 if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
630 NaClLog(LOG_FATAL,
631 "NaClSetDesc: could not set descriptor %d to 0x%08x\n",
633 (uintptr_t) ndp);
637 int NaClSetAvailMu(struct NaClApp *nap,
638 struct NaClDesc *ndp)
640 int pos;
642 pos = DynArrayFirstAvail(&nap->desc_tbl);
643 if (pos < 0) {
644 NaClLog(LOG_FATAL,
645 ("NaClSetAvailMu: DynArrayFirstAvail returned a negative"
646 " number as first available position\n"));
648 NaClSetDescMu(nap, pos, ndp);
650 return pos;
653 struct NaClDesc *NaClGetDesc(struct NaClApp *nap,
654 int d)
656 struct NaClDesc *res;
658 NaClXMutexLock(&nap->desc_mu);
659 res = NaClGetDescMu(nap, d);
660 NaClXMutexUnlock(&nap->desc_mu);
661 return res;
664 void NaClSetDesc(struct NaClApp *nap,
665 int d,
666 struct NaClDesc *ndp)
668 NaClXMutexLock(&nap->desc_mu);
669 NaClSetDescMu(nap, d, ndp);
670 NaClXMutexUnlock(&nap->desc_mu);
673 int NaClSetAvail(struct NaClApp *nap,
674 struct NaClDesc *ndp)
676 int pos;
678 NaClXMutexLock(&nap->desc_mu);
679 pos = NaClSetAvailMu(nap, ndp);
680 NaClXMutexUnlock(&nap->desc_mu);
682 return pos;
685 int NaClAddThreadMu(struct NaClApp *nap,
686 struct NaClAppThread *natp)
688 int pos;
690 pos = DynArrayFirstAvail(&nap->threads);
691 if (pos < 0) {
692 NaClLog(LOG_FATAL,
693 ("NaClAddThreadMu: DynArrayFirstAvail returned a negative"
694 " number as first available position\n"));
696 if (!DynArraySet(&nap->threads, pos, natp)) {
697 NaClLog(LOG_FATAL,
698 "NaClAddThreadMu: DynArraySet at position %d failed\n",
699 pos);
701 ++nap->num_threads;
702 return pos;
705 int NaClAddThread(struct NaClApp *nap,
706 struct NaClAppThread *natp)
708 int pos;
710 NaClXMutexLock(&nap->threads_mu);
711 pos = NaClAddThreadMu(nap, natp);
712 NaClXMutexUnlock(&nap->threads_mu);
714 return pos;
718 * Assumes thread_num is valid.
720 void NaClRemoveThreadMu(struct NaClApp *nap,
721 int thread_num)
723 --nap->num_threads;
724 if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
725 NaClLog(LOG_FATAL,
726 "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
727 thread_num);
731 void NaClRemoveThread(struct NaClApp *nap,
732 int thread_num)
734 NaClXMutexLock(&nap->threads_mu);
735 NaClRemoveThreadMu(nap, thread_num);
736 NaClXCondVarBroadcast(&nap->threads_cv);
737 NaClXMutexUnlock(&nap->threads_mu);
740 struct NaClAppThread *NaClGetThreadMu(struct NaClApp *nap,
741 int thread_num)
743 return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
746 void NaClAddHostDescriptor(struct NaClApp *nap,
747 int host_os_desc,
748 int mode,
749 int nacl_desc)
751 struct NaClDescIoDesc *dp;
753 dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, mode));
754 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
757 void NaClAddImcHandle(struct NaClApp *nap,
758 NaClHandle h,
759 int nacl_desc)
761 struct NaClDescImcDesc *dp;
763 dp = malloc(sizeof *dp);
764 if (NULL == dp) {
765 NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
767 if (!NaClDescImcDescCtor(dp, h)) {
768 NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
769 " IMC descriptor object\n"));
771 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
774 void NaClAddImcAddr(struct NaClApp *nap,
775 struct NaClSocketAddress const *addr,
776 int nacl_desc)
778 struct NaClDescConnCap *dp;
780 dp = malloc(sizeof *dp);
781 if (NULL == dp) {
782 NaClLog(LOG_FATAL, "NaClAddImcAddr: no memory\n");
784 if (!NaClDescConnCapCtor(dp, addr)) {
785 NaClLog(LOG_FATAL, ("NaClAddImcAddr: canot construct"
786 " connection capability object\n"));
788 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
791 void NaClAppVmmapUpdate(struct NaClApp *nap,
792 uintptr_t page_num,
793 size_t npages,
794 int prot,
795 struct NaClMemObj *nmop,
796 int remove)
798 NaClXMutexLock(&nap->mu);
799 NaClVmmapUpdate(&nap->mem_map,
800 page_num,
801 npages,
802 prot,
803 nmop,
804 remove);
805 NaClXMutexUnlock(&nap->mu);
808 uintptr_t NaClAppVmmapFindSpace(struct NaClApp *nap,
809 int num_pages)
811 int rv;
813 NaClXMutexLock(&nap->mu);
814 rv = NaClVmmapFindSpace(&nap->mem_map,
815 num_pages);
816 NaClXMutexUnlock(&nap->mu);
817 return rv;
820 uintptr_t NaClAppVmmapFindMapSpace(struct NaClApp *nap,
821 int num_pages)
823 int rv;
825 NaClXMutexLock(&nap->mu);
826 rv = NaClVmmapFindMapSpace(&nap->mem_map,
827 num_pages);
828 NaClXMutexUnlock(&nap->mu);
829 return rv;
832 void NaClCreateServiceSocket(struct NaClApp *nap)
834 struct NaClDesc *pair[2];
836 NaClLog(3, "Entered NaClCreateServiceSocket\n");
837 NaClCommonDescMakeBoundSock(pair);
838 NaClLog(4,
839 "got bound socket at 0x%08x, addr at 0x%08x\n",
840 (uintptr_t) pair[0],
841 (uintptr_t) pair[1]);
842 NaClSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
843 NaClSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
844 if (NULL != nap->service_port) {
845 NaClDescUnref(nap->service_port);
847 nap->service_port = pair[0];
848 NaClDescRef(nap->service_port);
849 if (NULL != nap->service_address) {
850 NaClDescUnref(nap->service_address);
852 nap->service_address = pair[1];
853 NaClDescRef(nap->service_address);
854 NaClLog(4, "Leaving NaClCreateServiceSocket\n");
857 void NaClSendServiceAddressTo(struct NaClApp *nap,
858 int desc)
860 struct NaClDesc *channel;
861 struct NaClImcTypedMsgHdr hdr;
862 int rv;
864 struct NaClNrdXferEffector nnxep;
866 NaClLog(4,
867 "NaClSendServiceAddressTo(0x%08x, %d)\n",
868 (uintptr_t) nap,
869 desc);
871 channel = NaClGetDesc(nap, desc);
872 if (NULL == channel) {
873 NaClLog(LOG_FATAL,
874 "NaClSendServiceAddressTo: descriptor %d not in open file table\n",
875 desc);
876 /* NOTREACHED */
877 return;
879 if (NULL == nap->service_address) {
880 NaClLog(LOG_FATAL,
881 "NaClSendServiceAddressTo: service address not set\n");
882 /* NOTREACHED */
883 return;
886 * service_address and service_port are set together.
888 (void) NaClNrdXferEffectorCtor(&nnxep, nap->service_port);
890 hdr.iov = (struct NaClImcMsgIoVec *) NULL;
891 hdr.iov_length = 0;
892 hdr.ndescv = &nap->service_address;
893 hdr.ndesc_length = 1;
895 rv = NaClImcSendTypedMessage(channel,
896 (struct NaClDescEffector *) &nnxep,
897 &hdr, 0);
899 NaClDescUnref(channel);
900 channel = NULL;
902 (*nnxep.base.vtbl->Dtor)((struct NaClDescEffector *) &nnxep);
904 NaClLog(1,
905 "NaClSendServiceAddressTo: descriptor %d, error %d\n",
906 desc,
907 rv);
910 void NaClDumpServiceAddressTo(struct NaClApp *nap,
911 int desc)
913 NaClLog(4,
914 "NaClDumpServiceAddressTo(0x%08x, %d)\n",
915 (uintptr_t) nap,
916 desc);
917 if (NULL == nap->service_address) {
918 NaClLog(LOG_FATAL,
919 "NaClDumpServiceAddressTo: service address not set\n");
920 /* NOTREACHED */
921 return;
923 if (sizeof ((struct NaClDescConnCap *) nap->service_address)->cap.path
924 != write(desc,
925 ((struct NaClDescConnCap *) nap->service_address)->cap.path,
926 sizeof
927 ((struct NaClDescConnCap *) nap->service_address)->cap.path)) {
928 NaClLog(LOG_FATAL,
929 "NaClDumpServiceAddressTo: could not send service address\n");
933 struct NaClFreeState {
934 struct NaClApp *nap;
935 struct NaClDescEffector *effp;
936 uintptr_t partial;
937 size_t pbytes;
940 static void NaClAppFreeWalker(void *state,
941 struct NaClVmmapEntry *entry)
943 struct NaClFreeState *p = (struct NaClFreeState *) state;
944 uintptr_t sysaddr;
945 size_t nbytes;
947 NaClLog(3, "NaClAppFreeWalker: p->partial = 0x%08x, p->pbytes = 0x%08x\n",
948 p->partial, p->pbytes);
949 NaClLog(3,
950 (" entry->page_num = 0x%x, entry->npages = 0x%x,"
951 " entry->nmop = 0x%08x\n"),
952 entry->page_num, entry->npages, entry->nmop);
953 sysaddr = NaClUserToSysAddrNullOkay(p->nap,
954 entry->page_num << NACL_PAGESHIFT);
955 nbytes = entry->npages << NACL_PAGESHIFT;
956 if (NULL == entry->nmop) {
957 if (0 != p->pbytes) {
958 /* partial exists, accumulate and try to free */
959 if (p->partial + p->pbytes != sysaddr) {
960 NaClLog(LOG_FATAL,
961 ("Partial allocation pages not contiguous?!?"
962 " Partial start 0x%08x, length 0x%x; next start 0x%08x\n"),
963 p->partial, p->pbytes, sysaddr);
965 p->pbytes += nbytes;
966 if (NaClRoundHostAllocPage(p->pbytes) == p->pbytes) {
967 NaCl_page_free((void *) p->partial, p->pbytes);
968 p->partial = 0;
969 p->pbytes = 0;
970 } else {
971 NaClLog(3, "Partial accummulated 0x%08x, 0x%x\n",
972 p->partial, p->pbytes);
974 } else {
975 /* free if we can; else accumulate */
976 if (NaClRoundHostAllocPage(nbytes) == nbytes) {
977 NaCl_page_free((void *) sysaddr, nbytes);
978 } else {
979 p->partial = sysaddr;
980 p->pbytes = nbytes;
983 } else {
984 uintptr_t user_address = entry->page_num << NACL_PAGESHIFT;
985 if (NaClRoundAllocPage(user_address) != user_address) {
986 NaClLog(LOG_FATAL,
987 ("descriptor backed memory does not start"
988 " at allocation boundary, addr: 0x%08x\n"),
989 user_address);
991 if (NaClRoundHostAllocPage(nbytes) != nbytes) {
992 NaClLog(LOG_FATAL,
993 ("descriptor backed memory size not allocation granularity:"
994 " 0x%x\n"),
995 nbytes);
997 (*entry->nmop->ndp->vtbl->UnmapUnsafe)(entry->nmop->ndp,
998 p->effp,
999 (void *) sysaddr,
1000 nbytes);
1004 void NaClAppFreeAllMemory(struct NaClApp *nap)
1006 struct NaClFreeState state;
1007 struct NaClDescEffectorCleanup eff;
1009 state.nap = nap;
1010 state.effp = (struct NaClDescEffector *) &eff;
1011 state.partial = 0;
1012 state.pbytes = 0;
1014 NaClDescEffectorCleanupCtor(&eff);
1015 NaClVmmapVisit(&nap->mem_map, NaClAppFreeWalker, &state);
1016 (*eff.base.vtbl->Dtor)(&eff.base);