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