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"
45 # include <netinet/in.h>
48 # include <sys/types.h>
50 # include <sys/socket.h>
55 #include "native_client/service_runtime/nacl_globals.h"
57 #include "native_client/service_runtime/expiration.h"
58 #include "native_client/service_runtime/nacl_log.h"
59 #include "native_client/service_runtime/sel_ldr.h"
60 #include "native_client/service_runtime/nacl_app.h"
61 #include "native_client/service_runtime/nacl_all_modules.h"
62 #include "native_client/service_runtime/nacl_syscall_common.h"
64 #include "native_client/intermodule_comm/nacl_imc_c.h"
66 #include "native_client/tools/libsrpc/nacl_srpc.h"
70 void VmentryPrinter(void *state
,
71 struct NaClVmmapEntry
*vmep
)
73 printf("page num 0x%06x\n", (uint32_t)vmep
->page_num
);
74 printf("num pages %d\n", (uint32_t)vmep
->npages
);
75 printf("prot bits %x\n", vmep
->prot
);
79 void PrintVmmap(struct NaClApp
*nap
)
83 printf("In PrintVmmap\n"); fflush(stdout
);
84 NaClVmmapVisit(&nap
->mem_map
, VmentryPrinter
, (void *) 0);
86 page_num
= NaClVmmapFindSpace(&nap
->mem_map
, 1024);
88 printf("found a 4MB hole at page number 0x%06x\n", (uint32_t)page_num
);
108 struct NaClSocketAddress addr
;
112 int ImportModeMap(char opt
)
122 fprintf(stderr
, ("option %c not understood as a host descriptor"
129 #if defined(HAVE_SDL)
133 int NaClDup2(d_old
, d_new
)
135 if (d_old
== d_new
) {
145 fprintf(stderr
, "sel_ldr: dup2 for log file failed\n");
152 * Note that we cannot use the 3 arg declaration for main, since SDL
153 * preprocessor defines main to SDLmain and then provides a
154 * replacement main that performs other startup initialization. The
155 * SDL startup code only supplies 2 args to the renamed SDLmain, and
156 * if we used the 3 arg version here we'd pick up some garbage off the
157 * stack for envp. Instead, we make envp be a local variable, and
158 * initialize it from the eviron global variable.
167 struct redir
*redir_queue
;
168 struct redir
**redir_qend
;
170 struct NaClApp state
;
172 int main_thread_only
= 1;
173 int export_addr_to
= -2;
174 int dump_sock_addr_to
= -1;
179 NaClErrorCode errcode
;
180 struct GioMemoryFileSnapshot gf
;
181 int (*fp
)(int, char **, char **);
183 extern char **environ
;
184 char *log_file
= NULL
;
186 /* do expiration check first */
187 if (NaClHasExpired()) {
188 fprintf(stderr
, "This version of Native Client has expired.\n");
189 fprintf(stderr
, "Please visit: http://code.google.com/p/nativeclient/\n");
193 /* SDL does not pass 3 args to re-defined main */
198 redir_qend
= &redir_queue
;
202 * Set an exception handler so Windows won't show a message box if
203 * an exception occurs
205 WINDOWS_EXCEPTION_TRY
;
207 NaClAllModulesInit();
209 if (!GioFileRefCtor(&gout
, stdout
)) {
210 fprintf(stderr
, "Could not create general standard output channel\n");
214 while ((opt
= getopt(ac
, av
, "a:dD:f:h:i:l:mMP:r:vw:X:")) != -1) {
217 /* import IMC socket address */
218 entry
= malloc(sizeof *entry
);
220 fprintf(stderr
, "No memory for redirection queue\n");
224 entry
->nacl_desc
= strtol(optarg
, &rest
, 0);
225 entry
->tag
= IMC_ADDR
;
226 strncpy(entry
->u
.addr
.path
, rest
+ 1, NACL_PATH_MAX
);
228 entry
->u
.addr
.path
[NACL_PATH_MAX
-1] = '\0';
230 redir_qend
= &entry
->next
;
233 fprintf(stderr
, "DEBUG MODE ENABLED\n");
234 NaClInsecurelyBypassAllAclChecks();
235 NaClIgnoreValidatorResult();
240 /* import host descriptor */
241 entry
= malloc(sizeof *entry
);
243 fprintf(stderr
, "No memory for redirection queue\n");
247 entry
->nacl_desc
= strtol(optarg
, &rest
, 0);
248 entry
->tag
= HOST_DESC
;
249 entry
->u
.host
.d
= strtol(rest
+1, (char **) 0, 0);
250 entry
->u
.host
.mode
= ImportModeMap(opt
);
252 redir_qend
= &entry
->next
;
255 /* import IMC handle */
256 entry
= malloc(sizeof *entry
);
258 fprintf(stderr
, "No memory for redirection queue\n");
262 entry
->nacl_desc
= strtol(optarg
, &rest
, 0);
263 entry
->tag
= IMC_DESC
;
264 entry
->u
.handle
= (NaClHandle
) strtol(rest
+1, (char **) 0, 0);
266 redir_qend
= &entry
->next
;
272 main_thread_only
= 1;
275 main_thread_only
= 0;
278 dump_sock_addr_to
= strtol(optarg
, (char **) 0, 0);
284 /* Conduit to convey the descriptor ID to the application code. */
285 NaClSrpcFileDescriptor
= strtol(optarg
, (char **) 0, 0);
289 NaClLogIncrVerbosity();
292 export_addr_to
= strtol(optarg
, (char **) 0, 0);
296 "Usage: sel_ldr [-a d:addr]\n"
297 " [-h d:D] [-r d:D] [-w d:D] [-i d:D]\n"
299 " [-P SRPC port number]\n"
304 " -a associates an IMC address with application descriptor d\n"
307 " -w associate a host POSIX descriptor D with app desc d\n"
308 " that was opened in O_RDWR, O_RDONLY, and O_WRONLY modes\n"
310 " -i associates an IMC handle D with app desc d\n"
312 " -P set SRPC port number for SRPC calls\n"
313 " -v increases verbosity\n"
314 " -X create a bound socket and export the address via an\n"
315 " IMC message to a corresponding NaCl app descriptor\n"
316 " (use -1 to create the bound socket / address descriptor\n"
317 " pair, but that no export via IMC should occur)\n"
318 " [NB: -m and -M only applies to the SDL builds\n ]\n"
319 " -m enforce that certain syscalls can only be made from\n"
320 " the main NaCl app thread, so that we're enforcing (bug)\n"
321 " compatibility with standalone windows apps that must\n"
322 " make certain (e.g., graphics) calls from the main\n"
324 " -M allow syscalls to be made from any NaCl app thread,\n"
325 " since these (windows-library-using) syscalls are\n"
326 " actually done via a work queue using the sel_ldr\n"
327 " main thread anyway\n"
330 " -d debug mode (allow access to files!)\n"
331 " -D dump bound socket address (if any) to this POSIX\n"
339 * change stdout/stderr to log file now, so that subsequent error
340 * messages will go there. unfortunately, error messages that
341 * result from getopt processing -- usually out-of-memory, which
342 * shouldn't happen -- won't show up.
344 if (NULL
!= log_file
) {
346 int should_close
= 1;
348 d
= open(log_file
, O_WRONLY
| O_APPEND
| O_CREAT
, 0777);
350 fprintf(stderr
, "Could not create log file\n");
353 should_close
&= NaClDup2(d
, 1);
354 should_close
&= NaClDup2(d
, 2);
360 if (!nacl_file
&& optind
< ac
) {
361 nacl_file
= av
[optind
];
365 fprintf(stderr
, "No nacl file specified\n");
369 /* to be passed to NaClMain, eventually... */
370 av
[--optind
] = "NaClMain";
372 if (0 == GioMemoryFileSnapshotCtor(&gf
, nacl_file
)) {
374 fprintf(stderr
, "Cannot open \"%s\".\n", nacl_file
);
378 if (!NaClAppCtor(&state
)) {
379 fprintf(stderr
, "Error while constructing app state\n");
383 state
.restrict_to_main_thread
= main_thread_only
;
385 errcode
= NaClAppLoadFile((struct Gio
*) &gf
, &state
);
388 if (LOAD_OK
!= errcode
) {
389 fprintf(stderr
, "Error while loading \"%s\": %s\n",
391 NaClErrorString(errcode
));
395 gprintf((struct Gio
*) &gout
, "printing NaClApp details\n");
396 NaClAppPrintDetails(nap
, (struct Gio
*) &gout
);
399 fp
= 0; /* eliminate compile-time warnings */
402 * Finish setting up the NaCl App. This includes dup'ing
403 * descriptors 0-2 and making them available to the NaCl App.
405 ret_code
= NaClAppPrepareToLaunch(nap
);
406 if (LOAD_OK
!= ret_code
) {
407 fprintf(stderr
, "NaClAppPrepareToLaunch returned %d", ret_code
);
412 * Execute additional I/O redirections. NB: since the NaClApp
413 * takes ownership of host / IMC socket descriptors, all but
414 * the first run will not get access if the NaClApp closes
415 * them. Currently a normal NaClApp process exit does not
416 * close descriptors, since the underlying host OS will do so
417 * as part of service runtime exit.
419 for (entry
= redir_queue
; NULL
!= entry
; entry
= entry
->next
) {
420 switch (entry
->tag
) {
422 NaClAddHostDescriptor(nap
, entry
->u
.host
.d
,
423 entry
->u
.host
.mode
, entry
->nacl_desc
);
426 NaClAddImcHandle(nap
, entry
->u
.handle
, entry
->nacl_desc
);
429 NaClAddImcAddr(nap
, &entry
->u
.addr
, entry
->nacl_desc
);
435 * If export_addr_to is set to a non-negative integer, we
436 * create a bound socket and socket address pair and bind the
437 * former to descriptor 3 and the latter to descritor 4. The
438 * socket address is written out to the export_addr_to IMC
439 * socket. Since the other I/O redirections have been done,
440 * those descriptor numbers are available as a send target.
441 * Note that if those specified descriptors 3 and 4, they will
442 * get overwritten here.
444 * If export_addr_to is -1, we only create the bound socket
445 * and socket address pair, and we do not export to an IMC
446 * socket. This use case is typically only used in testing,
447 * where we only "dump" the socket address to stdout or
450 if (-2 < export_addr_to
) {
451 NaClCreateServiceSocket(nap
);
452 if (0 <= export_addr_to
) {
453 NaClSendServiceAddressTo(nap
, export_addr_to
);
457 if (-1 != dump_sock_addr_to
) {
458 NaClDumpServiceAddressTo(nap
, dump_sock_addr_to
);
462 * Print out a marker for scripts to use to mark the start of app
465 NaClLog(1, "NACL: Application output follows\n");
468 * Make sure all the file buffers are flushed before entering
469 * the application code.
474 * only nap->ehdrs.e_entry is usable, no symbol table is
477 if (!NaClCreateMainThread(nap
,
481 fprintf(stderr
, "creating main thread failed\n");
485 ret_code
= NaClWaitForMainThreadToExit(nap
);
492 gprintf((struct Gio
*) &gout
, "exiting -- printing NaClApp details\n");
493 NaClAppPrintDetails(nap
, (struct Gio
*) &gout
);
495 printf("Dumping vmmap.\n"); fflush(stdout
);
506 if ((*((struct Gio
*) &gf
)->vtbl
->Close
)((struct Gio
*) &gf
) == -1) {
507 fprintf(stderr
, "Error while closing \"%s\".\n", av
[optind
]);
509 (*((struct Gio
*) &gf
)->vtbl
->Dtor
)((struct Gio
*) &gf
);
516 NaClAllModulesFini();
518 WINDOWS_EXCEPTION_CATCH
;