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).
35 #include "native_client/include/portability.h"
46 # include <netinet/in.h>
49 # include <sys/types.h>
51 # include <sys/socket.h>
56 #include "native_client/service_runtime/nacl_globals.h"
58 #include "native_client/service_runtime/expiration.h"
59 #include "native_client/service_runtime/gio.h"
60 #include "native_client/service_runtime/nacl_log.h"
61 #include "native_client/service_runtime/nacl_sync.h"
62 #include "native_client/service_runtime/nacl_sync_checked.h"
63 #include "native_client/service_runtime/nacl_app.h"
64 #include "native_client/service_runtime/nacl_all_modules.h"
65 #include "native_client/platform_qual_test/nacl_os_qualify.h"
66 #include "native_client/service_runtime/nacl_syscall_common.h"
67 #include "native_client/service_runtime/sel_ldr.h"
69 #include "native_client/intermodule_comm/nacl_imc_c.h"
71 #include "native_client/tools/libsrpc/nacl_srpc.h"
75 static void VmentryPrinter(void *state
,
76 struct NaClVmmapEntry
*vmep
)
78 printf("page num 0x%06x\n", (uint32_t)vmep
->page_num
);
79 printf("num pages %d\n", (uint32_t)vmep
->npages
);
80 printf("prot bits %x\n", vmep
->prot
);
84 static void PrintVmmap(struct NaClApp
*nap
)
86 printf("In PrintVmmap\n");
88 NaClXMutexLock(&nap
->mu
);
89 NaClVmmapVisit(&nap
->mem_map
, VmentryPrinter
, (void *) 0);
91 NaClXMutexUnlock(&nap
->mu
);
109 struct NaClSocketAddress addr
;
113 int ImportModeMap(char opt
)
123 fprintf(stderr
, ("option %c not understood as a host descriptor"
130 #if defined(HAVE_SDL)
134 int NaClDup2(int d_old
, int d_new
)
136 if (d_old
== d_new
) {
139 if (DUP2(d_old
, d_new
) == -1) {
140 fprintf(stderr
, "sel_ldr: dup2 for log file failed\n");
149 * GDB's canonical overlay managment routine.
150 * We need its symbol in the symbol table so don't inline it.
153 static void __attribute__ ((noinline
)) _ovly_debug_event (void)
156 * The asm volatile is here as instructed by the GCC docs.
157 * It's not enough to declare a function noinline.
158 * GCC will still look inside the function to see if it's worth calling.
165 static void StopForDebuggerInit (const struct NaClApp
*state
)
167 /* Put xlate_base in a place where gdb can find it. */
168 nacl_global_xlate_base
= state
->xlate_base
;
171 _ovly_debug_event ();
175 static void trace_stack(struct sigcontext_struct
*regs
)
177 fprintf(stderr
, " top_of_stack, code_addr=%lx\n", regs
->eip
);
178 int frame
= regs
->ebp
;
179 int base
= 0x10000000; /* TODO: don't hard code this */
181 int ret_addr
= *(int *) (base
+ frame
+ 4);
182 int next_frame
= *(int *) (base
+ frame
);
183 fprintf(stderr
, " stack_frame=%x, code_addr=%x\n", frame
, ret_addr
);
188 static void print_regs(struct sigcontext_struct
*regs
)
190 #define PRINT_REG(name) \
191 fprintf(stderr, " " #name "=0x%lx (%li)\n", regs->name, regs->name);
202 static void handle_signal(int arg
)
204 struct sigcontext_struct
*regs
= (void *) (&arg
+ 1);
205 /* Need to restore %gs even if we don't use TLS variables.
206 Stack protector value is fetched from %gs. */
207 __asm__("mov %0, %%gs" : : "r" (orig_gs
));
208 /* Disable this handler. */
209 signal(SIGSEGV
, SIG_DFL
);
210 fprintf(stderr
, "Caught signal\n");
213 fprintf(stderr
, "Signal handler done, exiting\n");
217 static void set_up_signal_handler()
221 st
.ss_sp
= malloc(st
.ss_size
);
223 if(sigaltstack(&st
, NULL
) < 0) {
224 perror("sigaltstack");
228 __asm__("mov %%gs, %0" : "=r" (orig_gs
));
230 struct sigaction act
;
231 act
.sa_handler
= handle_signal
;
232 sigemptyset(&act
.sa_mask
);
233 act
.sa_flags
= SA_ONSTACK
;
234 if(sigaction(SIGSEGV
, &act
, NULL
) < 0) {
241 * Note that we cannot use the 3 arg declaration for main, since SDL
242 * preprocessor defines main to SDLmain and then provides a
243 * replacement main that performs other startup initialization. The
244 * SDL startup code only supplies 2 args to the renamed SDLmain, and
245 * if we used the 3 arg version here we'd pick up some garbage off the
246 * stack for envp. Instead, we make envp be a local variable, and
247 * initialize it from the eviron global variable.
256 struct redir
*redir_queue
;
257 struct redir
**redir_qend
;
259 struct NaClApp state
;
261 int main_thread_only
= 1;
262 int export_addr_to
= -2;
263 int dump_sock_addr_to
= -1;
268 NaClErrorCode errcode
;
269 struct GioMemoryFileSnapshot gf
;
272 extern char **environ
;
273 char *log_file
= NULL
;
277 struct GioFile log_gio
;
279 set_up_signal_handler();
281 /* do expiration check first */
283 if (NaClHasExpired()) {
284 fprintf(stderr
, "This version of Native Client has expired.\n");
285 fprintf(stderr
, "Please visit: http://code.google.com/p/nativeclient/\n");
292 redir_qend
= &redir_queue
;
295 * Set an exception handler so Windows won't show a message box if
296 * an exception occurs
298 WINDOWS_EXCEPTION_TRY
;
300 NaClAllModulesInit();
302 log_file
= getenv("NACLLOG");
304 if (NULL
!= (env_verbosity
= getenv("NACLVERBOSITY"))) {
305 int v
= strtol(env_verbosity
, (char **) 0, 0);
309 NaClLogSetVerbosity(v
);
312 fflush((FILE *) NULL
);
314 if (!GioFileRefCtor(&gout
, stdout
)) {
315 fprintf(stderr
, "Could not create general standard output channel\n");
319 while ((opt
= getopt(ac
, av
, "a:dD:f:h:i:l:mMP:r:vw:X:E:")) != -1) {
322 /* import IMC socket address */
323 entry
= malloc(sizeof *entry
);
325 fprintf(stderr
, "No memory for redirection queue\n");
329 entry
->nacl_desc
= strtol(optarg
, &rest
, 0);
330 entry
->tag
= IMC_ADDR
;
331 strncpy(entry
->u
.addr
.path
, rest
+ 1, NACL_PATH_MAX
);
333 entry
->u
.addr
.path
[NACL_PATH_MAX
-1] = '\0';
335 redir_qend
= &entry
->next
;
338 fprintf(stderr
, "DEBUG MODE ENABLED\n");
339 NaClInsecurelyBypassAllAclChecks();
340 /* NaClIgnoreValidatorResult(); */
345 /* import host descriptor */
346 entry
= malloc(sizeof *entry
);
348 fprintf(stderr
, "No memory for redirection queue\n");
352 entry
->nacl_desc
= strtol(optarg
, &rest
, 0);
353 entry
->tag
= HOST_DESC
;
354 entry
->u
.host
.d
= strtol(rest
+1, (char **) 0, 0);
355 entry
->u
.host
.mode
= ImportModeMap(opt
);
357 redir_qend
= &entry
->next
;
360 /* import IMC handle */
361 entry
= malloc(sizeof *entry
);
363 fprintf(stderr
, "No memory for redirection queue\n");
367 entry
->nacl_desc
= strtol(optarg
, &rest
, 0);
368 entry
->tag
= IMC_DESC
;
369 entry
->u
.handle
= (NaClHandle
) strtol(rest
+1, (char **) 0, 0);
371 redir_qend
= &entry
->next
;
377 main_thread_only
= 1;
380 main_thread_only
= 0;
383 dump_sock_addr_to
= strtol(optarg
, (char **) 0, 0);
389 /* Conduit to convey the descriptor ID to the application code. */
390 NaClSrpcFileDescriptor
= strtol(optarg
, (char **) 0, 0);
394 NaClLogIncrVerbosity();
397 export_addr_to
= strtol(optarg
, (char **) 0, 0);
400 if(putenv(optarg
) != 0) {
407 "Usage: sel_ldr [-a d:addr]\n"
408 " [-h d:D] [-r d:D] [-w d:D] [-i d:D]\n"
410 " [-P SRPC port number]\n"
417 " -a associates an IMC address with application descriptor d\n"
420 " -w associate a host POSIX descriptor D with app desc d\n"
421 " that was opened in O_RDWR, O_RDONLY, and O_WRONLY modes\n"
423 " -i associates an IMC handle D with app desc d\n"
425 " -P set SRPC port number for SRPC calls\n"
426 " -v increases verbosity\n"
427 " -X create a bound socket and export the address via an\n"
428 " IMC message to a corresponding NaCl app descriptor\n"
429 " (use -1 to create the bound socket / address descriptor\n"
430 " pair, but that no export via IMC should occur)\n"
431 " [NB: -m and -M only applies to the SDL builds\n ]\n");
433 " -m enforce that certain syscalls can only be made from\n"
434 " the main NaCl app thread, so that we're enforcing (bug)\n"
435 " compatibility with standalone windows apps that must\n"
436 " make certain (e.g., graphics) calls from the main\n"
438 " -M allow syscalls to be made from any NaCl app thread,\n"
439 " since these (windows-library-using) syscalls are\n"
440 " actually done via a work queue using the sel_ldr\n"
441 " main thread anyway\n"
442 " -E set environment variable\n"
445 " -d debug mode (allow access to files!)\n"
446 " -D dump bound socket address (if any) to this POSIX\n"
452 /* SDL does not pass 3 args to re-defined main */
456 * change stdout/stderr to log file now, so that subsequent error
457 * messages will go there. unfortunately, error messages that
458 * result from getopt processing -- usually out-of-memory, which
459 * shouldn't happen -- won't show up.
461 if (NULL
!= log_file
) {
463 log_desc
= open(log_file
, O_WRONLY
| O_APPEND
| O_CREAT
, 0777);
464 if (-1 == log_desc
) {
465 fprintf(stderr
, "Could not create log file\n");
469 log_stream
= FDOPEN(log_desc
, "a");
470 if (NULL
== log_stream
) {
471 fprintf(stderr
, "Could not fdopen log stream\n");
474 GioFileRefCtor(&log_gio
, log_stream
);
475 NaClLogSetGio((struct Gio
*) &log_gio
);
478 if (!nacl_file
&& optind
< ac
) {
479 nacl_file
= av
[optind
];
483 fprintf(stderr
, "No nacl file specified\n");
487 /* to be passed to NaClMain, eventually... */
488 av
[--optind
] = "NaClMain";
490 if (0 == GioMemoryFileSnapshotCtor(&gf
, nacl_file
)) {
492 fprintf(stderr
, "Cannot open \"%s\".\n", nacl_file
);
496 if (!NaClAppCtor(&state
)) {
497 fprintf(stderr
, "Error while constructing app state\n");
501 state
.restrict_to_main_thread
= main_thread_only
;
507 * in order to report load error to the browser plugin through the
508 * secure command channel, we do not immediate jump to cleanup code
509 * on error. rather, we continue processing (assuming earlier
510 * errors do not make it inappropriate) until the secure command
511 * channel is set up, and then bail out.
515 * Ensure this operating system platform is supported.
517 if (!NaClOsIsSupported()) {
518 errcode
= LOAD_UNSUPPORTED_OS_PLATFORM
;
519 nap
->module_load_status
= errcode
;
520 fprintf(stderr
, "Error while loading \"%s\": %s\n",
522 NaClErrorString(errcode
));
525 if (LOAD_OK
== errcode
) {
526 errcode
= NaClAppLoadFile((struct Gio
*) &gf
, nap
);
527 if (LOAD_OK
!= errcode
) {
528 nap
->module_load_status
= errcode
;
529 fprintf(stderr
, "Error while loading \"%s\": %s\n",
531 NaClErrorString(errcode
));
535 if (LOAD_OK
== errcode
) {
537 gprintf((struct Gio
*) &gout
, "printing NaClApp details\n");
538 NaClAppPrintDetails(nap
, (struct Gio
*) &gout
);
542 * Finish setting up the NaCl App. This includes dup'ing
543 * descriptors 0-2 and making them available to the NaCl App.
545 errcode
= NaClAppPrepareToLaunch(nap
,
547 (-1 == log_desc
) ? 1 : log_desc
,
548 (-1 == log_desc
) ? 2 : log_desc
);
549 if (LOAD_OK
!= errcode
) {
550 nap
->module_load_status
= errcode
;
551 fprintf(stderr
, "NaClAppPrepareToLaunch returned %d", errcode
);
555 /* Give debuggers a well known point at which xlate_base is known. */
556 StopForDebuggerInit (&state
);
559 * Execute additional I/O redirections. NB: since the NaClApp
560 * takes ownership of host / IMC socket descriptors, all but
561 * the first run will not get access if the NaClApp closes
562 * them. Currently a normal NaClApp process exit does not
563 * close descriptors, since the underlying host OS will do so
564 * as part of service runtime exit.
566 for (entry
= redir_queue
; NULL
!= entry
; entry
= entry
->next
) {
567 switch (entry
->tag
) {
569 NaClAddHostDescriptor(nap
, entry
->u
.host
.d
,
570 entry
->u
.host
.mode
, entry
->nacl_desc
);
573 NaClAddImcHandle(nap
, entry
->u
.handle
, entry
->nacl_desc
);
576 NaClAddImcAddr(nap
, &entry
->u
.addr
, entry
->nacl_desc
);
581 * If export_addr_to is set to a non-negative integer, we create a
582 * bound socket and socket address pair and bind the former to
583 * descriptor 3 and the latter to descriptor 4. The socket address
584 * is written out to the export_addr_to descriptor.
586 * The service runtime also accepts a connection on the bound socket
587 * and spawns a secure command channel thread to service it.
589 * If export_addr_to is -1, we only create the bound socket and
590 * socket address pair, and we do not export to an IMC socket. This
591 * use case is typically only used in testing, where we only "dump"
592 * the socket address to stdout or similar channel.
594 if (-2 < export_addr_to
) {
595 NaClCreateServiceSocket(nap
);
596 if (0 <= export_addr_to
) {
597 NaClSendServiceAddressTo(nap
, export_addr_to
);
599 * NB: spawns a thread that uses the command channel. we do
600 * this after NaClAppLoadFile so that NaClApp object is more
601 * fully populated. Hereafter any changes to nap should be done
602 * while holding locks.
604 NaClSecureCommandChannel(nap
);
608 * may have created a thread, so need to synchronize uses of nap
612 if (-1 != dump_sock_addr_to
) {
613 NaClDumpServiceAddressTo(nap
, dump_sock_addr_to
);
617 * Print out a marker for scripts to use to mark the start of app
620 NaClLog(1, "NACL: Application output follows\n");
623 * Make sure all the file buffers are flushed before entering
624 * the application code.
626 fflush((FILE *) NULL
);
628 NaClXMutexLock(&nap
->mu
);
629 nap
->module_load_status
= LOAD_OK
;
630 NaClXCondVarBroadcast(&nap
->cv
);
631 NaClXMutexUnlock(&nap
->mu
);
633 if (NULL
!= nap
->secure_channel
) {
635 * wait for start_module RPC call on secure channel thread.
637 NaClWaitForModuleStartStatusCall(nap
);
641 * error reporting done; can quit now if there was an error earlier.
643 if (LOAD_OK
!= errcode
) {
648 * only nap->ehdrs.e_entry is usable, no symbol table is
651 if (!NaClCreateMainThread(nap
,
655 fprintf(stderr
, "creating main thread failed\n");
659 ret_code
= NaClWaitForMainThreadToExit(nap
);
662 * exit_group or equiv kills any still running threads while module
663 * addr space is still valid. otherwise we'd have to kill threads
664 * before we clean up the address space.
672 gprintf((struct Gio
*) &gout
, "exiting -- printing NaClApp details\n");
673 NaClAppPrintDetails(nap
, (struct Gio
*) &gout
);
675 printf("Dumping vmmap.\n"); fflush(stdout
);
686 if ((*((struct Gio
*) &gf
)->vtbl
->Close
)((struct Gio
*) &gf
) == -1) {
687 fprintf(stderr
, "Error while closing \"%s\".\n", av
[optind
]);
689 (*((struct Gio
*) &gf
)->vtbl
->Dtor
)((struct Gio
*) &gf
);
696 NaClAllModulesFini();
698 WINDOWS_EXCEPTION_CATCH
;