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 /*
8 * NaCl service run-time, non-platform specific system call helper routines.
9 */
10 #include <sys/types.h>
11 #include <sys/stat.h>
12
13 #include <errno.h>
14 #include <stdio.h>
15
16 #include "native_client/src/include/build_config.h"
17
18 #if NACL_WINDOWS
19 #include <windows.h>
20 #endif
21
22 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
23
24 #include "native_client/src/include/nacl_macros.h"
25 #include "native_client/src/include/portability_process.h"
26 #include "native_client/src/include/portability_string.h"
27
28 #include "native_client/src/shared/platform/nacl_check.h"
29 #include "native_client/src/shared/platform/nacl_clock.h"
30 #include "native_client/src/shared/platform/nacl_exit.h"
31 #include "native_client/src/shared/platform/nacl_sync_checked.h"
32 #include "native_client/src/shared/platform/nacl_time.h"
33
34 #include "native_client/src/trusted/cpu_features/arch/x86/cpu_x86.h"
35
36 #include "native_client/src/trusted/desc/nacl_desc_base.h"
37 #include "native_client/src/trusted/desc/nacl_desc_cond.h"
38 #include "native_client/src/trusted/desc/nacl_desc_mutex.h"
39 #include "native_client/src/trusted/desc/nacl_desc_semaphore.h"
40
41 #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
42 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
43 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
44 #include "native_client/src/trusted/service_runtime/include/sys/unistd.h"
45
46 #include "native_client/src/trusted/service_runtime/include/sys/nacl_test_crash.h"
47
48 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
49 #include "native_client/src/trusted/service_runtime/nacl_copy.h"
50 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
51 #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
52 #include "native_client/src/trusted/service_runtime/nacl_thread_nice.h"
53 #include "native_client/src/trusted/service_runtime/nacl_tls.h"
54 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
55
56
NaClSysNotImplementedDecoder(struct NaClAppThread * natp)57 int32_t NaClSysNotImplementedDecoder(struct NaClAppThread *natp) {
58 NaClCopyDropLock(natp->nap);
59 return -NACL_ABI_ENOSYS;
60 }
61
NaClAddSyscall(struct NaClApp * nap,uint32_t num,int32_t (* fn)(struct NaClAppThread *))62 void NaClAddSyscall(struct NaClApp *nap, uint32_t num,
63 int32_t (*fn)(struct NaClAppThread *)) {
64 CHECK(num < NACL_MAX_SYSCALLS);
65 if (nap->syscall_table[num].handler != &NaClSysNotImplementedDecoder) {
66 NaClLog(LOG_FATAL, "Duplicate syscall number %d\n", num);
67 }
68 nap->syscall_table[num].handler = fn;
69 }
70
NaClSysNull(struct NaClAppThread * natp)71 int32_t NaClSysNull(struct NaClAppThread *natp) {
72 UNREFERENCED_PARAMETER(natp);
73 return 0;
74 }
75
76 int NaClAclBypassChecks = 0;
77
NaClInsecurelyBypassAllAclChecks(void)78 void NaClInsecurelyBypassAllAclChecks(void) {
79 NaClLog(LOG_WARNING, "BYPASSING ALL ACL CHECKS\n");
80 NaClAclBypassChecks = 1;
81 }
82
83 char *NaClRootDir = NULL;
84 size_t NaClRootDirLen = 0;
85
86 #if NACL_WINDOWS
NaClMountRootDir(const char * root)87 int NaClMountRootDir(const char *root) {
88 /*
89 * TODO(smklein): Implement this functionality (and functionality
90 * in sys_filename.c) for Windows.
91 */
92 return 0;
93 }
94
95 #elif NACL_LINUX || NACL_OSX
NaClMountRootDir(const char * root)96 int NaClMountRootDir(const char *root) {
97 /* realpath mallocs NaClRootDir -- we must free it later */
98 NaClRootDir = realpath(root, NULL);
99 if (NaClRootDir == NULL) {
100 NaClLog(LOG_INFO, "Could not sanitize mount directory\n");
101 goto fail;
102 }
103 NaClRootDirLen = strlen(NaClRootDir);
104
105 /*
106 * Currently, mounting at '/' is not allowed.
107 * This simplifies some path parsing issues later (for example, when
108 * creating a new file in the mounted directory).
109 */
110 if (NaClRootDirLen <= 1)
111 goto fail;
112 if (NaClRootDirLen >= NACL_CONFIG_PATH_MAX)
113 goto fail;
114 return 1;
115 fail:
116 free(NaClRootDir);
117 NaClRootDir = NULL;
118 NaClRootDirLen = 0;
119 return 0;
120 }
121 #else
122 #error Unsupported platform
123 #endif
124
NaClFileAccessEnabled(void)125 int NaClFileAccessEnabled(void) {
126 return NaClAclBypassChecks || (NaClRootDir != NULL);
127 }
128
NaClHighResolutionTimerEnabled(void)129 int NaClHighResolutionTimerEnabled(void) {
130 return NaClAclBypassChecks;
131 }
132
NaClSysGetpid(struct NaClAppThread * natp)133 int32_t NaClSysGetpid(struct NaClAppThread *natp) {
134 int32_t pid;
135 UNREFERENCED_PARAMETER(natp);
136
137 if (NaClAclBypassChecks) {
138 pid = GETPID();
139 } else {
140 pid = -NACL_ABI_ENOSYS;
141 }
142 NaClLog(4, "NaClSysGetpid: returning %d\n", pid);
143
144 return pid;
145 }
146
NaClSysExit(struct NaClAppThread * natp,int status)147 int32_t NaClSysExit(struct NaClAppThread *natp,
148 int status) {
149 struct NaClApp *nap = natp->nap;
150
151 NaClLog(1, "Exit syscall handler: %d\n", status);
152
153 (void) NaClReportExitStatus(nap, NACL_ABI_W_EXITCODE(status, 0));
154
155 NaClAppThreadTeardown(natp);
156 /* NOTREACHED */
157 return -NACL_ABI_EINVAL;
158 }
159
NaClSysThreadExit(struct NaClAppThread * natp,uint32_t stack_flag_addr)160 int32_t NaClSysThreadExit(struct NaClAppThread *natp,
161 uint32_t stack_flag_addr) {
162 uint32_t zero = 0;
163
164 NaClLog(4, "NaClSysThreadExit(0x%08"NACL_PRIxPTR", "
165 "0x%08"NACL_PRIx32"\n",
166 (uintptr_t) natp, stack_flag_addr);
167 /*
168 * NB: NaClThreads are never joinable, but the abstraction for NaClApps
169 * are.
170 */
171
172 if (0 != stack_flag_addr) {
173 if (!NaClCopyOutToUser(natp->nap, (uintptr_t) stack_flag_addr,
174 &zero, sizeof zero)) {
175 NaClLog(4, "NaClSysThreadExit: ignoring invalid stack_flag_addr\n");
176 }
177 }
178
179 NaClAppThreadTeardown(natp);
180 /* NOTREACHED */
181 return -NACL_ABI_EINVAL;
182 }
183
NaClSysTlsInit(struct NaClAppThread * natp,uint32_t thread_ptr)184 int32_t NaClSysTlsInit(struct NaClAppThread *natp,
185 uint32_t thread_ptr) {
186 int32_t retval = -NACL_ABI_EINVAL;
187 uintptr_t sys_tls;
188
189 NaClLog(3,
190 ("Entered NaClSysTlsInit(0x%08"NACL_PRIxPTR
191 ", 0x%08"NACL_PRIxPTR")\n"),
192 (uintptr_t) natp, (uintptr_t) thread_ptr);
193
194 /* Verify that the address in the app's range and translated from
195 * nacl module address to service runtime address - a nop on ARM
196 */
197 sys_tls = NaClUserToSysAddrRange(natp->nap, thread_ptr, 4);
198 NaClLog(4,
199 "NaClSysTlsInit: thread_ptr 0x%"NACL_PRIx32
200 ", sys_tls 0x%"NACL_PRIxPTR"\n",
201 thread_ptr, sys_tls);
202 if (kNaClBadAddress == sys_tls) {
203 retval = -NACL_ABI_EFAULT;
204 goto cleanup;
205 }
206
207 NaClTlsSetTlsValue1(natp, thread_ptr);
208 retval = 0;
209 cleanup:
210 return retval;
211 }
212
NaClSysThreadCreate(struct NaClAppThread * natp,uint32_t prog_ctr,uint32_t stack_ptr,uint32_t thread_ptr,uint32_t second_thread_ptr)213 int32_t NaClSysThreadCreate(struct NaClAppThread *natp,
214 uint32_t prog_ctr,
215 uint32_t stack_ptr,
216 uint32_t thread_ptr,
217 uint32_t second_thread_ptr) {
218 struct NaClApp *nap = natp->nap;
219 int32_t retval = -NACL_ABI_EINVAL;
220 uintptr_t sys_tls;
221 uintptr_t sys_stack;
222
223 NaClLog(3,
224 ("Entered NaClSysThreadCreate(0x%08"NACL_PRIxPTR
225 " pc=0x%08"NACL_PRIx32", sp=0x%08"NACL_PRIx32", thread_ptr=0x%08"
226 NACL_PRIx32")\n"),
227 (uintptr_t) natp, prog_ctr, stack_ptr, thread_ptr);
228
229 if (!NaClIsValidJumpTarget(nap, prog_ctr)) {
230 NaClLog(LOG_ERROR, "NaClSysThreadCreate: Bad function pointer\n");
231 retval = -NACL_ABI_EFAULT;
232 goto cleanup;
233 }
234
235 /* Align the stack pointer. */
236 stack_ptr = ((stack_ptr + NACL_STACK_PAD_BELOW_ALIGN)
237 & ~NACL_STACK_ALIGN_MASK) - NACL_STACK_PAD_BELOW_ALIGN
238 - NACL_STACK_ARGS_SIZE;
239
240 sys_stack = NaClUserToSysAddr(nap, stack_ptr);
241 if (kNaClBadAddress == sys_stack) {
242 NaClLog(LOG_ERROR, "bad stack\n");
243 retval = -NACL_ABI_EFAULT;
244 goto cleanup;
245 }
246 sys_tls = NaClUserToSysAddrRange(nap, thread_ptr, 4);
247 if (kNaClBadAddress == sys_tls) {
248 NaClLog(LOG_ERROR, "bad TLS pointer\n");
249 retval = -NACL_ABI_EFAULT;
250 goto cleanup;
251 }
252
253 NaClVmHoleWaitToStartThread(nap);
254
255 retval = NaClCreateAdditionalThread(nap,
256 prog_ctr,
257 sys_stack,
258 thread_ptr,
259 second_thread_ptr);
260
261 cleanup:
262 return retval;
263 }
264
265 /*
266 * This is not used on x86-64 and its functionality is replaced by
267 * NaClGetTlsFastPath1 (see nacl_syscall_64.S).
268 */
NaClSysTlsGet(struct NaClAppThread * natp)269 int32_t NaClSysTlsGet(struct NaClAppThread *natp) {
270 return NaClTlsGetTlsValue1(natp);
271 }
272
NaClSysSecondTlsSet(struct NaClAppThread * natp,uint32_t new_value)273 int32_t NaClSysSecondTlsSet(struct NaClAppThread *natp,
274 uint32_t new_value) {
275 NaClTlsSetTlsValue2(natp, new_value);
276 return 0;
277 }
278
279 /*
280 * This is not used on x86-64 and its functionality is replaced by
281 * NaClGetTlsFastPath2 (see nacl_syscall_64.S).
282 */
NaClSysSecondTlsGet(struct NaClAppThread * natp)283 int32_t NaClSysSecondTlsGet(struct NaClAppThread *natp) {
284 return NaClTlsGetTlsValue2(natp);
285 }
286
NaClSysThreadNice(struct NaClAppThread * natp,const int nice)287 int NaClSysThreadNice(struct NaClAppThread *natp,
288 const int nice) {
289 /* Note: implementation of nacl_thread_nice is OS dependent. */
290 UNREFERENCED_PARAMETER(natp);
291 return nacl_thread_nice(nice);
292 }
293
NaClSysMutexCreate(struct NaClAppThread * natp)294 int32_t NaClSysMutexCreate(struct NaClAppThread *natp) {
295 struct NaClApp *nap = natp->nap;
296 int32_t retval = -NACL_ABI_EINVAL;
297 struct NaClDescMutex *desc;
298
299 NaClLog(3,
300 ("Entered NaClSysMutexCreate(0x%08"NACL_PRIxPTR")\n"),
301 (uintptr_t) natp);
302
303 desc = malloc(sizeof(*desc));
304
305 if (!desc || !NaClDescMutexCtor(desc)) {
306 retval = -NACL_ABI_ENOMEM;
307 goto cleanup;
308 }
309
310 retval = NaClAppSetDescAvail(nap, (struct NaClDesc *) desc);
311 desc = NULL;
312 cleanup:
313 free(desc);
314 NaClLog(3,
315 ("NaClSysMutexCreate(0x%08"NACL_PRIxPTR") = %d\n"),
316 (uintptr_t) natp, retval);
317 return retval;
318 }
319
NaClSysMutexLock(struct NaClAppThread * natp,int32_t mutex_handle)320 int32_t NaClSysMutexLock(struct NaClAppThread *natp,
321 int32_t mutex_handle) {
322 struct NaClApp *nap = natp->nap;
323 int32_t retval = -NACL_ABI_EINVAL;
324 struct NaClDesc *desc;
325
326 NaClLog(3,
327 ("Entered NaClSysMutexLock(0x%08"NACL_PRIxPTR", %d)\n"),
328 (uintptr_t) natp, mutex_handle);
329
330 desc = NaClAppGetDesc(nap, mutex_handle);
331
332 if (NULL == desc) {
333 retval = -NACL_ABI_EBADF;
334 goto cleanup;
335 }
336
337 retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Lock)(desc);
338 NaClDescUnref(desc);
339
340 cleanup:
341 return retval;
342 }
343
NaClSysMutexUnlock(struct NaClAppThread * natp,int32_t mutex_handle)344 int32_t NaClSysMutexUnlock(struct NaClAppThread *natp,
345 int32_t mutex_handle) {
346 struct NaClApp *nap = natp->nap;
347 int32_t retval = -NACL_ABI_EINVAL;
348 struct NaClDesc *desc;
349
350 NaClLog(3,
351 ("Entered NaClSysMutexUnlock(0x%08"NACL_PRIxPTR", %d)\n"),
352 (uintptr_t) natp, mutex_handle);
353
354 desc = NaClAppGetDesc(nap, mutex_handle);
355
356 if (NULL == desc) {
357 retval = -NACL_ABI_EBADF;
358 goto cleanup;
359 }
360
361 retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Unlock)(desc);
362 NaClDescUnref(desc);
363
364 cleanup:
365 return retval;
366 }
367
NaClSysMutexTrylock(struct NaClAppThread * natp,int32_t mutex_handle)368 int32_t NaClSysMutexTrylock(struct NaClAppThread *natp,
369 int32_t mutex_handle) {
370 struct NaClApp *nap = natp->nap;
371 int32_t retval = -NACL_ABI_EINVAL;
372 struct NaClDesc *desc;
373
374 NaClLog(3,
375 ("Entered NaClSysMutexTrylock(0x%08"NACL_PRIxPTR", %d)\n"),
376 (uintptr_t) natp, mutex_handle);
377
378 desc = NaClAppGetDesc(nap, mutex_handle);
379
380 if (NULL == desc) {
381 retval = -NACL_ABI_EBADF;
382 goto cleanup;
383 }
384
385 retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->TryLock)(desc);
386 NaClDescUnref(desc);
387
388 cleanup:
389 return retval;
390 }
391
NaClSysCondCreate(struct NaClAppThread * natp)392 int32_t NaClSysCondCreate(struct NaClAppThread *natp) {
393 struct NaClApp *nap = natp->nap;
394 int32_t retval = -NACL_ABI_EINVAL;
395 struct NaClDescCondVar *desc;
396
397 NaClLog(3,
398 ("Entered NaClSysCondCreate(0x%08"NACL_PRIxPTR")\n"),
399 (uintptr_t) natp);
400
401 desc = malloc(sizeof(*desc));
402
403 if (!desc || !NaClDescCondVarCtor(desc)) {
404 retval = -NACL_ABI_ENOMEM;
405 goto cleanup;
406 }
407
408 retval = NaClAppSetDescAvail(nap, (struct NaClDesc *)desc);
409 desc = NULL;
410 cleanup:
411 free(desc);
412 NaClLog(3,
413 ("NaClSysCondCreate(0x%08"NACL_PRIxPTR") = %d\n"),
414 (uintptr_t) natp, retval);
415 return retval;
416 }
417
NaClSysCondWait(struct NaClAppThread * natp,int32_t cond_handle,int32_t mutex_handle)418 int32_t NaClSysCondWait(struct NaClAppThread *natp,
419 int32_t cond_handle,
420 int32_t mutex_handle) {
421 struct NaClApp *nap = natp->nap;
422 int32_t retval = -NACL_ABI_EINVAL;
423 struct NaClDesc *cv_desc;
424 struct NaClDesc *mutex_desc;
425
426 NaClLog(3,
427 ("Entered NaClSysCondWait(0x%08"NACL_PRIxPTR", %d, %d)\n"),
428 (uintptr_t) natp, cond_handle, mutex_handle);
429
430 cv_desc = NaClAppGetDesc(nap, cond_handle);
431
432 if (NULL == cv_desc) {
433 retval = -NACL_ABI_EBADF;
434 goto cleanup;
435 }
436
437 mutex_desc = NaClAppGetDesc(nap, mutex_handle);
438 if (NULL == mutex_desc) {
439 NaClDescUnref(cv_desc);
440 retval = -NACL_ABI_EBADF;
441 goto cleanup;
442 }
443
444 retval = (*((struct NaClDescVtbl const *) cv_desc->base.vtbl)->
445 Wait)(cv_desc, mutex_desc);
446 NaClDescUnref(cv_desc);
447 NaClDescUnref(mutex_desc);
448
449 cleanup:
450 return retval;
451 }
452
NaClSysCondSignal(struct NaClAppThread * natp,int32_t cond_handle)453 int32_t NaClSysCondSignal(struct NaClAppThread *natp,
454 int32_t cond_handle) {
455 struct NaClApp *nap = natp->nap;
456 int32_t retval = -NACL_ABI_EINVAL;
457 struct NaClDesc *desc;
458
459 NaClLog(3,
460 ("Entered NaClSysCondSignal(0x%08"NACL_PRIxPTR", %d)\n"),
461 (uintptr_t) natp, cond_handle);
462
463 desc = NaClAppGetDesc(nap, cond_handle);
464
465 if (NULL == desc) {
466 retval = -NACL_ABI_EBADF;
467 goto cleanup;
468 }
469
470 retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Signal)(desc);
471 NaClDescUnref(desc);
472 cleanup:
473 return retval;
474 }
475
NaClSysCondBroadcast(struct NaClAppThread * natp,int32_t cond_handle)476 int32_t NaClSysCondBroadcast(struct NaClAppThread *natp,
477 int32_t cond_handle) {
478 struct NaClApp *nap = natp->nap;
479 struct NaClDesc *desc;
480 int32_t retval = -NACL_ABI_EINVAL;
481
482 NaClLog(3,
483 ("Entered NaClSysCondBroadcast(0x%08"NACL_PRIxPTR", %d)\n"),
484 (uintptr_t) natp, cond_handle);
485
486 desc = NaClAppGetDesc(nap, cond_handle);
487
488 if (NULL == desc) {
489 retval = -NACL_ABI_EBADF;
490 goto cleanup;
491 }
492
493 retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Broadcast)(desc);
494 NaClDescUnref(desc);
495
496 cleanup:
497 return retval;
498 }
499
NaClSysCondTimedWaitAbs(struct NaClAppThread * natp,int32_t cond_handle,int32_t mutex_handle,uint32_t ts_addr)500 int32_t NaClSysCondTimedWaitAbs(struct NaClAppThread *natp,
501 int32_t cond_handle,
502 int32_t mutex_handle,
503 uint32_t ts_addr) {
504 struct NaClApp *nap = natp->nap;
505 int32_t retval = -NACL_ABI_EINVAL;
506 struct NaClDesc *cv_desc;
507 struct NaClDesc *mutex_desc;
508 struct nacl_abi_timespec trusted_ts;
509
510 NaClLog(3,
511 ("Entered NaClSysCondTimedWaitAbs(0x%08"NACL_PRIxPTR
512 ", %d, %d, 0x%08"NACL_PRIx32")\n"),
513 (uintptr_t) natp, cond_handle, mutex_handle, ts_addr);
514
515 if (!NaClCopyInFromUser(nap, &trusted_ts, ts_addr, sizeof trusted_ts)) {
516 retval = -NACL_ABI_EFAULT;
517 goto cleanup;
518 }
519 /* TODO(gregoryd): validate ts - do we have a limit for time to wait? */
520
521 cv_desc = NaClAppGetDesc(nap, cond_handle);
522 if (NULL == cv_desc) {
523 retval = -NACL_ABI_EBADF;
524 goto cleanup;
525 }
526
527 mutex_desc = NaClAppGetDesc(nap, mutex_handle);
528 if (NULL == mutex_desc) {
529 NaClDescUnref(cv_desc);
530 retval = -NACL_ABI_EBADF;
531 goto cleanup;
532 }
533
534 retval = (*((struct NaClDescVtbl const *) cv_desc->base.vtbl)->
535 TimedWaitAbs)(cv_desc,
536 mutex_desc,
537 &trusted_ts);
538 NaClDescUnref(cv_desc);
539 NaClDescUnref(mutex_desc);
540 cleanup:
541 return retval;
542 }
543
NaClSysSemCreate(struct NaClAppThread * natp,int32_t init_value)544 int32_t NaClSysSemCreate(struct NaClAppThread *natp,
545 int32_t init_value) {
546 struct NaClApp *nap = natp->nap;
547 int32_t retval = -NACL_ABI_EINVAL;
548 struct NaClDescSemaphore *desc;
549
550 NaClLog(3,
551 ("Entered NaClSysSemCreate(0x%08"NACL_PRIxPTR
552 ", %d)\n"),
553 (uintptr_t) natp, init_value);
554
555 desc = malloc(sizeof(*desc));
556
557 if (!desc || !NaClDescSemaphoreCtor(desc, init_value)) {
558 retval = -NACL_ABI_ENOMEM;
559 goto cleanup;
560 }
561
562 retval = NaClAppSetDescAvail(nap, (struct NaClDesc *) desc);
563 desc = NULL;
564 cleanup:
565 free(desc);
566 return retval;
567 }
568
569
NaClSysSemWait(struct NaClAppThread * natp,int32_t sem_handle)570 int32_t NaClSysSemWait(struct NaClAppThread *natp,
571 int32_t sem_handle) {
572 struct NaClApp *nap = natp->nap;
573 int32_t retval = -NACL_ABI_EINVAL;
574 struct NaClDesc *desc;
575
576 NaClLog(3,
577 ("Entered NaClSysSemWait(0x%08"NACL_PRIxPTR
578 ", %d)\n"),
579 (uintptr_t) natp, sem_handle);
580
581 desc = NaClAppGetDesc(nap, sem_handle);
582
583 if (NULL == desc) {
584 retval = -NACL_ABI_EBADF;
585 goto cleanup;
586 }
587
588 /*
589 * TODO(gregoryd): we have to decide on the syscall API: do we
590 * switch to read/write/ioctl API or do we stay with the more
591 * detailed API. Anyway, using a single syscall for waiting on all
592 * synchronization objects makes sense.
593 */
594 retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->SemWait)(desc);
595 NaClDescUnref(desc);
596 cleanup:
597 return retval;
598 }
599
NaClSysSemPost(struct NaClAppThread * natp,int32_t sem_handle)600 int32_t NaClSysSemPost(struct NaClAppThread *natp,
601 int32_t sem_handle) {
602 struct NaClApp *nap = natp->nap;
603 int32_t retval = -NACL_ABI_EINVAL;
604 struct NaClDesc *desc;
605
606 NaClLog(3,
607 ("Entered NaClSysSemPost(0x%08"NACL_PRIxPTR
608 ", %d)\n"),
609 (uintptr_t) natp, sem_handle);
610
611 desc = NaClAppGetDesc(nap, sem_handle);
612
613 if (NULL == desc) {
614 retval = -NACL_ABI_EBADF;
615 goto cleanup;
616 }
617
618 retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Post)(desc);
619 NaClDescUnref(desc);
620 cleanup:
621 return retval;
622 }
623
NaClSysSemGetValue(struct NaClAppThread * natp,int32_t sem_handle)624 int32_t NaClSysSemGetValue(struct NaClAppThread *natp,
625 int32_t sem_handle) {
626 struct NaClApp *nap = natp->nap;
627 int32_t retval = -NACL_ABI_EINVAL;
628 struct NaClDesc *desc;
629
630 NaClLog(3,
631 ("Entered NaClSysSemGetValue(0x%08"NACL_PRIxPTR
632 ", %d)\n"),
633 (uintptr_t) natp, sem_handle);
634
635 desc = NaClAppGetDesc(nap, sem_handle);
636
637 if (NULL == desc) {
638 retval = -NACL_ABI_EBADF;
639 goto cleanup;
640 }
641
642 retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->GetValue)(desc);
643 NaClDescUnref(desc);
644 cleanup:
645 return retval;
646 }
647
NaClSysNanosleep(struct NaClAppThread * natp,uint32_t req_addr,uint32_t rem_addr)648 int32_t NaClSysNanosleep(struct NaClAppThread *natp,
649 uint32_t req_addr,
650 uint32_t rem_addr) {
651 struct NaClApp *nap = natp->nap;
652 struct nacl_abi_timespec t_sleep;
653 struct nacl_abi_timespec t_rem;
654 struct nacl_abi_timespec *remptr;
655 int retval = -NACL_ABI_EINVAL;
656
657 NaClLog(3,
658 ("Entered NaClSysNanosleep(0x%08"NACL_PRIxPTR
659 ", 0x%08"NACL_PRIx32", 0x%08"NACL_PRIx32"x)\n"),
660 (uintptr_t) natp, req_addr, rem_addr);
661
662 /* do the check before we sleep */
663 if (0 != rem_addr && kNaClBadAddress ==
664 NaClUserToSysAddrRange(nap, rem_addr, sizeof *remptr)) {
665 retval = -NACL_ABI_EFAULT;
666 goto cleanup;
667 }
668
669 if (!NaClCopyInFromUser(nap, &t_sleep, req_addr, sizeof t_sleep)) {
670 retval = -NACL_ABI_EFAULT;
671 goto cleanup;
672 }
673
674 remptr = (0 == rem_addr) ? NULL : &t_rem;
675 /* NULL != remptr \equiv NULL != rem */
676
677 /*
678 * We assume that we do not need to normalize the time request values.
679 *
680 * If bogus values can cause the underlying OS to get into trouble,
681 * then we need more checking here.
682 */
683 NaClLog(4, "NaClSysNanosleep(time = %"NACL_PRId64".%09"NACL_PRId64" S)\n",
684 (int64_t) t_sleep.tv_sec, (int64_t) t_sleep.tv_nsec);
685 retval = NaClNanosleep(&t_sleep, remptr);
686 NaClLog(4, "NaClNanosleep returned %d\n", retval);
687
688 if (-EINTR == retval && 0 != rem_addr &&
689 !NaClCopyOutToUser(nap, rem_addr, remptr, sizeof *remptr)) {
690 NaClLog(LOG_FATAL, "NaClSysNanosleep: check rem failed at copyout\n");
691 }
692
693 cleanup:
694 NaClLog(4, "nanosleep done.\n");
695 return retval;
696 }
697
NaClSysSchedYield(struct NaClAppThread * natp)698 int32_t NaClSysSchedYield(struct NaClAppThread *natp) {
699 UNREFERENCED_PARAMETER(natp);
700
701 NaClThreadYield();
702 return 0;
703 }
704
NaClSysSysconf(struct NaClAppThread * natp,int32_t name,uint32_t result_addr)705 int32_t NaClSysSysconf(struct NaClAppThread *natp,
706 int32_t name,
707 uint32_t result_addr) {
708 struct NaClApp *nap = natp->nap;
709 int32_t retval = -NACL_ABI_EINVAL;
710 int32_t result_value;
711
712 NaClLog(3,
713 ("Entered NaClSysSysconf(%08"NACL_PRIxPTR
714 "x, %d, 0x%08"NACL_PRIx32")\n"),
715 (uintptr_t) natp, name, result_addr);
716
717 switch (name) {
718 case NACL_ABI__SC_NPROCESSORS_ONLN: {
719 #if NACL_WINDOWS
720 static int32_t number_of_workers = 0;
721 if (0 == number_of_workers) {
722 SYSTEM_INFO si;
723 GetSystemInfo(&si);
724 number_of_workers = (int32_t) si.dwNumberOfProcessors;
725 }
726 result_value = number_of_workers;
727 #elif NACL_LINUX || NACL_OSX
728 if (-1 == nap->sc_nprocessors_onln) {
729 /* Unable to get the number of processors at startup. */
730 goto cleanup;
731 }
732 result_value = nap->sc_nprocessors_onln;
733 #else
734 #error Unsupported platform
735 #endif
736 break;
737 }
738 case NACL_ABI__SC_PAGESIZE: {
739 result_value = 1 << 16; /* always 64k pages */
740 break;
741 }
742 case NACL_ABI__SC_NACL_FILE_ACCESS_ENABLED: {
743 result_value = NaClFileAccessEnabled();
744 break;
745 }
746 case NACL_ABI__SC_NACL_LIST_MAPPINGS_ENABLED: {
747 result_value = nap->enable_list_mappings;
748 break;
749 }
750 case NACL_ABI__SC_NACL_PNACL_MODE: {
751 result_value = nap->pnacl_mode;
752 break;
753 }
754 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
755 case NACL_ABI__SC_NACL_CPU_FEATURE_X86: {
756 NaClCPUFeaturesX86 *features = (NaClCPUFeaturesX86 *) nap->cpu_features;
757 if (nap->pnacl_mode) {
758 goto cleanup;
759 }
760 /*
761 * The result value is modelled after the first three bits of XCR0.
762 */
763 result_value =
764 (NaClGetCPUFeatureX86(features, NaClCPUFeatureX86_x87) << 0) |
765 (NaClGetCPUFeatureX86(features, NaClCPUFeatureX86_SSE) << 1) |
766 (NaClGetCPUFeatureX86(features, NaClCPUFeatureX86_AVX) << 2);
767 break;
768 }
769 #endif
770 default: {
771 retval = -NACL_ABI_EINVAL;
772 goto cleanup;
773 }
774 }
775 if (!NaClCopyOutToUser(nap, result_addr, &result_value,
776 sizeof result_value)) {
777 retval = -NACL_ABI_EFAULT;
778 goto cleanup;
779 }
780 retval = 0;
781 cleanup:
782 return retval;
783 }
784
NaClSysTestInfoLeak(struct NaClAppThread * natp)785 int32_t NaClSysTestInfoLeak(struct NaClAppThread *natp) {
786 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
787 /*
788 * Put some interesting bits into the x87 and SSE registers.
789 */
790 union fxsave {
791 char buf[512];
792 struct {
793 uint16_t fcw;
794 uint16_t fsw;
795 uint16_t ftw;
796 uint16_t fop;
797 union {
798 struct {
799 uint64_t rip;
800 uint64_t rdp;
801 } x64;
802 struct {
803 uint32_t fpu_ip;
804 uint32_t cs;
805 uint32_t fpu_dp;
806 uint32_t ds;
807 } ia32;
808 } bitness;
809 uint32_t mxcsr;
810 uint32_t mxcsr_mask;
811 struct {
812 uint8_t st[10];
813 uint8_t reserved[6];
814 } st_space[8];
815 uint32_t xmm_space[64];
816 } fxsave;
817 };
818
819 static const char tenbytes[10] = "SecretBit";
820 static const char manybytes[256] =
821 "Highly sensitive information must not be leaked to untrusted code!\n"
822 "xyzzy\nplugh\nYou are likely to be eaten by a grue.\n"
823 "When in the Course of human events it becomes necessary for one people"
824 " to dissolve the political bands which have connected them with ...\n";
825
826 # ifdef __GNUC__
827 union fxsave u __attribute__((aligned(16)));
828 # elif NACL_WINDOWS
829 __declspec(align(16)) union fxsave u;
830 # else
831 # error Unsupported platform
832 # endif
833
834 int i;
835
836 # ifdef __GNUC__
837 __asm__("fxsave %0" : "=m" (u));
838 # elif NACL_WINDOWS
839 # if NACL_BUILD_SUBARCH == 64
840 NaClDoFxsave(&u);
841 # else
842 __asm {
843 fxsave u
844 };
845 # endif
846 # else
847 # error Unsupported platform
848 # endif
849
850 for (i = 0; i < 8; ++i)
851 memcpy(&u.fxsave.st_space[i], tenbytes, sizeof(tenbytes));
852
853 memcpy(u.fxsave.xmm_space, manybytes, sizeof(u.fxsave.xmm_space));
854
855 /*
856 * Set the MXCSR to an unlikely (but valid) value: all valid bits set.
857 * The mask is provided by the hardware to say which bits can be set
858 * (all others are reserved). The untrusted test code (in
859 * tests/infoleak/test_infoleak.c) sets MXCSR to zero before
860 * making this system call so this value ensures that the test
861 * actually verifies the behavior of the syscall return path.
862 */
863 u.fxsave.mxcsr = u.fxsave.mxcsr_mask;
864
865 # ifdef __GNUC__
866 __asm__ volatile("fxrstor %0" :: "m" (u));
867 # elif NACL_WINDOWS
868 # if NACL_BUILD_SUBARCH == 64
869 NaClDoFxrstor(&u);
870 # else
871 __asm {
872 fxrstor u
873 };
874 # endif
875 # else
876 # error Unsupported platform
877 # endif
878
879 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
880 /*
881 * Put some interesting bits into the VFP registers.
882 */
883
884 static const char manybytes[64] =
885 "Sensitive information must not be leaked to untrusted code!!!!\n";
886
887 __asm__ volatile("vldm %0, {d0-d7}" :: "r" (manybytes) :
888 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7");
889
890 /*
891 * __builtin_arm_set_fpscr is not available yet in gcc (not even in 4.8)
892 * and clang doesn't know about the "vfpcc" register.
893 * TODO(sbc): Always use __builtin_arm_set_fpscr once we are using a
894 * version of gcc that supports it.
895 */
896 #ifdef __clang__
897 __builtin_arm_set_fpscr(0xdeadbeef);
898 #else
899 __asm__ volatile("fmxr fpscr, %0" :: "r" (0xdeadbeef) : "vfpcc");
900 #endif
901
902 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
903
904 static const char manybytes[128] =
905 "Sensitive information must not be leaked to untrusted code!!!\n"
906 "Where is Maletoth?\n";
907
908 __asm__ volatile("ldc1 $f0, 0(%0)\n"
909 "ldc1 $f2, 8(%0)\n"
910 "ldc1 $f4, 16(%0)\n"
911 "ldc1 $f6, 24(%0)\n"
912 "ldc1 $f8, 32(%0)\n"
913 "ldc1 $f10, 40(%0)\n"
914 "ldc1 $f12, 48(%0)\n"
915 "ldc1 $f14, 56(%0)\n"
916 "ldc1 $f16, 64(%0)\n"
917 "ldc1 $f18, 72(%0)\n"
918 : : "r" (manybytes)
919 : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
920 "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14",
921 "$f15", "$f16", "$f17", "$f18", "$f19");
922
923 #endif
924
925 UNREFERENCED_PARAMETER(natp);
926
927 return -NACL_ABI_ENOSYS;
928 }
929
930 /*
931 * This syscall is intended for testing NaCl's support for Breakpad
932 * crash reporting inside Chromium. When
933 * http://code.google.com/p/nativeclient/issues/detail?id=579 is
934 * addressed, we might put this syscall behind a flag. Until then,
935 * untrusted code can trigger Breakpad-reported crashes inside
936 * syscalls, so there is no benefit to restricting this syscall.
937 */
NaClSysTestCrash(struct NaClAppThread * natp,int crash_type)938 int32_t NaClSysTestCrash(struct NaClAppThread *natp, int crash_type) {
939 /*
940 * Despite being volatile, the Apple system compiler, llvm-gcc, still
941 * optimizes the null pointer dereference into an illegal instruction when
942 * written as a one-liner. That interferes with tests that expect precisely
943 * a SIGSEGV, because they'll see a SIGILL instead.
944 */
945 volatile int *volatile p = 0;
946 UNREFERENCED_PARAMETER(natp);
947
948 switch (crash_type) {
949 case NACL_TEST_CRASH_MEMORY:
950 *p = 0;
951 break;
952 case NACL_TEST_CRASH_LOG_FATAL:
953 NaClLog(LOG_FATAL, "NaClSysTestCrash: This is a test error\n");
954 break;
955 case NACL_TEST_CRASH_CHECK_FAILURE:
956 CHECK(0);
957 break;
958 }
959 return -NACL_ABI_EINVAL;
960 }
961
962 /*
963 * This syscall does not take a "tz" (timezone) argument. tz is not
964 * supported in linux, nor is it supported by glibc, since tzset(3) and the
965 * zoneinfo file should be used instead.
966 */
NaClSysGetTimeOfDay(struct NaClAppThread * natp,uint32_t tv_addr)967 int32_t NaClSysGetTimeOfDay(struct NaClAppThread *natp,
968 uint32_t tv_addr) {
969 int retval;
970 struct nacl_abi_timeval now;
971
972 NaClLog(3,
973 ("Entered NaClSysGetTimeOfDay(%08"NACL_PRIxPTR
974 ", 0x%08"NACL_PRIx32")\n"),
975 (uintptr_t) natp, tv_addr);
976
977 /* memset() call is required to clear padding in struct nacl_abi_timeval. */
978 memset(&now, 0, sizeof(now));
979 retval = NaClGetTimeOfDay(&now);
980 if (0 != retval) {
981 return retval;
982 }
983 #if !NACL_WINDOWS
984 /*
985 * Coarsen the time to the same level we get on Windows -
986 * 10 microseconds.
987 */
988 if (!NaClHighResolutionTimerEnabled()) {
989 now.nacl_abi_tv_usec = (now.nacl_abi_tv_usec / 10) * 10;
990 }
991 #endif
992 CHECK(now.nacl_abi_tv_usec >= 0);
993 CHECK(now.nacl_abi_tv_usec < NACL_MICROS_PER_UNIT);
994 if (!NaClCopyOutToUser(natp->nap, tv_addr, &now, sizeof now)) {
995 return -NACL_ABI_EFAULT;
996 }
997 return 0;
998 }
999
NaClIsValidClockId(int clk_id)1000 static int NaClIsValidClockId(int clk_id) {
1001 switch (clk_id) {
1002 case NACL_ABI_CLOCK_REALTIME:
1003 case NACL_ABI_CLOCK_MONOTONIC:
1004 case NACL_ABI_CLOCK_PROCESS_CPUTIME_ID:
1005 case NACL_ABI_CLOCK_THREAD_CPUTIME_ID:
1006 return 1;
1007 }
1008 return 0;
1009 }
1010
NaClSysClockGetCommon(struct NaClAppThread * natp,int clk_id,uint32_t ts_addr,int (* timefunc)(nacl_clockid_t clk_id,struct nacl_abi_timespec * tp),int null_ok)1011 static int32_t NaClSysClockGetCommon(struct NaClAppThread *natp,
1012 int clk_id,
1013 uint32_t ts_addr,
1014 int (*timefunc)(
1015 nacl_clockid_t clk_id,
1016 struct nacl_abi_timespec *tp),
1017 int null_ok) {
1018 struct NaClApp *nap = natp->nap;
1019 int retval = -NACL_ABI_EINVAL;
1020 struct nacl_abi_timespec out_buf;
1021
1022 if (!NaClIsValidClockId(clk_id)) {
1023 goto done;
1024 }
1025 /* memset() call is required to clear padding in struct nacl_abi_timespec. */
1026 memset(&out_buf, 0, sizeof(out_buf));
1027 retval = (*timefunc)((nacl_clockid_t) clk_id, &out_buf);
1028 if (0 == retval) {
1029 if (ts_addr == 0 ? !null_ok :
1030 !NaClCopyOutToUser(nap, (uintptr_t) ts_addr,
1031 &out_buf, sizeof out_buf)) {
1032 retval = -NACL_ABI_EFAULT;
1033 }
1034 }
1035 done:
1036 return retval;
1037 }
1038
NaClSysClockGetRes(struct NaClAppThread * natp,int clk_id,uint32_t tsp)1039 int32_t NaClSysClockGetRes(struct NaClAppThread *natp,
1040 int clk_id,
1041 uint32_t tsp) {
1042 return NaClSysClockGetCommon(natp, clk_id, (uintptr_t) tsp,
1043 NaClClockGetRes, 1);
1044 }
1045
NaClSysClockGetTime(struct NaClAppThread * natp,int clk_id,uint32_t tsp)1046 int32_t NaClSysClockGetTime(struct NaClAppThread *natp,
1047 int clk_id,
1048 uint32_t tsp) {
1049 return NaClSysClockGetCommon(natp, clk_id, (uintptr_t) tsp,
1050 NaClClockGetTime, 0);
1051 }
1052