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