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"
70 #include "native_client/tools/libsrpc/nacl_srpc.h"
76 int NaClAppCtor(struct NaClApp
*nap
)
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;
92 if (!DynArrayCtor(&nap
->threads
, 2)) {
95 if (!DynArrayCtor(&nap
->desc_tbl
, 2)) {
98 if (!NaClVmmapCtor(&nap
->mem_map
)) {
99 goto cleanup_desc_tbl
;
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
)) {
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
)) {
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
;
136 nap
->exit_status
= -1;
138 nap
->code_seg_sel
= 0;
139 nap
->data_seg_sel
= 0;
141 nap
->freeze_thread_ops
= 0;
147 NaClMutexDtor(&nap
->desc_mu
);
150 NaClCondVarDtor(&nap
->threads_cv
);
152 NaClMutexDtor(&nap
->threads_mu
);
154 NaClSyncQueueDtor(&nap
->work_queue
);
156 NaClCondVarDtor(&nap
->cv
);
158 NaClMutexDtor(&nap
->mu
);
160 NaClVmmapDtor(&nap
->mem_map
);
162 DynArrayDtor(&nap
->desc_tbl
);
164 DynArrayDtor(&nap
->threads
);
169 void NaClAppDtor(struct NaClApp
*nap
)
172 struct NaClDesc
*ndp
;
173 struct NaClAppThread
*natp
;
176 "NaClAppDtor: there are %d threads alive; thread table size %d\n",
178 nap
->threads
.num_entries
);
179 for (i
= 0; i
< nap
->threads
.num_entries
; ++i
) {
181 enum NaClThreadState state
;
183 NaClLog(2, "Checking thread %d\n", i
);
184 if (NULL
== (natp
= NaClGetThreadMu(nap
, i
))) {
187 NaClLog(2, "Extracting state for thread %d\n", i
);
188 NaClXMutexLock(&natp
->mu
);
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
) {
198 ("NaClAppDtor: thread %d still running when NaCl app"
199 " is being destroyed?!?\n"),
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
);
217 NaClMutexDtor(&nap
->desc_mu
);
218 NaClMutexDtor(&nap
->threads_mu
);
219 NaClCondVarDtor(&nap
->threads_cv
);
220 NaClSyncQueueDtor(&nap
->work_queue
);
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
);
236 size_t NaClAlignPad(size_t val
,
239 /* align is always a power of 2, but we do not depend on it */
242 "sel_ldr: NaClAlignPad, align == 0, at 0x%08"PRIxS
"\n",
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
,
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
,
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
299 uint32_t target
, value
;
302 struct NaClPatchInfo
{
308 struct NaClPatch
*abs32
;
310 struct NaClPatch
*abs16
;
314 void NaClPatchMemory(struct NaClPatchInfo
*patch
)
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
387 void NaClLoadTrampoline(struct NaClApp
*nap
)
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
;
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
,
459 NaClXMutexLock(&nap
->mu
);
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
,
480 NaClXMutexUnlock(&nap
->mu
);
484 char const *NaClAppLoadErrorString(NaClErrorCode errcode
) {
485 NaClLog(0, "Deprecated NaClAppLoadErrorString interface used\n");
486 return NaClErrorString(errcode
);
489 char const *NaClErrorString(NaClErrorCode errcode
)
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";
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";
507 return "ELF file has unexpected OS ABI";
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";
517 return "ELF bad sections";
519 return "Insufficient memory to load file";
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";
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";
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";
564 return "ELF file not accessible";
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";
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
,
599 struct NaClDesc
*result
;
601 result
= (struct NaClDesc
*) DynArrayGet(&nap
->desc_tbl
, d
);
602 if (NULL
!= result
) {
609 void NaClSetDescMu(struct NaClApp
*nap
,
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
)) {
621 "NaClSetDesc: could not set descriptor %d to 0x%08"PRIxPTR
"\n",
627 int NaClSetAvailMu(struct NaClApp
*nap
,
628 struct NaClDesc
*ndp
)
632 pos
= DynArrayFirstAvail(&nap
->desc_tbl
);
635 ("NaClSetAvailMu: DynArrayFirstAvail returned a negative"
636 " number as first available position\n"));
638 NaClSetDescMu(nap
, pos
, ndp
);
643 struct NaClDesc
*NaClGetDesc(struct NaClApp
*nap
,
646 struct NaClDesc
*res
;
648 NaClXMutexLock(&nap
->desc_mu
);
649 res
= NaClGetDescMu(nap
, d
);
650 NaClXMutexUnlock(&nap
->desc_mu
);
654 void NaClSetDesc(struct NaClApp
*nap
,
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
)
668 NaClXMutexLock(&nap
->desc_mu
);
669 pos
= NaClSetAvailMu(nap
, ndp
);
670 NaClXMutexUnlock(&nap
->desc_mu
);
675 int NaClAddThreadMu(struct NaClApp
*nap
,
676 struct NaClAppThread
*natp
)
680 pos
= DynArrayFirstAvail(&nap
->threads
);
683 ("NaClAddThreadMu: DynArrayFirstAvail returned a negative"
684 " number as first available position\n"));
686 if (!DynArraySet(&nap
->threads
, pos
, natp
)) {
688 "NaClAddThreadMu: DynArraySet at position %d failed\n",
695 int NaClAddThread(struct NaClApp
*nap
,
696 struct NaClAppThread
*natp
)
700 NaClXMutexLock(&nap
->threads_mu
);
701 pos
= NaClAddThreadMu(nap
, natp
);
702 NaClXMutexUnlock(&nap
->threads_mu
);
708 * Assumes thread_num is valid.
710 void NaClRemoveThreadMu(struct NaClApp
*nap
,
714 if (!DynArraySet(&nap
->threads
, thread_num
, (struct NaClAppThread
*) NULL
)) {
716 "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
721 void NaClRemoveThread(struct NaClApp
*nap
,
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
,
733 return (struct NaClAppThread
*) DynArrayGet(&nap
->threads
, thread_num
);
736 void NaClAddHostDescriptor(struct NaClApp
*nap
,
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
,
751 struct NaClDescImcDesc
*dp
;
753 dp
= malloc(sizeof *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
,
768 struct NaClDescConnCap
*dp
;
770 dp
= malloc(sizeof *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
,
785 struct NaClMemObj
*nmop
,
788 NaClXMutexLock(&nap
->mu
);
789 NaClVmmapUpdate(&nap
->mem_map
,
795 NaClXMutexUnlock(&nap
->mu
);
798 uintptr_t NaClAppVmmapFindSpace(struct NaClApp
*nap
,
803 NaClXMutexLock(&nap
->mu
);
804 rv
= NaClVmmapFindSpace(&nap
->mem_map
,
806 NaClXMutexUnlock(&nap
->mu
);
810 uintptr_t NaClAppVmmapFindMapSpace(struct NaClApp
*nap
,
815 NaClXMutexLock(&nap
->mu
);
816 rv
= NaClVmmapFindMapSpace(&nap
->mem_map
,
818 NaClXMutexUnlock(&nap
->mu
);
822 void NaClCreateServiceSocket(struct NaClApp
*nap
)
824 struct NaClDesc
*pair
[2];
826 NaClLog(3, "Entered NaClCreateServiceSocket\n");
827 NaClCommonDescMakeBoundSock(pair
);
829 "got bound socket at 0x%08"PRIxPTR
", addr at 0x%08"PRIxPTR
"\n",
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
,
850 struct NaClDesc
*channel
;
851 struct NaClImcTypedMsgHdr hdr
;
854 struct NaClNrdXferEffector nnxep
;
857 "NaClSendServiceAddressTo(0x%08"PRIxPTR
", %d)\n",
861 channel
= NaClGetDesc(nap
, desc
);
862 if (NULL
== channel
) {
864 "NaClSendServiceAddressTo: descriptor %d not in open file table\n",
869 if (NULL
== nap
->service_address
) {
871 "NaClSendServiceAddressTo: service address not set\n");
876 * service_address and service_port are set together.
878 (void) NaClNrdXferEffectorCtor(&nnxep
, nap
->service_port
);
880 hdr
.iov
= (struct NaClImcMsgIoVec
*) NULL
;
882 hdr
.ndescv
= &nap
->service_address
;
883 hdr
.ndesc_length
= 1;
885 rv
= NaClImcSendTypedMessage(channel
,
886 (struct NaClDescEffector
*) &nnxep
,
889 NaClDescUnref(channel
);
892 (*nnxep
.base
.vtbl
->Dtor
)((struct NaClDescEffector
*) &nnxep
);
895 "NaClSendServiceAddressTo: descriptor %d, error %d\n",
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");
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
;
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
,
974 NaClLog(LOG_INFO
, "NaClSecureChannelThread: channel closed, exiting.\n");
978 void NaClSecureCommandChannel(struct NaClApp
*nap
)
980 struct NaClNrdXferEffector nnxep
;
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
)
990 (struct NaClDescEffector
*) &nnxep
));
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
,
1004 NACL_KERN_STACK_SIZE
);
1005 NaClLog(LOG_INFO
, "NaClSecureCommandChannel: thread spawned, continuing\n");
1008 void NaClDumpServiceAddressTo(struct NaClApp
*nap
,
1012 "NaClDumpServiceAddressTo(0x%08"PRIxPTR
", %d)\n",
1015 if (NULL
== nap
->service_address
) {
1017 "NaClDumpServiceAddressTo: service address not set\n");
1021 if (sizeof ((struct NaClDescConnCap
*) nap
->service_address
)->cap
.path
1023 ((struct NaClDescConnCap
*) nap
->service_address
)->cap
.path
,
1025 ((struct NaClDescConnCap
*) nap
->service_address
)->cap
.path
)) {
1027 "NaClDumpServiceAddressTo: could not send service address\n");
1031 struct NaClFreeState
{
1032 struct NaClApp
*nap
;
1033 struct NaClDescEffector
*effp
;
1038 static void NaClAppFreeWalker(void *state
,
1039 struct NaClVmmapEntry
*entry
)
1041 struct NaClFreeState
*p
= (struct NaClFreeState
*) state
;
1046 ("NaClAppFreeWalker: p->partial = 0x%08"PRIxPTR
","
1047 " p->pbytes = 0x%08"PRIxS
"\n"),
1048 p
->partial
, p
->pbytes
);
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
) {
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
);
1072 NaClLog(3, "Partial accummulated 0x%08"PRIxPTR
", 0x%"PRIxS
"\n",
1073 p
->partial
, p
->pbytes
);
1076 /* free if we can; else accumulate */
1077 if (NaClRoundHostAllocPage(nbytes
) == nbytes
) {
1078 NaCl_page_free((void *) sysaddr
, nbytes
);
1080 p
->partial
= sysaddr
;
1085 uintptr_t user_address
= entry
->page_num
<< NACL_PAGESHIFT
;
1086 if (NaClRoundAllocPage(user_address
) != user_address
) {
1088 ("descriptor backed memory does not start"
1089 " at allocation boundary, addr: 0x%08"PRIxPTR
"\n"),
1092 if (NaClRoundHostAllocPage(nbytes
) != nbytes
) {
1094 ("descriptor backed memory size not allocation granularity:"
1098 (*entry
->nmop
->ndp
->vtbl
->UnmapUnsafe
)(entry
->nmop
->ndp
,
1105 void NaClAppFreeAllMemory(struct NaClApp
*nap
)
1107 struct NaClFreeState state
;
1108 struct NaClDescEffectorCleanup eff
;
1111 state
.effp
= (struct NaClDescEffector
*) &eff
;
1115 NaClDescEffectorCleanupCtor(&eff
);
1116 NaClVmmapVisit(&nap
->mem_map
, NaClAppFreeWalker
, &state
);
1117 (*eff
.base
.vtbl
->Dtor
)(&eff
.base
);