2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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).
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"
74 int NaClAppCtor(struct NaClApp
*nap
)
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
;
84 nap
->text_region_bytes
= 0;
91 if (!DynArrayCtor(&nap
->threads
, 2)) {
94 if (!DynArrayCtor(&nap
->desc_tbl
, 2)) {
97 if (!NaClVmmapCtor(&nap
->mem_map
)) {
98 goto cleanup_desc_tbl
;
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
)) {
112 nap
->restrict_to_main_thread
= 1;
114 if (!NaClSyncQueueCtor(&nap
->work_queue
)) {
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
;
130 nap
->exit_status
= -1;
132 nap
->code_seg_sel
= 0;
133 nap
->data_seg_sel
= 0;
135 nap
->freeze_thread_ops
= 0;
141 NaClMutexDtor(&nap
->desc_mu
);
144 NaClCondVarDtor(&nap
->threads_cv
);
146 NaClMutexDtor(&nap
->threads_mu
);
148 NaClSyncQueueDtor(&nap
->work_queue
);
150 NaClCondVarDtor(&nap
->cv
);
152 NaClMutexDtor(&nap
->mu
);
154 NaClVmmapDtor(&nap
->mem_map
);
156 DynArrayDtor(&nap
->desc_tbl
);
158 DynArrayDtor(&nap
->threads
);
163 void NaClAppDtor(struct NaClApp
*nap
)
166 struct NaClDesc
*ndp
;
167 struct NaClAppThread
*natp
;
170 "NaClAppDtor: there are %d threads alive; thread table size %d\n",
172 nap
->threads
.num_entries
);
173 for (i
= 0; i
< nap
->threads
.num_entries
; ++i
) {
175 enum NaClThreadState state
;
177 NaClLog(2, "Checking thread %d\n", i
);
178 if (NULL
== (natp
= NaClGetThreadMu(nap
, i
))) {
181 NaClLog(2, "Extracting state for thread %d\n", i
);
182 NaClXMutexLock(&natp
->mu
);
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
) {
192 ("NaClAppDtor: thread %d still running when NaCl app"
193 " is being destroyed?!?\n"),
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
);
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
);
228 size_t NaClAlignPad(size_t val
,
231 /* align is always a power of 2, but we do not depend on it */
234 "sel_ldr: NaClAlignPad, align == 0, at 0x%08x\n",
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
,
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
,
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
291 uint32_t target
, value
;
294 struct NaClPatchInfo
{
300 struct NaClPatch
*abs32
;
302 struct NaClPatch
*abs16
;
306 void NaClPatchMemory(struct NaClPatchInfo
*patch
)
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
379 void NaClLoadTrampoline(struct NaClApp
*nap
)
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
;
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
,
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
,
475 char const *NaClAppLoadErrorString(NaClErrorCode errcode
) {
476 NaClLog(0, "Deprecated NaClAppLoadErrorString interface used\n");
477 return NaClErrorString(errcode
);
480 char const *NaClErrorString(NaClErrorCode errcode
)
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";
494 return "ELF file has unexpected OS ABI";
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";
504 return "ELF bad sections";
506 return "Insufficient memory to load file";
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";
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";
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";
551 return "ELF file not accessible";
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...
573 return "RPC returned OK";
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";
585 return "Out of memory for RPC arglist";
587 return "RPC application-level error";
588 case RPC_STRING_OUTPUT
:
589 return "RPC cannot have C string as output";
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
,
609 struct NaClDesc
*result
;
611 result
= (struct NaClDesc
*) DynArrayGet(&nap
->desc_tbl
, d
);
612 if (NULL
!= result
) {
619 void NaClSetDescMu(struct NaClApp
*nap
,
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
)) {
631 "NaClSetDesc: could not set descriptor %d to 0x%08x\n",
637 int NaClSetAvailMu(struct NaClApp
*nap
,
638 struct NaClDesc
*ndp
)
642 pos
= DynArrayFirstAvail(&nap
->desc_tbl
);
645 ("NaClSetAvailMu: DynArrayFirstAvail returned a negative"
646 " number as first available position\n"));
648 NaClSetDescMu(nap
, pos
, ndp
);
653 struct NaClDesc
*NaClGetDesc(struct NaClApp
*nap
,
656 struct NaClDesc
*res
;
658 NaClXMutexLock(&nap
->desc_mu
);
659 res
= NaClGetDescMu(nap
, d
);
660 NaClXMutexUnlock(&nap
->desc_mu
);
664 void NaClSetDesc(struct NaClApp
*nap
,
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
)
678 NaClXMutexLock(&nap
->desc_mu
);
679 pos
= NaClSetAvailMu(nap
, ndp
);
680 NaClXMutexUnlock(&nap
->desc_mu
);
685 int NaClAddThreadMu(struct NaClApp
*nap
,
686 struct NaClAppThread
*natp
)
690 pos
= DynArrayFirstAvail(&nap
->threads
);
693 ("NaClAddThreadMu: DynArrayFirstAvail returned a negative"
694 " number as first available position\n"));
696 if (!DynArraySet(&nap
->threads
, pos
, natp
)) {
698 "NaClAddThreadMu: DynArraySet at position %d failed\n",
705 int NaClAddThread(struct NaClApp
*nap
,
706 struct NaClAppThread
*natp
)
710 NaClXMutexLock(&nap
->threads_mu
);
711 pos
= NaClAddThreadMu(nap
, natp
);
712 NaClXMutexUnlock(&nap
->threads_mu
);
718 * Assumes thread_num is valid.
720 void NaClRemoveThreadMu(struct NaClApp
*nap
,
724 if (!DynArraySet(&nap
->threads
, thread_num
, (struct NaClAppThread
*) NULL
)) {
726 "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
731 void NaClRemoveThread(struct NaClApp
*nap
,
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
,
743 return (struct NaClAppThread
*) DynArrayGet(&nap
->threads
, thread_num
);
746 void NaClAddHostDescriptor(struct NaClApp
*nap
,
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
,
761 struct NaClDescImcDesc
*dp
;
763 dp
= malloc(sizeof *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
,
778 struct NaClDescConnCap
*dp
;
780 dp
= malloc(sizeof *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
,
795 struct NaClMemObj
*nmop
,
798 NaClXMutexLock(&nap
->mu
);
799 NaClVmmapUpdate(&nap
->mem_map
,
805 NaClXMutexUnlock(&nap
->mu
);
808 uintptr_t NaClAppVmmapFindSpace(struct NaClApp
*nap
,
813 NaClXMutexLock(&nap
->mu
);
814 rv
= NaClVmmapFindSpace(&nap
->mem_map
,
816 NaClXMutexUnlock(&nap
->mu
);
820 uintptr_t NaClAppVmmapFindMapSpace(struct NaClApp
*nap
,
825 NaClXMutexLock(&nap
->mu
);
826 rv
= NaClVmmapFindMapSpace(&nap
->mem_map
,
828 NaClXMutexUnlock(&nap
->mu
);
832 void NaClCreateServiceSocket(struct NaClApp
*nap
)
834 struct NaClDesc
*pair
[2];
836 NaClLog(3, "Entered NaClCreateServiceSocket\n");
837 NaClCommonDescMakeBoundSock(pair
);
839 "got bound socket at 0x%08x, addr at 0x%08x\n",
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
,
860 struct NaClDesc
*channel
;
861 struct NaClImcTypedMsgHdr hdr
;
864 struct NaClNrdXferEffector nnxep
;
867 "NaClSendServiceAddressTo(0x%08x, %d)\n",
871 channel
= NaClGetDesc(nap
, desc
);
872 if (NULL
== channel
) {
874 "NaClSendServiceAddressTo: descriptor %d not in open file table\n",
879 if (NULL
== nap
->service_address
) {
881 "NaClSendServiceAddressTo: service address not set\n");
886 * service_address and service_port are set together.
888 (void) NaClNrdXferEffectorCtor(&nnxep
, nap
->service_port
);
890 hdr
.iov
= (struct NaClImcMsgIoVec
*) NULL
;
892 hdr
.ndescv
= &nap
->service_address
;
893 hdr
.ndesc_length
= 1;
895 rv
= NaClImcSendTypedMessage(channel
,
896 (struct NaClDescEffector
*) &nnxep
,
899 NaClDescUnref(channel
);
902 (*nnxep
.base
.vtbl
->Dtor
)((struct NaClDescEffector
*) &nnxep
);
905 "NaClSendServiceAddressTo: descriptor %d, error %d\n",
910 void NaClDumpServiceAddressTo(struct NaClApp
*nap
,
914 "NaClDumpServiceAddressTo(0x%08x, %d)\n",
917 if (NULL
== nap
->service_address
) {
919 "NaClDumpServiceAddressTo: service address not set\n");
923 if (sizeof ((struct NaClDescConnCap
*) nap
->service_address
)->cap
.path
925 ((struct NaClDescConnCap
*) nap
->service_address
)->cap
.path
,
927 ((struct NaClDescConnCap
*) nap
->service_address
)->cap
.path
)) {
929 "NaClDumpServiceAddressTo: could not send service address\n");
933 struct NaClFreeState
{
935 struct NaClDescEffector
*effp
;
940 static void NaClAppFreeWalker(void *state
,
941 struct NaClVmmapEntry
*entry
)
943 struct NaClFreeState
*p
= (struct NaClFreeState
*) state
;
947 NaClLog(3, "NaClAppFreeWalker: p->partial = 0x%08x, p->pbytes = 0x%08x\n",
948 p
->partial
, p
->pbytes
);
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
) {
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
);
966 if (NaClRoundHostAllocPage(p
->pbytes
) == p
->pbytes
) {
967 NaCl_page_free((void *) p
->partial
, p
->pbytes
);
971 NaClLog(3, "Partial accummulated 0x%08x, 0x%x\n",
972 p
->partial
, p
->pbytes
);
975 /* free if we can; else accumulate */
976 if (NaClRoundHostAllocPage(nbytes
) == nbytes
) {
977 NaCl_page_free((void *) sysaddr
, nbytes
);
979 p
->partial
= sysaddr
;
984 uintptr_t user_address
= entry
->page_num
<< NACL_PAGESHIFT
;
985 if (NaClRoundAllocPage(user_address
) != user_address
) {
987 ("descriptor backed memory does not start"
988 " at allocation boundary, addr: 0x%08x\n"),
991 if (NaClRoundHostAllocPage(nbytes
) != nbytes
) {
993 ("descriptor backed memory size not allocation granularity:"
997 (*entry
->nmop
->ndp
->vtbl
->UnmapUnsafe
)(entry
->nmop
->ndp
,
1004 void NaClAppFreeAllMemory(struct NaClApp
*nap
)
1006 struct NaClFreeState state
;
1007 struct NaClDescEffectorCleanup eff
;
1010 state
.effp
= (struct NaClDescEffector
*) &eff
;
1014 NaClDescEffectorCleanupCtor(&eff
);
1015 NaClVmmapVisit(&nap
->mem_map
, NaClAppFreeWalker
, &state
);
1016 (*eff
.base
.vtbl
->Dtor
)(&eff
.base
);