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