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 22003 : void NaClAddSyscall(int num, int32_t (*fn)(struct NaClAppThread *)) {
71 22003 : if (nacl_syscall[num].handler != &NaClSysNotImplementedDecoder) {
72 0 : NaClLog(LOG_FATAL, "Duplicate syscall number %d\n", num);
73 0 : }
74 22003 : nacl_syscall[num].handler = fn;
75 22003 : }
76 :
77 1412585 : int32_t NaClSysNull(struct NaClAppThread *natp) {
78 2825170 : UNREFERENCED_PARAMETER(natp);
79 1412585 : return 0;
80 : }
81 :
82 : int NaClAclBypassChecks = 0;
83 :
84 : void NaClInsecurelyBypassAllAclChecks(void) {
85 261 : NaClLog(LOG_WARNING, "BYPASSING ALL ACL CHECKS\n");
86 261 : NaClAclBypassChecks = 1;
87 261 : }
88 :
89 : int NaClHighResolutionTimerEnabled(void) {
90 13 : return NaClAclBypassChecks;
91 : }
92 :
93 6 : int32_t NaClSysGetpid(struct NaClAppThread *natp) {
94 6 : int32_t pid;
95 12 : UNREFERENCED_PARAMETER(natp);
96 :
97 6 : if (NaClAclBypassChecks) {
98 6 : pid = GETPID();
99 6 : } else {
100 0 : pid = -NACL_ABI_ENOSYS;
101 : }
102 6 : NaClLog(4, "NaClSysGetpid: returning %d\n", pid);
103 :
104 6 : return pid;
105 : }
106 :
107 243 : int32_t NaClSysExit(struct NaClAppThread *natp,
108 243 : int status) {
109 243 : struct NaClApp *nap = natp->nap;
110 :
111 243 : NaClLog(1, "Exit syscall handler: %d\n", status);
112 :
113 243 : (void) NaClReportExitStatus(nap, NACL_ABI_W_EXITCODE(status, 0));
114 :
115 243 : NaClAppThreadTeardown(natp);
116 : /* NOTREACHED */
117 243 : return -NACL_ABI_EINVAL;
118 : }
119 :
120 19704 : int32_t NaClSysThreadExit(struct NaClAppThread *natp,
121 19704 : int32_t *stack_flag) {
122 19704 : uint32_t zero = 0;
123 :
124 19704 : 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 19704 : if (NULL != stack_flag) {
134 19703 : NaClLog(4,
135 : "NaClSysThreadExit: stack_flag is %"NACL_PRIxPTR"\n",
136 : (uintptr_t) stack_flag);
137 19703 : 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 0 : }
144 19703 : }
145 :
146 19704 : NaClAppThreadTeardown(natp);
147 : /* NOTREACHED */
148 19704 : return -NACL_ABI_EINVAL;
149 : }
150 :
151 4 : int32_t NaClSysNameService(struct NaClAppThread *natp,
152 4 : int32_t *desc_addr) {
153 4 : struct NaClApp *nap = natp->nap;
154 4 : int32_t retval = -NACL_ABI_EINVAL;
155 4 : 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 4 : } else {
177 0 : retval = -NACL_ABI_EFAULT;
178 : }
179 4 : } 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 : 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 4 : }
198 :
199 : done:
200 4 : return retval;
201 : }
202 :
203 242 : int32_t NaClSysTlsInit(struct NaClAppThread *natp,
204 242 : uint32_t thread_ptr) {
205 242 : int32_t retval = -NACL_ABI_EINVAL;
206 242 : uintptr_t sys_tls;
207 :
208 242 : 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 242 : sys_tls = NaClUserToSysAddrRange(natp->nap, thread_ptr, 4);
217 242 : NaClLog(4,
218 : "NaClSysTlsInit: thread_ptr 0x%"NACL_PRIx32
219 : ", sys_tls 0x%"NACL_PRIxPTR"\n",
220 : thread_ptr, sys_tls);
221 242 : if (kNaClBadAddress == sys_tls) {
222 0 : retval = -NACL_ABI_EFAULT;
223 0 : goto cleanup;
224 : }
225 :
226 242 : NaClTlsSetTlsValue1(natp, thread_ptr);
227 242 : retval = 0;
228 : cleanup:
229 242 : return retval;
230 : }
231 :
232 20613 : int32_t NaClSysThreadCreate(struct NaClAppThread *natp,
233 20613 : void *prog_ctr,
234 20613 : uint32_t stack_ptr,
235 20613 : uint32_t thread_ptr,
236 20613 : uint32_t second_thread_ptr) {
237 20613 : struct NaClApp *nap = natp->nap;
238 20613 : int32_t retval = -NACL_ABI_EINVAL;
239 20613 : uintptr_t sys_tls;
240 20613 : uintptr_t sys_stack;
241 :
242 20613 : 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 20613 : 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 20611 : stack_ptr = ((stack_ptr + NACL_STACK_PAD_BELOW_ALIGN)
256 : & ~NACL_STACK_ALIGN_MASK) - NACL_STACK_PAD_BELOW_ALIGN
257 : - NACL_STACK_ARGS_SIZE;
258 :
259 20611 : sys_stack = NaClUserToSysAddr(nap, stack_ptr);
260 20611 : if (kNaClBadAddress == sys_stack) {
261 0 : NaClLog(LOG_ERROR, "bad stack\n");
262 0 : retval = -NACL_ABI_EFAULT;
263 0 : goto cleanup;
264 : }
265 20611 : sys_tls = NaClUserToSysAddrRange(nap, thread_ptr, 4);
266 20611 : 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 20611 : NaClVmHoleWaitToStartThread(nap);
273 :
274 20611 : retval = NaClCreateAdditionalThread(nap,
275 : (uintptr_t) prog_ctr,
276 : sys_stack,
277 : thread_ptr,
278 : second_thread_ptr);
279 :
280 : cleanup:
281 20613 : 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 0 : int32_t NaClSysTlsGet(struct NaClAppThread *natp) {
289 0 : return NaClTlsGetTlsValue1(natp);
290 : }
291 :
292 9 : int32_t NaClSysSecondTlsSet(struct NaClAppThread *natp,
293 9 : uint32_t new_value) {
294 9 : NaClTlsSetTlsValue2(natp, new_value);
295 9 : 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 0 : int32_t NaClSysSecondTlsGet(struct NaClAppThread *natp) {
303 0 : return NaClTlsGetTlsValue2(natp);
304 : }
305 :
306 0 : int NaClSysThreadNice(struct NaClAppThread *natp,
307 0 : const int nice) {
308 : /* Note: implementation of nacl_thread_nice is OS dependent. */
309 0 : 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 0 : 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 0 : int32_t mutex_handle) {
341 0 : struct NaClApp *nap = natp->nap;
342 0 : int32_t retval = -NACL_ABI_EINVAL;
343 0 : 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 0 : int32_t mutex_handle) {
365 0 : struct NaClApp *nap = natp->nap;
366 0 : int32_t retval = -NACL_ABI_EINVAL;
367 0 : 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 0 : int32_t mutex_handle) {
389 0 : struct NaClApp *nap = natp->nap;
390 0 : int32_t retval = -NACL_ABI_EINVAL;
391 0 : 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 0 : 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 0 : int32_t cond_handle,
439 0 : int32_t mutex_handle) {
440 0 : struct NaClApp *nap = natp->nap;
441 0 : int32_t retval = -NACL_ABI_EINVAL;
442 0 : struct NaClDesc *cv_desc;
443 0 : 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 : 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 0 : int32_t cond_handle) {
474 0 : struct NaClApp *nap = natp->nap;
475 0 : int32_t retval = -NACL_ABI_EINVAL;
476 0 : 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 0 : int32_t cond_handle) {
497 0 : struct NaClApp *nap = natp->nap;
498 0 : 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 0 : int32_t cond_handle,
521 0 : int32_t mutex_handle,
522 0 : struct nacl_abi_timespec *ts) {
523 0 : struct NaClApp *nap = natp->nap;
524 0 : int32_t retval = -NACL_ABI_EINVAL;
525 0 : struct NaClDesc *cv_desc;
526 0 : struct NaClDesc *mutex_desc;
527 0 : 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 : 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 0 : int32_t init_value) {
566 0 : struct NaClApp *nap = natp->nap;
567 0 : int32_t retval = -NACL_ABI_EINVAL;
568 0 : 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 0 : int32_t sem_handle) {
592 0 : struct NaClApp *nap = natp->nap;
593 0 : int32_t retval = -NACL_ABI_EINVAL;
594 0 : 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 0 : int32_t sem_handle) {
622 0 : struct NaClApp *nap = natp->nap;
623 0 : int32_t retval = -NACL_ABI_EINVAL;
624 0 : 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 0 : int32_t sem_handle) {
646 0 : struct NaClApp *nap = natp->nap;
647 0 : int32_t retval = -NACL_ABI_EINVAL;
648 0 : 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 73 : int32_t NaClSysNanosleep(struct NaClAppThread *natp,
669 73 : struct nacl_abi_timespec *req,
670 73 : struct nacl_abi_timespec *rem) {
671 73 : struct NaClApp *nap = natp->nap;
672 73 : struct nacl_abi_timespec t_sleep;
673 73 : struct nacl_abi_timespec t_rem;
674 73 : struct nacl_abi_timespec *remptr;
675 73 : int retval = -NACL_ABI_EINVAL;
676 :
677 73 : 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 73 : if (NULL != rem && kNaClBadAddress ==
684 56 : NaClUserToSysAddrRange(nap, (uintptr_t) rem, sizeof *rem)) {
685 0 : retval = -NACL_ABI_EFAULT;
686 0 : goto cleanup;
687 : }
688 :
689 73 : 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 213 : 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 69 : NaClLog(4, "NaClSysNanosleep(time = %"NACL_PRId64".%09"NACL_PRId64" S)\n",
705 : (int64_t) t_sleep.tv_sec, (int64_t) t_sleep.tv_nsec);
706 69 : 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 69 : }
713 :
714 : cleanup:
715 70 : NaClLog(4, "nanosleep done.\n");
716 70 : return retval;
717 : }
718 :
719 17648 : int32_t NaClSysSchedYield(struct NaClAppThread *natp) {
720 35296 : UNREFERENCED_PARAMETER(natp);
721 :
722 17648 : NaClThreadYield();
723 17648 : return 0;
724 : }
725 :
726 231 : int32_t NaClSysSysconf(struct NaClAppThread *natp,
727 231 : int32_t name,
728 231 : int32_t *result) {
729 231 : struct NaClApp *nap = natp->nap;
730 231 : int32_t retval = -NACL_ABI_EINVAL;
731 231 : int32_t result_value;
732 :
733 231 : 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 231 : 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 228 : result_value = 1 << 16; /* always 64k pages */
761 228 : 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 230 : if (!NaClCopyOutToUser(nap, (uintptr_t) result, &result_value,
781 : sizeof result_value)) {
782 0 : retval = -NACL_ABI_EFAULT;
783 0 : goto cleanup;
784 : }
785 230 : retval = 0;
786 : cleanup:
787 231 : 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 1 : 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 1 : 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 18 : for (i = 0; i < 8; ++i)
856 24 : 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 2 : 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 2 : 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 2 : volatile int *volatile p = 0;
940 4 : UNREFERENCED_PARAMETER(natp);
941 :
942 2 : switch (crash_type) {
943 : case NACL_TEST_CRASH_MEMORY:
944 2 : *p = 0;
945 2 : 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 0 : return -NACL_ABI_EINVAL;
954 : }
955 :
956 13 : int32_t NaClSysGetTimeOfDay(struct NaClAppThread *natp,
957 13 : struct nacl_abi_timeval *tv,
958 13 : struct nacl_abi_timezone *tz) {
959 13 : int retval;
960 13 : struct nacl_abi_timeval now;
961 :
962 26 : UNREFERENCED_PARAMETER(tz);
963 :
964 13 : 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 13 : retval = NaClGetTimeOfDay(&now);
978 13 : if (0 != retval) {
979 0 : return retval;
980 : }
981 : #if !NACL_WINDOWS
982 : /*
983 : * Coarsen the time to the same level we get on Windows -
984 : * 10 microseconds.
985 : */
986 13 : if (!NaClHighResolutionTimerEnabled()) {
987 0 : now.nacl_abi_tv_usec = (now.nacl_abi_tv_usec / 10) * 10;
988 0 : }
989 : #endif
990 39 : CHECK(now.nacl_abi_tv_usec >= 0);
991 39 : CHECK(now.nacl_abi_tv_usec < NACL_MICROS_PER_UNIT);
992 13 : if (!NaClCopyOutToUser(natp->nap, (uintptr_t) tv, &now, sizeof now)) {
993 0 : return -NACL_ABI_EFAULT;
994 : }
995 13 : return 0;
996 13 : }
997 :
998 706618 : static int NaClIsValidClockId(int clk_id) {
999 706618 : switch (clk_id) {
1000 : case NACL_ABI_CLOCK_REALTIME:
1001 : case NACL_ABI_CLOCK_MONOTONIC:
1002 : case NACL_ABI_CLOCK_PROCESS_CPUTIME_ID:
1003 : case NACL_ABI_CLOCK_THREAD_CPUTIME_ID:
1004 706618 : return 1;
1005 : }
1006 0 : return 0;
1007 706618 : }
1008 :
1009 706618 : static int32_t NaClSysClockGetCommon(struct NaClAppThread *natp,
1010 706618 : int clk_id,
1011 706618 : uint32_t ts_addr,
1012 706618 : int (*timefunc)(
1013 : nacl_clockid_t clk_id,
1014 : struct nacl_abi_timespec *tp),
1015 706618 : int null_ok) {
1016 706618 : struct NaClApp *nap = natp->nap;
1017 706618 : int retval = -NACL_ABI_EINVAL;
1018 706618 : struct nacl_abi_timespec out_buf;
1019 :
1020 706618 : if (!NaClIsValidClockId(clk_id)) {
1021 0 : goto done;
1022 : }
1023 706618 : retval = (*timefunc)((nacl_clockid_t) clk_id, &out_buf);
1024 706618 : if (0 == retval) {
1025 706622 : if (ts_addr == 0 ? !null_ok :
1026 706614 : !NaClCopyOutToUser(nap, (uintptr_t) ts_addr,
1027 : &out_buf, sizeof out_buf)) {
1028 0 : retval = -NACL_ABI_EFAULT;
1029 0 : }
1030 1413236 : }
1031 : done:
1032 706618 : return retval;
1033 : }
1034 :
1035 8 : int32_t NaClSysClockGetRes(struct NaClAppThread *natp,
1036 8 : int clk_id,
1037 8 : uint32_t tsp) {
1038 8 : return NaClSysClockGetCommon(natp, clk_id, (uintptr_t) tsp,
1039 : NaClClockGetRes, 1);
1040 : }
1041 :
1042 706610 : int32_t NaClSysClockGetTime(struct NaClAppThread *natp,
1043 706610 : int clk_id,
1044 706610 : uint32_t tsp) {
1045 706610 : return NaClSysClockGetCommon(natp, clk_id, (uintptr_t) tsp,
1046 : NaClClockGetTime, 0);
1047 : }
|