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