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