Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / sel_main_chrome.c
1 /*
2  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #include "native_client/src/public/chrome_main.h"
8
9 #include "native_client/src/include/portability.h"
10 #include "native_client/src/include/portability_io.h"
11 #include "native_client/src/include/portability_sockets.h"
12
13 #include <stdio.h>
14 #include <string.h>
15
16 #include "native_client/src/include/nacl_macros.h"
17 #include "native_client/src/public/nacl_app.h"
18 #include "native_client/src/shared/platform/nacl_check.h"
19 #include "native_client/src/shared/platform/nacl_exit.h"
20 #include "native_client/src/shared/platform/nacl_log.h"
21 #include "native_client/src/shared/platform/nacl_secure_random.h"
22 #include "native_client/src/shared/platform/nacl_sync.h"
23 #include "native_client/src/shared/platform/nacl_sync_checked.h"
24 #include "native_client/src/trusted/desc/nacl_desc_io.h"
25 #include "native_client/src/trusted/fault_injection/fault_injection.h"
26 #include "native_client/src/trusted/service_runtime/env_cleanser.h"
27 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
28 #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
29 #include "native_client/src/trusted/service_runtime/nacl_app.h"
30 #include "native_client/src/trusted/service_runtime/nacl_bootstrap_channel_error_reporter.h"
31 #include "native_client/src/trusted/service_runtime/nacl_error_log_hook.h"
32 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
33 #include "native_client/src/trusted/service_runtime/nacl_debug_init.h"
34 #include "native_client/src/trusted/service_runtime/nacl_signal.h"
35 #include "native_client/src/trusted/service_runtime/osx/mach_exception_handler.h"
36 #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
37 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
38 #include "native_client/src/trusted/service_runtime/sel_main_common.h"
39 #include "native_client/src/trusted/service_runtime/sel_qualify.h"
40 #include "native_client/src/trusted/service_runtime/win/exception_patch/ntdll_patch.h"
41 #include "native_client/src/trusted/validator/rich_file_info.h"
42 #include "native_client/src/trusted/validator/validation_metadata.h"
43
44 static int g_initialized = 0;
45
46 static void (*g_fatal_error_handler)(const char *data, size_t bytes) = NULL;
47
48 static const int default_argc = 1;
49 static const char *const default_argv[1] = {"NaClMain"};
50
51 #if NACL_LINUX || NACL_OSX
52 void NaClChromeMainSetUrandomFd(int urandom_fd) {
53   CHECK(!g_initialized);
54   NaClSecureRngModuleSetUrandomFd(urandom_fd);
55 }
56 #endif
57
58 void NaClChromeMainInit(void) {
59   CHECK(!g_initialized);
60   NaClAllModulesInit();
61   g_initialized = 1;
62 }
63
64 static void NaClFatalErrorHandlerCallback(void *state,
65                                           char *buf,
66                                           size_t buf_bytes) {
67   CHECK(state == NULL);
68   g_fatal_error_handler(buf, buf_bytes);
69 }
70
71 void NaClSetFatalErrorCallback(void (*func)(const char *data, size_t bytes)) {
72   CHECK(g_initialized);
73   if (g_fatal_error_handler != NULL)
74     NaClLog(LOG_FATAL, "NaClSetFatalErrorCallback called twice.\n");
75   g_fatal_error_handler = func;
76   NaClErrorLogHookInit(NaClFatalErrorHandlerCallback, NULL);
77 }
78
79 struct NaClChromeMainArgs *NaClChromeMainArgsCreate(void) {
80   struct NaClChromeMainArgs *args;
81
82   CHECK(g_initialized);
83   args = malloc(sizeof(*args));
84   if (args == NULL)
85     return NULL;
86   args->imc_bootstrap_handle = NACL_INVALID_HANDLE;
87   args->irt_fd = -1;
88   args->irt_desc = NULL;
89   args->irt_load_optional = 0;
90   args->enable_exception_handling = 0;
91   args->enable_debug_stub = 0;
92   args->enable_dyncode_syscalls = 1;
93   args->pnacl_mode = 0;
94   /* TODO(ncbray): default to 0. */
95   args->skip_qualification =
96       getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL;
97   args->initial_nexe_max_code_bytes = 0;  /* No limit */
98 #if NACL_LINUX || NACL_OSX
99   args->debug_stub_server_bound_socket_fd = NACL_INVALID_SOCKET;
100 #endif
101 #if NACL_WINDOWS
102   args->debug_stub_server_port_selected_handler_func = NULL;
103 #endif
104   args->create_memory_object_func = NULL;
105   args->validation_cache = NULL;
106 #if NACL_WINDOWS
107   args->broker_duplicate_handle_func = NULL;
108   args->attach_debug_exception_handler_func = NULL;
109 #endif
110 #if NACL_LINUX || NACL_OSX
111   args->number_of_cores = -1;  /* unknown */
112 #endif
113 #if NACL_LINUX
114   args->prereserved_sandbox_size = 0;
115 #endif
116   args->nexe_desc = NULL;
117
118   args->argc = default_argc;
119   args->argv = (char **) default_argv;
120   return args;
121 }
122
123 static struct NaClDesc *IrtDescFromFd(int irt_fd) {
124   struct NaClDesc *irt_desc;
125
126   if (irt_fd == -1) {
127     NaClLog(LOG_FATAL,
128             "IrtDescFromFd: Integrated runtime (IRT) not present.\n");
129   }
130
131   /* Takes ownership of the FD. */
132   irt_desc = NaClDescIoDescFromDescAllocCtor(irt_fd, NACL_ABI_O_RDONLY);
133   if (NULL == irt_desc) {
134     NaClLog(LOG_FATAL,
135             "IrtDescFromFd: failed to construct NaClDesc object from"
136             " descriptor\n");
137   }
138
139   return irt_desc;
140 }
141
142 static char kFakeIrtName[] = "\0IRT";
143
144 static void NaClLoadIrt(struct NaClApp *nap, struct NaClDesc *irt_desc) {
145   struct NaClRichFileInfo info;
146   struct NaClValidationMetadata metadata;
147   NaClErrorCode errcode;
148
149   /* Attach file origin info to the IRT's NaClDesc. */
150   NaClRichFileInfoCtor(&info);
151   /*
152    * For the IRT use a fake file name with null characters at the begining and
153    * the end of the name.
154    * TODO(ncbray): plumb the real filename in from Chrome.
155    * Note that when the file info is attached to the NaClDesc, information from
156    * stat is incorporated into the metadata.  There is no functional reason to
157    * attach the info to the NaClDesc other than to create the final metadata.
158    * TODO(ncbray): API for deriving metadata from a NaClDesc without attaching.
159    */
160   info.known_file = 1;
161   info.file_path = kFakeIrtName;
162   info.file_path_length = sizeof(kFakeIrtName);
163   NaClSetFileOriginInfo(irt_desc, &info);
164   /* Don't free the info struct because we don't own the file path string. */
165
166   NaClMetadataFromNaClDescCtor(&metadata, irt_desc);
167   errcode = NaClMainLoadIrt(nap, irt_desc, &metadata);
168   if (errcode != LOAD_OK) {
169     NaClLog(LOG_FATAL,
170             "NaClLoadIrt: Failed to load the integrated runtime (IRT): %s\n",
171             NaClErrorString(errcode));
172   }
173
174   NaClMetadataDtor(&metadata);
175 }
176
177 static int LoadApp(struct NaClApp *nap, struct NaClChromeMainArgs *args) {
178   NaClErrorCode errcode = LOAD_OK;
179   int has_bootstrap_channel = args->imc_bootstrap_handle != NACL_INVALID_HANDLE;
180
181   CHECK(g_initialized);
182
183   /*
184    * TODO(teravest): Remove this once Chromium uses NaClSetFatalErrorCallback.
185    */
186   if (has_bootstrap_channel && g_fatal_error_handler == NULL) {
187     NaClBootstrapChannelErrorReporterInit();
188     NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, nap);
189   }
190
191   /* Allow or disallow dyncode API based on args. */
192   nap->enable_dyncode_syscalls = args->enable_dyncode_syscalls;
193   nap->initial_nexe_max_code_bytes = args->initial_nexe_max_code_bytes;
194   nap->pnacl_mode = args->pnacl_mode;
195
196 #if NACL_LINUX
197   g_prereserved_sandbox_size = args->prereserved_sandbox_size;
198 #endif
199 #if NACL_LINUX || NACL_OSX
200   /*
201    * Overwrite value of sc_nprocessors_onln set in NaClAppCtor.  In
202    * the Chrome embedding, the outer sandbox was already enabled when
203    * the NaClApp Ctor was invoked, so a bogus value was written in
204    * sc_nprocessors_onln.
205    */
206   if (-1 != args->number_of_cores) {
207     nap->sc_nprocessors_onln = args->number_of_cores;
208   }
209 #endif
210
211   if (args->create_memory_object_func != NULL)
212     NaClSetCreateMemoryObjectFunc(args->create_memory_object_func);
213
214   /* Inject the validation caching interface, if it exists. */
215   nap->validation_cache = args->validation_cache;
216
217 #if NACL_WINDOWS
218   if (args->broker_duplicate_handle_func != NULL)
219     NaClSetBrokerDuplicateHandleFunc(args->broker_duplicate_handle_func);
220 #endif
221
222   NaClAppInitialDescriptorHookup(nap);
223
224   /*
225    * NACL_SERVICE_PORT_DESCRIPTOR and NACL_SERVICE_ADDRESS_DESCRIPTOR
226    * are 3 and 4.
227    */
228
229   /*
230    * in order to report load error to the browser plugin through the
231    * secure command channel, we do not immediate jump to cleanup code
232    * on error.  rather, we continue processing (assuming earlier
233    * errors do not make it inappropriate) until the secure command
234    * channel is set up, and then bail out.
235    */
236
237   /*
238    * Ensure this operating system platform is supported.
239    */
240   if (args->skip_qualification) {
241     fprintf(stderr, "PLATFORM QUALIFICATION DISABLED - "
242         "Native Client's sandbox will be unreliable!\n");
243   } else {
244     errcode = NACL_FI_VAL("pq", NaClErrorCode,
245                           NaClRunSelQualificationTests());
246     if (LOAD_OK != errcode) {
247       nap->module_load_status = errcode;
248       fprintf(stderr, "Error while loading in SelMain: %s\n",
249               NaClErrorString(errcode));
250     }
251   }
252
253   /*
254    * Patch the Windows exception dispatcher to be safe in the case
255    * of faults inside x86-64 sandboxed code.  The sandbox is not
256    * secure on 64-bit Windows without this.
257    */
258 #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
259      NACL_BUILD_SUBARCH == 64)
260   NaClPatchWindowsExceptionDispatcher();
261 #endif
262   NaClSignalTestCrashOnStartup();
263
264   nap->enable_exception_handling = args->enable_exception_handling;
265
266   if (args->enable_exception_handling || args->enable_debug_stub) {
267 #if NACL_LINUX
268     /* NaCl's signal handler is always enabled on Linux. */
269 #elif NACL_OSX
270     if (!NaClInterceptMachExceptions()) {
271       NaClLog(LOG_FATAL, "LoadApp: Failed to set up Mach exception handler\n");
272     }
273 #elif NACL_WINDOWS
274     nap->attach_debug_exception_handler_func =
275         args->attach_debug_exception_handler_func;
276 #else
277 # error Unknown host OS
278 #endif
279   }
280 #if NACL_LINUX
281   NaClSignalHandlerInit();
282 #endif
283
284   /* Give debuggers a well known point at which xlate_base is known.  */
285   NaClGdbHook(nap);
286
287   if (has_bootstrap_channel) {
288     NaClCreateServiceSocket(nap);
289     /*
290      * LOG_FATAL errors that occur before NaClSetUpBootstrapChannel will
291      * not be reported via the crash log mechanism (for Chromium
292      * embedding of NaCl, shown in the JavaScript console).
293      *
294      * Some errors, such as due to NaClRunSelQualificationTests, do not
295      * trigger a LOG_FATAL but instead set module_load_status to be sent
296      * in the start_module RPC reply.  Log messages associated with such
297      * errors would be seen, since NaClSetUpBootstrapChannel will get
298      * called.
299      */
300     NaClSetUpBootstrapChannel(nap, args->imc_bootstrap_handle);
301   }
302
303   if (args->nexe_desc) {
304     NaClAppLoadModule(nap, args->nexe_desc, NULL, NULL);
305     NaClDescUnref(args->nexe_desc);
306     args->nexe_desc = NULL;
307   }
308
309   if (has_bootstrap_channel) {
310     NACL_FI_FATAL("BeforeSecureCommandChannel");
311     /*
312      * Spawns a thread that uses the command channel.
313      * Hereafter any changes to nap should be done while holding locks.
314      */
315     NaClSecureCommandChannel(nap);
316
317     NaClLog(4, "NaClSecureCommandChannel has spawned channel\n");
318
319     NaClLog(4, "secure service = %"NACL_PRIxPTR"\n",
320             (uintptr_t) nap->secure_service);
321     NACL_FI_FATAL("BeforeWaitForStartModule");
322
323     if (NULL != nap->secure_service) {
324       NaClErrorCode start_result;
325       /*
326        * wait for start_module RPC call on secure channel thread.
327        */
328       start_result = NaClWaitForStartModuleCommand(nap);
329       if (LOAD_OK == errcode) {
330         errcode = start_result;
331       }
332     }
333   }
334
335   NACL_FI_FATAL("BeforeLoadIrt");
336
337   /*
338    * error reporting done; can quit now if there was an error earlier.
339    */
340   if (LOAD_OK != errcode) {
341     goto done;
342   }
343
344   /*
345    * Load the integrated runtime (IRT) library.
346    * Skip if irt_load_optional and the nexe doesn't have the usual 256MB
347    * segment gap. PNaCl's disabling of the segment gap doesn't actually
348    * disable the segment gap. It only only reduces it drastically.
349    */
350   if (args->irt_load_optional && nap->dynamic_text_end < 0x10000000) {
351     NaClLog(1,
352             "Skipped NaClLoadIrt, irt_load_optional with dynamic_text_end: %"
353             NACL_PRIxPTR"\n", nap->dynamic_text_end);
354   } else {
355     if (args->irt_fd != -1) {
356       CHECK(args->irt_desc == NULL);
357       args->irt_desc = IrtDescFromFd(args->irt_fd);
358       args->irt_fd = -1;
359     }
360     if (args->irt_desc != NULL) {
361       NaClLoadIrt(nap, args->irt_desc);
362       NaClDescUnref(args->irt_desc);
363       args->irt_desc = NULL;
364     }
365   }
366
367   if (has_bootstrap_channel) {
368     if (NACL_FI_ERROR_COND("LaunchServiceThreads",
369                            !NaClAppLaunchServiceThreads(nap))) {
370       NaClLog(LOG_FATAL, "Launch service threads failed\n");
371     }
372   }
373
374   if (args->enable_debug_stub) {
375 #if NACL_LINUX || NACL_OSX
376     if (args->debug_stub_server_bound_socket_fd != NACL_INVALID_SOCKET) {
377       NaClDebugSetBoundSocket(args->debug_stub_server_bound_socket_fd);
378     }
379 #endif
380     if (!NaClDebugInit(nap)) {
381       goto done;
382     }
383 #if NACL_WINDOWS
384     if (NULL != args->debug_stub_server_port_selected_handler_func) {
385       args->debug_stub_server_port_selected_handler_func(nap->debug_stub_port);
386     }
387 #endif
388   }
389
390   return LOAD_OK;
391
392 done:
393   fflush(stdout);
394
395   /*
396    * If there is a secure command channel, we sent an RPC reply with
397    * the reason that the nexe was rejected.  If we exit now, that
398    * reply may still be in-flight and the various channel closure (esp
399    * reverse channel) may be detected first.  This would result in a
400    * crash being reported, rather than the error in the RPC reply.
401    * Instead, we wait for the hard-shutdown on the command channel.
402    */
403   if (LOAD_OK != errcode) {
404     NaClBlockIfCommandChannelExists(nap);
405   } else {
406     /*
407      * Don't return LOAD_OK if we had some failure loading.
408      */
409     errcode = LOAD_INTERNAL;
410   }
411   return errcode;
412 }
413
414 static int StartApp(struct NaClApp *nap, struct NaClChromeMainArgs *args) {
415   int ret_code;
416   struct NaClEnvCleanser env_cleanser;
417   char const *const *envp;
418
419   NACL_FI_FATAL("BeforeEnvCleanserCtor");
420
421   NaClEnvCleanserCtor(&env_cleanser, 1);
422   if (!NaClEnvCleanserInit(&env_cleanser, NaClGetEnviron(), NULL)) {
423     NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n");
424   }
425   envp = NaClEnvCleanserEnvironment(&env_cleanser);
426
427   if (NACL_FI_ERROR_COND(
428           "CreateMainThread",
429           !NaClCreateMainThread(nap, args->argc, args->argv, envp))) {
430     NaClLog(LOG_FATAL, "creating main thread failed\n");
431   }
432   NACL_FI_FATAL("BeforeEnvCleanserDtor");
433
434   NaClEnvCleanserDtor(&env_cleanser);
435
436   ret_code = NaClWaitForMainThreadToExit(nap);
437
438   if (NACL_ABI_WIFEXITED(nap->exit_status)) {
439     /*
440      * Under Chrome, a call to _exit() often indicates that something
441      * has gone awry, so we report it here to aid debugging.
442      *
443      * This conditional does not run if the NaCl process was
444      * terminated forcibly, which is the normal case under Chrome.
445      * This forcible exit is triggered by the renderer closing the
446      * trusted SRPC channel, which we record as NACL_ABI_SIGKILL
447      * internally.
448      */
449     NaClLog(LOG_INFO, "NaCl untrusted code called _exit(0x%x)\n", ret_code);
450   }
451   return ret_code;
452 }
453
454 void NaClChromeMainStartApp(struct NaClApp *nap,
455                             struct NaClChromeMainArgs *args) {
456   int status = 1;
457   NaClChromeMainStart(nap, args, &status);
458   /*
459    * exit_group or equiv kills any still running threads while module
460    * addr space is still valid.  otherwise we'd have to kill threads
461    * before we clean up the address space.
462    */
463   NaClExit(status);
464 }
465
466 int NaClChromeMainStart(struct NaClApp *nap,
467                         struct NaClChromeMainArgs *args,
468                         int *exit_status) {
469   int load_ok = LOAD_OK == LoadApp(nap, args);
470   if (load_ok) {
471     *exit_status = StartApp(nap, args);
472   }
473   free(args);
474   return load_ok;
475 }