Tidy ups of mapping code
[nativeclient.git] / service_runtime / nacl_syscall_common.c
blobfc02ee0d880ec6f40f29e2b702cbe2cf26ca08bf
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl service run-time, non-platform specific system call helper routines.
36 #include <assert.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <string.h>
42 #include "native_client/include/portability.h"
44 #include "native_client/include/nacl_platform.h"
46 #include "native_client/service_runtime/nacl_syscall_common.h"
48 #include "native_client/service_runtime/nacl_app_thread.h"
50 #include "native_client/service_runtime/nacl_desc_base.h"
51 #include "native_client/service_runtime/nacl_desc_cond.h"
52 #include "native_client/service_runtime/nacl_desc_io.h"
53 #include "native_client/service_runtime/nacl_desc_conn_cap.h"
54 #include "native_client/service_runtime/nacl_desc_imc.h"
55 #include "native_client/service_runtime/nacl_desc_imc_bound_desc.h"
56 #include "native_client/service_runtime/nacl_desc_imc_shm.h"
57 #include "native_client/service_runtime/nacl_desc_mutex.h"
58 #include "native_client/service_runtime/nacl_desc_dir.h"
59 #include "native_client/service_runtime/nacl_desc_semaphore.h"
61 #include "native_client/service_runtime/nacl_global_secure_random.h"
62 #include "native_client/service_runtime/nacl_globals.h"
63 #include "native_client/service_runtime/nacl_ldt.h"
64 #include "native_client/service_runtime/nacl_log.h"
65 #include "native_client/service_runtime/nacl_secure_random.h"
66 #include "native_client/service_runtime/nacl_sync_checked.h"
68 #include "native_client/service_runtime/nrd_xfer_lib/nrd_xfer.h"
70 #include "native_client/service_runtime/sel_ldr.h"
71 #include "native_client/service_runtime/sel_mem.h"
72 #include "native_client/service_runtime/sel_memory.h"
73 #include "native_client/service_runtime/sel_util.h"
75 #include "native_client/service_runtime/include/bits/mman.h"
76 #include "native_client/service_runtime/include/sys/errno.h"
77 #include "native_client/service_runtime/include/sys/fcntl.h"
78 #include "native_client/service_runtime/include/sys/nacl_imc_api.h"
79 #include "native_client/service_runtime/include/sys/stat.h"
81 #include "native_client/intermodule_comm/nacl_imc_c.h"
83 #include "native_client/ncv/ncvalidate.h"
85 #if NACL_WINDOWS
86 # include "native_client/service_runtime/win/nacl_syscall_inl.h"
87 #elif NACL_LINUX || NACL_OSX
88 # include "native_client/service_runtime/linux/nacl_syscall_inl.h"
89 #else
90 # error "what target platform are you on?"
91 #endif
93 #if defined(HAVE_SDL)
94 # include "native_client/service_runtime/include/sys/audio_video.h"
95 # include "native_client/service_runtime/nacl_bottom_half.h"
96 #endif
98 static INLINE size_t size_min(size_t a, size_t b)
100 return (a < b) ? a : b;
104 * natp should be thread_self(), called while holding no locks.
106 void NaClSysCommonThreadSuicide(struct NaClAppThread *natp)
108 struct NaClApp *nap;
109 uint16_t ldt_ix;
112 * mark this thread as dead; doesn't matter if some other thread is
113 * asking us to commit suicide.
115 NaClLog(3, "NaClSysCommonThreadSuicide(0x%08"PRIxPTR")\n", (uintptr_t) natp);
116 nap = natp->nap;
117 NaClLog(3, " getting thread table lock\n");
118 NaClXMutexLock(&nap->threads_mu);
119 NaClLog(3, " getting thread lock\n");
120 NaClXMutexLock(&natp->mu);
121 natp->state = NACL_APP_THREAD_DEAD;
123 * Remove ourselves from the ldt-indexed global tables. The ldt
124 * entry is released as part of NaClAppThreadDtor (via
125 * NaClAppThreadDecRef), and if another thread is immediately
126 * created (from some other running thread) we want to be sure that
127 * any ldt-based lookups will not reach this dying thread's data.
129 ldt_ix = natp->user.gs >> 3;
130 nacl_sys[ldt_ix] = NULL;
131 nacl_user[ldt_ix] = NULL;
132 nacl_thread[ldt_ix] = NULL;
133 NaClLog(3, " removing thread from thread table\n");
134 NaClRemoveThreadMu(nap, natp->thread_num);
135 NaClLog(3, " unlocking thread\n");
136 NaClXMutexUnlock(&natp->mu);
137 NaClLog(3, " announcing thread count change\n");
138 NaClXCondVarBroadcast(&nap->threads_cv);
139 NaClLog(3, " unlocking thread table\n");
140 NaClXMutexUnlock(&nap->threads_mu);
141 NaClLog(3, " decref'ing thread object (from count %d)\n", natp->refcount);
142 NaClAppThreadDecRef(natp);
143 NaClLog(3, " NaClThreadExit\n");
144 NaClThreadExit(); /* should not return */
145 NaClLog(LOG_ERROR, "INCONCEIVABLE!\n");
146 abort();
147 /* NOTREACHED */
150 void NaClSysCommonThreadSyscallEnter(struct NaClAppThread *natp)
152 NaClLog(4, "NaClSysCommonThreadSyscallEnter: locking 0x%08"PRIxPTR"\n",
153 (uintptr_t) &natp->mu);
154 NaClXMutexLock(&natp->mu);
155 natp->holding_sr_locks = 1;
156 NaClLog(4, "NaClSysCommonThreadSyscallEnter: unlocking 0x%08"PRIxPTR"\n\n",
157 (uintptr_t) &natp->mu);
158 NaClXMutexUnlock(&natp->mu);
161 void NaClSysCommonThreadSyscallLeave(struct NaClAppThread *natp)
163 NaClXMutexLock(&natp->mu);
164 natp->holding_sr_locks = 0;
165 switch (natp->state) {
166 case NACL_APP_THREAD_ALIVE:
167 break;
168 case NACL_APP_THREAD_SUICIDE_PENDING:
169 NaClXMutexUnlock(&natp->mu);
170 NaClSysCommonThreadSuicide(natp);
171 /* NOTREACHED */
172 break;
173 case NACL_APP_THREAD_DEAD:
174 NaClLog(LOG_FATAL, "Dead thread at NaClSysCommonThreadSyscallLeave\n");
175 /* NOTREACHED */
176 break;
178 NaClXMutexUnlock(&natp->mu);
181 int32_t NaClSetBreak(struct NaClAppThread *natp,
182 uintptr_t new_break)
184 struct NaClApp *nap;
185 int32_t rv;
186 struct NaClVmmapIter iter;
187 struct NaClVmmapEntry *ent;
188 struct NaClVmmapEntry *next_ent;
189 uintptr_t sys_break;
190 uintptr_t sys_new_break;
191 uintptr_t usr_last_data_page;
192 uintptr_t usr_new_last_data_page;
193 uintptr_t last_internal_data_addr;
194 uintptr_t last_internal_page;
195 uintptr_t start_new_region;
196 uintptr_t region_size;
198 nap = natp->nap;
199 rv = nap->break_addr;
201 NaClLog(2, "NaClSetBreak: new_break 0x%08"PRIxPTR"\n", new_break);
203 NaClSysCommonThreadSyscallEnter(natp);
205 sys_new_break = NaClUserToSysAddr(natp->nap, new_break);
206 NaClLog(2, "sys_new_break 0x%08"PRIxPTR"\n", sys_new_break);
208 if (kNaClBadAddress == sys_new_break) {
209 goto cleanup_no_lock;
211 if (NACL_SYNC_OK != NaClMutexLock(&nap->mu)) {
212 NaClLog(LOG_ERROR, "Could not get app lock for 0x%08"PRIxPTR"\n",
213 (uintptr_t) nap);
214 goto cleanup_no_lock;
216 if (new_break < nap->data_end) {
217 goto cleanup;
219 if (new_break <= nap->break_addr) {
220 /* freeing memory */
221 nap->break_addr = new_break;
222 } else {
225 * See if page containing new_break is in mem_map; if so, we are
226 * essentially done -- just update break_addr. Otherwise, we
227 * extend the VM map entry from the page containing the current
228 * break to the page containing new_break.
231 sys_break = NaClUserToSys(nap, nap->break_addr);
233 usr_last_data_page = (nap->break_addr - 1) >> NACL_PAGESHIFT;
235 usr_new_last_data_page = (new_break - 1) >> NACL_PAGESHIFT;
237 last_internal_data_addr = NaClRoundAllocPage(new_break) - 1;
238 last_internal_page = last_internal_data_addr >> NACL_PAGESHIFT;
240 NaClLog(2, ("current break sys addr 0x%08"PRIxPTR
241 ", usr last data page 0x%"PRIxPTR"\n"),
242 sys_break, usr_last_data_page);
243 NaClLog(2, "new break usr last data page 0x%"PRIxPTR"\n",
244 usr_new_last_data_page);
245 NaClLog(3, "last internal data addr 0x%08"PRIxPTR"\n",
246 last_internal_data_addr);
248 if (NULL == NaClVmmapFindPageIter(&nap->mem_map,
249 usr_last_data_page,
250 &iter)
251 || NaClVmmapIterAtEnd(&iter)) {
252 NaClLog(LOG_FATAL, ("current break (0x%08"PRIxPTR", sys 0x%08"PRIxPTR")"
253 " not in address map\n"),
254 nap->break_addr, sys_break);
256 ent = NaClVmmapIterStar(&iter);
257 NaClLog(2, ("segment containing current break"
258 ": page_num 0x%08"PRIxPTR", npages 0x%"PRIxS"\n"),
259 ent->page_num, ent->npages);
260 if (usr_new_last_data_page < ent->page_num + ent->npages) {
261 NaClLog(2, "new break within break segment, just bumping addr\n");
262 nap->break_addr = new_break;
263 rv = new_break;
264 } else {
265 NaClVmmapIterIncr(&iter);
266 if (!NaClVmmapIterAtEnd(&iter)
267 && ((next_ent = NaClVmmapIterStar(&iter))->page_num
268 <= last_internal_page)) {
269 /* ran into next segment! */
270 NaClLog(1,
271 ("new break request of usr address"
272 " 0x%08"PRIxPTR" / usr page 0x%"PRIxPTR
273 " runs into next region, page_num 0x%"PRIxPTR
274 ", npages 0x%"PRIxS"\n"),
275 new_break, usr_new_last_data_page,
276 next_ent->page_num, next_ent->npages);
277 goto cleanup;
279 NaClLog(2,
280 "extending segment: page_num 0x%08"PRIxPTR", npages 0x%"PRIxS"\n",
281 ent->page_num, ent->npages);
282 /* go ahead and extend ent to cover, and make pages accessible */
283 start_new_region = (ent->page_num + ent->npages) << NACL_PAGESHIFT;
284 ent->npages = (last_internal_page - ent->page_num + 1);
285 region_size = (((last_internal_page + 1) << NACL_PAGESHIFT)
286 - start_new_region);
287 if (0 != NaCl_mprotect((void *) NaClUserToSys(nap, start_new_region),
288 region_size,
289 PROT_READ | PROT_WRITE)) {
290 NaClLog(LOG_FATAL,
291 ("Could not mprotect(0x%08"PRIxPTR", 0x%08"PRIxPTR", "
292 "PROT_READ|PROT_WRITE)\n"),
293 start_new_region,
294 region_size);
296 NaClLog(2, "segment now: page_num 0x%08"PRIxPTR", npages 0x%"PRIxS"\n",
297 ent->page_num, ent->npages);
298 nap->break_addr = new_break;
299 rv = new_break;
303 cleanup:
304 (void) NaClMutexUnlock(&nap->mu);
305 cleanup_no_lock:
306 NaClSysCommonThreadSyscallLeave(natp);
308 NaClLog(2, "NaClSetBreak: returning 0x%08"PRIx32"\n", rv);
309 return rv;
312 static int NaClAclBypassChecks = 0;
314 void NaClInsecurelyBypassAllAclChecks(void)
316 NaClLog(LOG_WARNING, "BYPASSING ALL ACL CHECKS\n");
317 NaClAclBypassChecks = 1;
320 int NaClHighResolutionTimerEnabled() {
321 return NaClAclBypassChecks;
325 * NaClOpenAclCheck: Is the NaCl app authorized to open this file? The
326 * return value is syscall return convention, so 0 is success and
327 * small negative numbers are negated errno values.
329 int32_t NaClOpenAclCheck(struct NaClApp *nap,
330 char const *path,
331 int flags,
332 int mode)
335 * TODO: provide some minimal authorization check, based on
336 * whether a debug flag is set; eventually provide a data-driven
337 * authorization configuration mechanism, perhaps persisted via
338 * gears. need GUI for user configuration, as well as designing an
339 * appropriate language (with sufficient expressiveness), however.
341 NaClLog(LOG_INFO, "NaClOpenAclCheck(0x%08"PRIxPTR", %s, 0%o, 0%o)\n",
342 (uintptr_t) nap, path, flags, mode);
343 if (3 < NaClLogGetVerbosity()) {
344 NaClLog(0, "O_ACCMODE: 0%o\n", flags & NACL_ABI_O_ACCMODE);
345 NaClLog(0, "O_RDONLY = %d\n", NACL_ABI_O_RDONLY);
346 NaClLog(0, "O_WRONLY = %d\n", NACL_ABI_O_WRONLY);
347 NaClLog(0, "O_RDWR = %d\n", NACL_ABI_O_RDWR);
348 #define FLOG(VAR, BIT) do {\
349 NaClLog(LOG_INFO, "%s: %s\n", #BIT, (VAR & BIT) ? "yes" : "no");\
350 } while (0)
351 FLOG(flags, NACL_ABI_O_CREAT);
352 FLOG(flags, NACL_ABI_O_TRUNC);
353 FLOG(flags, NACL_ABI_O_APPEND);
354 #undef FLOG
356 if (NaClAclBypassChecks) {
357 return 0;
359 return -NACL_ABI_EACCES;
363 * NaClStatAclCheck: Is the NaCl app authorized to stat this pathname? The
364 * return value is syscall return convention, so 0 is success and
365 * small negative numbers are negated errno values.
367 int32_t NaClStatAclCheck(struct NaClApp *nap,
368 char const *path)
371 * TODO: provide some minimal authorization check, based on
372 * whether a debug flag is set; eventually provide a data-driven
373 * authorization configuration mechanism, perhaps persisted via
374 * gears. need GUI for user configuration, as well as designing an
375 * appropriate language (with sufficient expressiveness), however.
377 NaClLog(LOG_INFO,
378 "NaClStatAclCheck(0x%08"PRIxPTR", %s)\n", (uintptr_t) nap, path);
379 if (NaClAclBypassChecks) {
380 return 0;
382 return -NACL_ABI_EACCES;
385 int32_t NaClIoctlAclCheck(struct NaClApp *nap,
386 struct NaClDesc *ndp,
387 int request,
388 void *arg) {
389 NaClLog(LOG_INFO,
390 ("NaClIoctlAclCheck(0x%08"PRIxPTR", 0x%08"PRIxPTR","
391 " %d, 0x%08"PRIxPTR"\n"),
392 (uintptr_t) nap, (uintptr_t) ndp, request, (uintptr_t) arg);
393 if (NaClAclBypassChecks) {
394 return 0;
396 return -NACL_ABI_EINVAL;
399 int32_t NaClCommonSysExit(struct NaClAppThread *natp,
400 int status)
402 struct NaClApp *nap;
404 NaClSysCommonThreadSyscallEnter(natp);
406 nap = natp->nap;
407 NaClSyncQueueQuit(&nap->work_queue);
409 NaClXMutexLock(&nap->mu);
410 nap->exit_status = status;
411 nap->running = 0;
412 NaClCondVarSignal(&nap->cv);
413 NaClXMutexUnlock(&nap->mu);
415 NaClSysCommonThreadSuicide(natp);
416 /* NOTREACHED */
417 return -NACL_ABI_EINVAL;
420 int32_t NaClCommonSysThreadExit(struct NaClAppThread *natp,
421 int32_t *stack_flag)
423 uintptr_t sys_stack_flag;
424 struct NaClApp *nap;
426 NaClLog(4, "NaclCommonSysThreadExit(0x%08"PRIxPTR", 0x%08"PRIxPTR"\n",
427 (uintptr_t) natp,
428 (uintptr_t) stack_flag);
429 NaClSysCommonThreadSyscallEnter(natp);
431 * NB: NaClThreads are never joinable, but the abstraction for NaClApps
432 * are.
434 nap = natp->nap;
436 if (NULL != stack_flag) {
437 sys_stack_flag = NaClUserToSys(natp->nap, (uintptr_t) stack_flag);
438 if (kNaClBadAddress != sys_stack_flag) {
440 * We don't return failure if the address is illegal because
441 * this function is not supposed to return.
443 *(int32_t *) sys_stack_flag = 0;
447 NaClSysCommonThreadSuicide(natp);
448 /* NOTREACHED */
449 return -NACL_ABI_EINVAL;
452 int32_t NaClCommonSysOpen(struct NaClAppThread *natp,
453 char *pathname,
454 int flags,
455 int mode)
457 uint32_t retval = -NACL_ABI_EINVAL;
458 uintptr_t sysaddr;
459 char path[NACL_CONFIG_PATH_MAX];
460 int len;
461 struct nacl_abi_stat stbuf;
462 int allowed_flags;
464 NaClLog(3, "NaClCommonSysOpen(0x%08"PRIxPTR", 0x%08"PRIxPTR", 0x%x, 0x%x)\n",
465 (uintptr_t) natp, (uintptr_t) pathname, flags, mode);
467 NaClSysCommonThreadSyscallEnter(natp);
469 sysaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) pathname);
470 if (kNaClBadAddress == sysaddr) {
471 NaClLog(LOG_ERROR, "Invalid address for pathname\n");
472 retval = -NACL_ABI_EFAULT;
473 goto cleanup;
475 allowed_flags = (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
476 | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
477 if (0 != (flags & ~allowed_flags)) {
478 NaClLog(LOG_WARNING, "Invalid open flags 0%o, ignoring extraneous bits\n",
479 flags);
480 flags &= allowed_flags;
482 if (0 != (mode & ~0600)) {
483 NaClLog(LOG_INFO, "IGNORING Invalid access mode bits 0%o\n", mode);
484 mode &= 0600;
486 NaClLog(4, " attempting to copy path via sysaddr 0x%08"PRIxPTR"\n", sysaddr);
487 NaClLog(4, " first 4 bytes: %.4s\n", (char *) sysaddr);
489 * strncpy may (try to) get bytes that is outside the app's address
490 * space and generate a fault.
492 strncpy(path, (char *) sysaddr, sizeof path);
494 * survived the copy, but did there happen to be data beyond the end?
496 path[sizeof path - 1] = '\0'; /* always null terminate */
497 NaClLog(LOG_INFO, "NaClSysOpen: Path: %s\n", path);
498 len = strlen(path);
500 * make sure sysaddr is a string, and the whole string is in app
501 * address space...
503 * address space is convex, so it is impossible for beginning and
504 * end to be both in the address space and yet have an intermediate
505 * byte not be in the address space.
507 if (kNaClBadAddress == NaClUserToSysAddr(natp->nap,
508 len + (uintptr_t) pathname)) {
509 NaClLog(LOG_ERROR, "String ends outside addrspace\n");
510 retval = -NACL_ABI_EFAULT;
511 goto cleanup;
514 retval = NaClOpenAclCheck(natp->nap, path, flags, mode);
515 if (0 != retval) {
516 NaClLog(3, "Open ACL check rejected \"%s\".\n", path);
517 goto cleanup;
521 * Perform a stat to determine whether the file is a directory.
523 * NB: it is okay for the stat to fail, since the request may be to
524 * create a new file.
526 * There is a race conditions here: between the stat and the
527 * open-as-a-file and open-as-a-dir, the type of the object that the
528 * path refers to can change.
530 retval = NaClHostDescStat(path, &stbuf);
532 if (0 == retval && NACL_ABI_S_ISDIR(stbuf.nacl_abi_st_mode)) {
533 struct NaClHostDir *hd;
535 hd = malloc(sizeof *hd);
536 if (NULL == hd) {
537 retval = -NACL_ABI_ENOMEM;
538 goto cleanup;
540 retval = NaClHostDirOpen(hd, path);
541 NaClLog(LOG_INFO, "NaClHostDirOpen(0x%08"PRIxPTR", %s) returned %d\n",
542 (uintptr_t) hd, path, retval);
543 if (0 == retval) {
544 retval = NaClSetAvail(natp->nap,
545 ((struct NaClDesc *) NaClDescDirDescMake(hd)));
546 NaClLog(LOG_INFO, "Entered directory into open file table at %d\n",
547 retval);
549 } else {
550 struct NaClHostDesc *hd;
552 hd = malloc(sizeof *hd);
553 if (NULL == hd) {
554 retval = -NACL_ABI_ENOMEM;
555 goto cleanup;
557 retval = NaClHostDescOpen(hd, path, flags, mode);
558 NaClLog(LOG_INFO,
559 "NaClHostDescOpen(0x%08"PRIxPTR", %s, 0%o, 0%o) returned %d\n",
560 (uintptr_t) hd, path, flags, mode, retval);
561 if (0 == retval) {
562 retval = NaClSetAvail(natp->nap,
563 ((struct NaClDesc *) NaClDescIoDescMake(hd)));
564 NaClLog(LOG_INFO, "Entered into open file table at %d\n", retval);
567 cleanup:
568 NaClSysCommonThreadSyscallLeave(natp);
570 return retval;
573 int32_t NaClCommonSysClose(struct NaClAppThread *natp,
574 int d)
576 int retval = -NACL_ABI_EBADF;
577 struct NaClDesc *ndp;
579 NaClLog(4, "Entered NaClCommonSysClose(0x%08"PRIxPTR", %d)\n",
580 (uintptr_t) natp, d);
582 NaClSysCommonThreadSyscallEnter(natp);
584 NaClXMutexLock(&natp->nap->desc_mu);
585 ndp = NaClGetDescMu(natp->nap, d);
586 if (NULL != ndp) {
587 NaClSetDescMu(natp->nap, d, NULL); /* Unref the desc_tbl */
589 NaClXMutexUnlock(&natp->nap->desc_mu);
590 NaClLog(5, "Invoking Close virtual function of object 0x%08"PRIxPTR"\n",
591 (uintptr_t) ndp);
592 if (NULL != ndp) {
593 retval = (*ndp->vtbl->Close)(ndp, natp->effp); /* Unref */
596 NaClSysCommonThreadSyscallLeave(natp);
597 return retval;
600 int32_t NaClCommonSysGetdents(struct NaClAppThread *natp,
601 int d,
602 void *dirp,
603 size_t count)
605 int retval = -NACL_ABI_EINVAL;
606 uintptr_t sysaddr;
607 struct NaClDesc *ndp;
609 NaClLog(4,
610 ("Entered NaClCommonSysGetdents(0x%08"PRIxPTR", %d, 0x%08"PRIxPTR","
611 " %"PRIdS"[0x%"PRIxS"])\n"),
612 (uintptr_t) natp, d, (uintptr_t) dirp, count, count);
614 NaClSysCommonThreadSyscallEnter(natp);
616 sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) dirp, count);
617 if (kNaClBadAddress == sysaddr) {
618 NaClLog(4, " illegal address for directory data\n");
619 retval = -NACL_ABI_EFAULT;
620 goto cleanup;
622 ndp = NaClGetDesc(natp->nap, d);
623 if (NULL == ndp) {
624 retval = -NACL_ABI_EBADF;
625 goto cleanup;
627 retval = (*ndp->vtbl->Getdents)(ndp, natp->effp, (void *) sysaddr, count);
628 if (retval > 0) {
629 NaClLog(4, "getdents returned %d bytes\n", retval);
630 NaClLog(8, "getdents result: %.*s\n", retval, (char *) sysaddr);
631 } else {
632 NaClLog(4, "getdents returned %d\n", retval);
634 NaClDescUnref(ndp);
636 cleanup:
637 NaClSysCommonThreadSyscallLeave(natp);
639 return retval;
642 int32_t NaClCommonSysRead(struct NaClAppThread *natp,
643 int d,
644 void *buf,
645 size_t count)
647 int32_t retval = -NACL_ABI_EINVAL;
648 uintptr_t sysaddr;
649 struct NaClDesc *ndp;
651 NaClLog(4,
652 ("Entered NaClCommonSysRead(0x%08"PRIxPTR", %d, 0x%08"PRIxPTR","
653 " %"PRIdS"[0x%"PRIxS"])\n"),
654 (uintptr_t) natp, d, (uintptr_t) buf, count, count);
656 NaClSysCommonThreadSyscallEnter(natp);
658 sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, count);
659 if (kNaClBadAddress == sysaddr) {
660 retval = -NACL_ABI_EFAULT;
661 goto cleanup;
663 ndp = NaClGetDesc(natp->nap, d);
664 if (NULL == ndp) {
665 retval = -NACL_ABI_EBADF;
666 goto cleanup;
668 retval = (*ndp->vtbl->Read)(ndp, natp->effp, (void *) sysaddr, count);
669 if (retval > 0) {
670 NaClLog(4, "read returned %d bytes\n", retval);
671 NaClLog(8, "read result: %.*s\n",
672 retval, (char *) sysaddr);
673 } else {
674 NaClLog(4, "read returned %d\n", retval);
676 NaClDescUnref(ndp);
677 cleanup:
678 NaClSysCommonThreadSyscallLeave(natp);
680 return retval;
683 int32_t NaClCommonSysWrite(struct NaClAppThread *natp,
684 int d,
685 void *buf,
686 size_t count)
688 int32_t retval = -NACL_ABI_EINVAL;
689 uintptr_t sysaddr;
690 struct NaClDesc *ndp;
692 NaClLog(4,
693 "Entered NaClCommonSysWrite(0x%08"PRIxPTR", %d, 0x%08"PRIxPTR","
694 " %"PRIdS"[0x%"PRIxS"])\n",
695 (uintptr_t) natp, d, (uintptr_t) buf, count, count);
697 NaClSysCommonThreadSyscallEnter(natp);
699 sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, count);
700 if (kNaClBadAddress == sysaddr) {
701 retval = -NACL_ABI_EFAULT;
702 goto cleanup;
705 NaClLog(4, "In NaClSysWrite(%d, %.*s, %"PRIdS")\n",
706 d, (int) count, (char *) sysaddr, count);
708 ndp = NaClGetDesc(natp->nap, d);
709 if (NULL == ndp) {
710 retval = -NACL_ABI_EBADF;
711 goto cleanup;
713 retval = (*ndp->vtbl->Write)(ndp, natp->effp, (void *) sysaddr, count);
714 NaClDescUnref(ndp);
716 cleanup:
717 NaClSysCommonThreadSyscallLeave(natp);
719 return retval;
722 int32_t NaClCommonSysLseek(struct NaClAppThread *natp,
723 int d,
724 off_t offset,
725 int whence)
727 int retval = -NACL_ABI_EINVAL;
728 struct NaClDesc *ndp;
730 NaClLog(4,
731 ("Entered NaClCommonSysLseek(0x%08"PRIxPTR", %d,"
732 " 0x%08"PRIx64", %d)\n"),
733 (uintptr_t) natp, d, (int64_t) offset, whence);
735 NaClSysCommonThreadSyscallEnter(natp);
737 ndp = NaClGetDesc(natp->nap, d);
738 if (NULL == ndp) {
739 retval = -NACL_ABI_EBADF;
740 goto cleanup;
742 retval = (*ndp->vtbl->Seek)(ndp, natp->effp, offset, whence);
743 NaClDescUnref(ndp);
744 cleanup:
745 NaClSysCommonThreadSyscallLeave(natp);
746 return retval;
749 int32_t NaClCommonSysIoctl(struct NaClAppThread *natp,
750 int d,
751 int request,
752 void *arg)
754 int retval = -NACL_ABI_EINVAL;
755 uintptr_t sysaddr;
756 struct NaClDesc *ndp;
758 NaClLog(4, "In NaClSysIoctl(%d, %d, 0x%08"PRIxPTR")\n", d, request,
759 (uintptr_t) arg);
761 NaClSysCommonThreadSyscallEnter(natp);
763 * Note that NaClUserToSysAddrRange is not feasible right now, since
764 * the size of the arg argument depends on the request. We do not
765 * have an enumeration of allowed ioctl requests yet.
767 * Furthermore, some requests take no arguments, so sysaddr might
768 * end up being kNaClBadAddress and that is perfectly okay.
770 sysaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) arg);
772 ****************************************
773 * NOTE: sysaddr may be kNaClBadAddress *
774 ****************************************
777 ndp = NaClGetDesc(natp->nap, d);
778 if (NULL == ndp) {
779 NaClLog(4, "bad desc\n");
780 retval = -NACL_ABI_EBADF;
781 goto cleanup;
784 retval = NaClIoctlAclCheck(natp->nap, ndp, request, arg);
785 if (0 != retval) {
786 NaClLog(3, "Ioctl ACL check rejected descriptor %d\n", d);
787 goto cleanup_unref;
790 retval = (*ndp->vtbl->Ioctl)(ndp, natp->effp, request, (void *) sysaddr);
791 cleanup_unref:
792 NaClDescUnref(ndp);
793 cleanup:
794 NaClSysCommonThreadSyscallLeave(natp);
795 return retval;
798 int32_t NaClCommonSysFstat(struct NaClAppThread *natp,
799 int d,
800 struct nacl_abi_stat *nasp)
802 int32_t retval = -NACL_ABI_EINVAL;
803 uintptr_t sysaddr;
804 struct NaClDesc *ndp;
806 NaClLog(4, "In NaClSysFstat(%d, 0x%08"PRIxPTR")\n", d, (uintptr_t) nasp);
808 NaClSysCommonThreadSyscallEnter(natp);
810 sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) nasp, sizeof *nasp);
811 if (kNaClBadAddress == sysaddr) {
812 NaClLog(4, "bad addr\n");
813 retval = -NACL_ABI_EFAULT;
814 goto cleanup;
817 ndp = NaClGetDesc(natp->nap, d);
818 if (NULL == ndp) {
819 NaClLog(4, "bad desc\n");
820 retval = -NACL_ABI_EBADF;
821 goto cleanup;
823 retval = (*ndp->vtbl->Fstat)(ndp, natp->effp,
824 (struct nacl_abi_stat *) sysaddr);
825 NaClDescUnref(ndp);
826 cleanup:
827 NaClSysCommonThreadSyscallLeave(natp);
829 return retval;
832 int32_t NaClCommonSysStat(struct NaClAppThread *natp,
833 const char *pathname,
834 struct nacl_abi_stat *buf)
836 int32_t retval = -NACL_ABI_EINVAL;
837 uintptr_t syspathaddr;
838 uintptr_t sysbufaddr;
839 char path[NACL_CONFIG_PATH_MAX];
840 int len;
842 NaClLog(4,
843 ("In NaClCommonSysStat(0x%08"PRIxPTR", 0x%08"PRIxPTR","
844 " 0x%08"PRIxPTR")\n"),
845 (uintptr_t) natp, (uintptr_t) pathname, (uintptr_t) buf);
847 NaClSysCommonThreadSyscallEnter(natp);
849 syspathaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) pathname);
850 if (kNaClBadAddress == syspathaddr) {
851 NaClLog(LOG_ERROR, "Invalid address for pathname\n");
852 retval = -NACL_ABI_EFAULT;
853 goto cleanup;
856 * strncpy may (try to) get bytes that is outside the app's address
857 * space and generate a fault.
859 strncpy(path, (char *) syspathaddr, sizeof path);
861 * survived the copy, but did there happen to be data beyond the end?
863 path[sizeof path - 1] = '\0'; /* always null terminate */
864 NaClLog(LOG_INFO, "NaClCommonSysStat: Path: %s\n", path);
865 len = strlen(path);
867 * make sure sysaddr is a string, and the whole string is in app
868 * address space...
870 * address space is convex, so it is impossible for beginning and
871 * end to be both in the address space and yet have an intermediate
872 * byte not be in the address space.
874 if (kNaClBadAddress == NaClUserToSysAddr(natp->nap,
875 len + (uintptr_t) pathname)) {
876 NaClLog(LOG_ERROR, "String ends outside addrspace\n");
877 retval = -NACL_ABI_EFAULT;
878 goto cleanup;
882 * Make sure result buffer is in the app's address space.
884 sysbufaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, sizeof *buf);
885 if (kNaClBadAddress == sysbufaddr) {
886 retval = -NACL_ABI_EFAULT;
887 goto cleanup;
890 retval = NaClStatAclCheck(natp->nap, path);
891 if (0 != retval) {
892 goto cleanup;
896 * Perform a host stat.
898 retval = NaClHostDescStat(path, (struct nacl_abi_stat *) sysbufaddr);
899 cleanup:
900 NaClSysCommonThreadSyscallLeave(natp);
901 return retval;
904 void NaClCommonUtilUpdateAddrMap(struct NaClAppThread *natp,
905 uintptr_t sysaddr,
906 size_t nbytes,
907 int sysprot,
908 struct NaClDesc *backing_desc,
909 size_t backing_bytes,
910 off_t offset_bytes,
911 int delete_mem)
913 uintptr_t usraddr;
914 struct NaClMemObj *nmop;
916 NaClLog(3,
917 ("NaClCommonUtilUpdateAddrMap(0x%08"PRIxPTR", 0x%08"PRIxPTR","
918 " 0x%"PRIxS", 0x%x, 0x%08"PRIxPTR", 0x%"PRIxS", 0x%"PRIx64", %d)\n"),
919 (uintptr_t) natp, sysaddr, nbytes,
920 sysprot, (uintptr_t) backing_desc, backing_bytes,
921 (int64_t) offset_bytes,
922 delete_mem);
923 usraddr = NaClSysToUser(natp->nap, sysaddr);
924 nmop = NULL;
925 /* delete_mem -> NULL == backing_desc */
926 if (NULL != backing_desc) {
927 if (delete_mem) {
928 NaClLog(LOG_FATAL,
929 ("invariant of delete_mem implies backing_desc NULL"
930 " violated.\n"));
932 nmop = NaClMemObjMake(backing_desc, backing_bytes, offset_bytes);
935 NaClVmmapUpdate(&natp->nap->mem_map,
936 usraddr >> NACL_PAGESHIFT,
937 nbytes >> NACL_PAGESHIFT,
938 sysprot,
939 nmop,
940 delete_mem);
944 int NaClSysCommonAddrRangeContainsExecutablePages_mu(struct NaClApp *nap,
945 uintptr_t usraddr,
946 size_t length)
949 * NOTE: currently only trampoline and text region are executable,
950 * and they are at the beginning of the address space, so this code
951 * is fine. We will probably never allow users to mark other pages
952 * as executable; but if so, we will have to revisit how this check
953 * is implemented.
955 * The sum NACL_TRAMPOLINE_END + nap->text_region_size is a
956 * multiple of 4K, the memory protection granularity. Since this
957 * routine is used for checking whether memory map adjustments /
958 * allocations -- which has 64K granularity -- is okay, usraddr must
959 * be an allocation granularity value. Our callers (as of this
960 * writing) does this, but we truncate it down to an allocation
961 * boundary to be sure.
963 /* MarkS: will need to update */
964 usraddr = NaClTruncAllocPage(usraddr);
965 return usraddr < nap->text_region_end;
969 static int
970 VerifyAndMapCode(struct NaClAppThread *natp, struct NaClDesc *ndp,
971 uintptr_t dest_addr, nacl_abi_off_t offset, size_t length)
973 void *temp_addr;
974 struct NCValidatorState *vstate;
975 int validate_result;
976 int retval;
977 int32_t read_size;
979 /* We make a copy of the code because we cannot guarantee that it
980 will not change underneath us, even if we use MAP_PRIVATE.
981 Copy-on-write on Linux does not induce a copy when the file is
982 changed, only when the private mapping is changed. */
983 temp_addr = mmap(NULL, length, PROT_READ | PROT_WRITE,
984 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
985 if (temp_addr == MAP_FAILED)
986 return -NACL_ABI_ENOMEM;
987 /* This changes the seek position which mmap() should not do.
988 TODO: use pread() instead. */
989 retval = ndp->vtbl->Seek(ndp, natp->effp, offset, SEEK_SET);
990 if (retval < 0)
991 goto cleanup;
992 read_size = ndp->vtbl->Read(ndp, natp->effp, temp_addr, length);
993 if (read_size < 0) {
994 retval = read_size;
995 goto cleanup;
997 if (read_size != length) {
998 retval = -NACL_ABI_EINVAL;
999 goto cleanup;
1002 vstate = NCValidateInit((uintptr_t) temp_addr, (uintptr_t) temp_addr + length,
1003 natp->nap->align_boundary);
1004 if (vstate == NULL) {
1005 NCValidateFreeState(&vstate);
1006 retval = -NACL_ABI_ENOMEM;
1007 goto cleanup;
1009 NCValidateSegment((uint8_t *) temp_addr, (uintptr_t) temp_addr,
1010 length, vstate);
1011 validate_result = NCValidateFinish(vstate);
1012 NCValidateFreeState(&vstate);
1013 if (validate_result != 0) {
1014 NaClLog(LOG_ERROR, "VALIDATION FAILED on mmap\n");
1015 retval = -NACL_ABI_EINVAL;
1016 goto cleanup;
1019 if (mprotect(temp_addr, length, PROT_READ | PROT_EXEC) < 0) {
1020 retval = -NACL_ABI_EPERM;
1021 goto cleanup;
1023 /* Linux-specific */
1024 if (mremap(temp_addr, length, length, MREMAP_MAYMOVE | MREMAP_FIXED,
1025 dest_addr) == MAP_FAILED) {
1026 retval = -NACL_ABI_EPERM;
1027 goto cleanup;
1029 return 0;
1031 cleanup:
1032 if (munmap(temp_addr, length))
1033 NaClLog(LOG_ERROR, "munmap of temporary space failed");
1034 assert(retval < 0);
1035 return retval;
1039 /* Warning: sizeof(nacl_abi_off_t)!=sizeof(off_t) on OSX */
1040 int32_t NaClCommonSysMmap(struct NaClAppThread *natp,
1041 void *start,
1042 size_t length,
1043 int prot,
1044 int flags,
1045 int fd,
1046 nacl_abi_off_t offset)
1048 int32_t retval = -NACL_ABI_EINVAL;
1049 int allowed_flags;
1050 struct NaClDesc *ndp;
1051 uintptr_t usraddr;
1052 uintptr_t usrpage;
1053 uintptr_t sysaddr;
1054 uintptr_t endaddr;
1055 void *map_result;
1056 int holding_app_lock;
1057 struct NaClMemObj *nmop;
1058 struct nacl_abi_stat stbuf;
1059 size_t alloc_rounded_length;
1060 off_t file_size;
1061 size_t file_bytes;
1062 size_t alloc_rounded_file_bytes;
1063 size_t start_of_inaccessible;
1065 holding_app_lock = 0;
1066 nmop = NULL;
1068 allowed_flags = (NACL_ABI_MAP_FIXED | NACL_ABI_MAP_SHARED
1069 | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS);
1071 usraddr = (uintptr_t) start;
1073 NaClLog(4,
1074 "NaClSysMmap(0x%08"PRIxPTR",0x%"PRIxS",0x%x,0x%x,%d,0x%08"PRIx32")\n",
1075 usraddr, length, prot, flags, fd, (int32_t) offset);
1077 NaClSysCommonThreadSyscallEnter(natp);
1079 if (0 != (flags & ~allowed_flags)) {
1080 NaClLog(LOG_WARNING, "invalid mmap flags 0%o, ignoring extraneous bits 0%o\n",
1081 flags, flags & ~allowed_flags);
1082 flags &= allowed_flags;
1085 if (0 != (flags & NACL_ABI_MAP_ANONYMOUS)) {
1087 * anonymous mmap, so backing store is just swap: no descriptor is
1088 * involved, and no memory object will be created to represent the
1089 * descriptor.
1091 ndp = NULL;
1092 } else {
1093 ndp = NaClGetDesc(natp->nap, fd);
1094 if (NULL == ndp) {
1095 retval = -NACL_ABI_EBADF;
1096 goto cleanup;
1101 * Starting address must be aligned to worst-case allocation
1102 * granularity. (Windows.) We round up.
1104 if (!NaClIsAllocPageMultiple(usraddr)) {
1105 NaClLog(2, "NaClSysMmap: address not allocation granularity aligned\n");
1106 usraddr = NaClRoundAllocPage(usraddr);
1109 * And offset must be a multiple of the allocation unit.
1111 if (!NaClIsAllocPageMultiple((uintptr_t) offset)) {
1112 NaClLog(LOG_INFO,
1113 ("NaClSysMmap: file offset 0x%08"PRIxPTR" not multiple"
1114 " of allocation size\n"),
1115 (uintptr_t) offset);
1116 retval = -NACL_ABI_EINVAL;
1117 goto cleanup;
1120 if (0 == length) {
1121 retval = -NACL_ABI_EINVAL;
1122 goto cleanup;
1124 alloc_rounded_length = NaClRoundAllocPage(length);
1125 if (alloc_rounded_length != length) {
1126 NaClLog(LOG_WARNING,
1127 "mmap: rounded length to 0x%"PRIxS"\n", alloc_rounded_length);
1130 if (NULL == ndp) {
1132 * sentinel values that are bigger than the addr space
1134 file_size = ~0u>>1;
1135 file_bytes = file_size;
1136 alloc_rounded_file_bytes = file_size;
1137 } else {
1139 * We stat the file to figure out its actual size.
1141 * This is needed since we allow an app to mmap in a odd-sized
1142 * file and will zero fill the allocation page containing the last
1143 * byte(s) of the file, but if the app asked for a length that
1144 * goes beyond the last allocation page, that memory is actually
1145 * inaccessible. Of course, the underlying OS deals with real
1146 * pages, and we may need to simulate this behavior (i.e., OSX and
1147 * Linux, we will need to put zero-filled pages between the last
1148 * 4K system page containing file data and the rest of the
1149 * simulated windows allocation 64K page.
1151 retval = (*ndp->vtbl->Fstat)(ndp, natp->effp, &stbuf);
1152 if (0 != retval) {
1153 goto cleanup;
1156 * BUG(bsy): there's a race between this fstat and the actual mmap
1157 * below. It's probably insoluble. Even if we fstat again after
1158 * mmap and compared, the mmap could have "seen" the file with a
1159 * different size, after which the racing thread restored back to
1160 * the same value before the 2nd fstat takes place.
1162 file_size = stbuf.nacl_abi_st_size;
1164 if (file_size < offset) {
1165 retval = -NACL_ABI_EINVAL;
1166 goto cleanup;
1168 file_bytes = NaClRoundHostAllocPage(file_size - offset);
1170 * We need to deal with NaClRoundHostAllocPage rounding up to zero
1171 * from ~0u - n, where n < 4096 or 65536 (== 1 alloc page).
1173 alloc_rounded_file_bytes = NaClRoundAllocPage(file_bytes);
1175 if (0 == alloc_rounded_file_bytes && 0 != file_bytes) {
1176 retval = -NACL_ABI_ENOMEM;
1177 goto cleanup;
1181 * NB: file_bytes and alloc_rounded_file_bytes can be zero. Such
1182 * an mmap just makes memory (offset relative to usraddr) in the
1183 * range [0, alloc_rounded_length) inaccessible.
1188 * file_bytes is how many bytes we can map from the file, given the
1189 * user-supplied starting offset. It is at least one page. If it
1190 * came from a real file, it is a multiple of host-OS allocation
1191 * size.
1193 length = size_min(alloc_rounded_length, file_bytes);
1194 start_of_inaccessible = size_min(alloc_rounded_length,
1195 alloc_rounded_file_bytes);
1198 * Now, we map, relative to usraddr, bytes [0, length) from the file
1199 * starting at offset, zero-filled pages for the memory region
1200 * [length, start_of_inaccessible), and inaccessible pages for the
1201 * memory region [start_of_inaccessible, alloc_rounded_length).
1205 * Lock the addr space.
1207 NaClXMutexLock(&natp->nap->mu);
1208 holding_app_lock = 1;
1210 if (0 == (flags & NACL_ABI_MAP_FIXED)) {
1212 * The user wants us to pick an address range.
1214 if (0 == usraddr) {
1216 * Pick a hole in addr space of appropriate size, anywhere.
1217 * We pick one that's best for the system.
1219 usrpage = NaClVmmapFindMapSpace(&natp->nap->mem_map,
1220 alloc_rounded_length >> NACL_PAGESHIFT);
1221 NaClLog(4, "NaClSysMmap: FindMapSpace: page 0x%05"PRIxPTR"\n", usrpage);
1222 if (0 == usrpage) {
1223 retval = -NACL_ABI_ENOMEM;
1224 goto cleanup;
1226 usraddr = usrpage << NACL_PAGESHIFT;
1227 NaClLog(4, "NaClSysMmap: new starting addr: 0x%08"PRIxPTR"\n", usraddr);
1228 } else {
1230 * user supplied an addr, but it's to be treated as a hint; we
1231 * find a hole of the right size in the app's address space,
1232 * according to the usual mmap semantics.
1234 usrpage = NaClVmmapFindMapSpaceAboveHint(&natp->nap->mem_map,
1235 usraddr,
1236 (alloc_rounded_length
1237 >> NACL_PAGESHIFT));
1238 NaClLog(4, "NaClSysMmap: FindSpaceAboveHint: page 0x%05"PRIxPTR"\n",
1239 usrpage);
1240 if (0 == usrpage) {
1241 NaClLog(4, "NaClSysMmap: hint failed, doing generic allocation\n");
1242 usrpage = NaClVmmapFindMapSpace(&natp->nap->mem_map,
1243 alloc_rounded_length >> NACL_PAGESHIFT);
1245 if (0 == usrpage) {
1246 retval = -NACL_ABI_ENOMEM;
1247 goto cleanup;
1249 usraddr = usrpage << NACL_PAGESHIFT;
1250 NaClLog(4, "NaClSysMmap: new starting addr: 0x%08"PRIxPTR"\n", usraddr);
1255 * Validate [usraddr, endaddr) is okay.
1257 if (usraddr >= (1U << natp->nap->addr_bits)) {
1258 NaClLog(2,
1259 ("NaClSysMmap: start address (0x%08"PRIxPTR") outside address"
1260 " space\n"),
1261 usraddr);
1262 retval = -NACL_ABI_EINVAL;
1263 goto cleanup;
1265 endaddr = usraddr + alloc_rounded_length;
1266 if (endaddr < usraddr) {
1267 NaClLog(0,
1268 ("NaClSysMmap: integer overflow -- "
1269 "NaClSysMmap(0x%08"PRIxPTR",0x%"PRIxS",0x%x,0x%x,%d,"
1270 "0x%08"PRIxPTR"\n"),
1271 usraddr, length, prot, flags, fd, (uintptr_t) offset);
1272 retval = -NACL_ABI_EINVAL;
1273 goto cleanup;
1276 * NB: we use > instead of >= here.
1278 * endaddr is the address of the first byte beyond the target region
1279 * and it can equal the address space limit. (of course, normally
1280 * the main thread's stack is there.)
1282 if (endaddr > (1U << natp->nap->addr_bits)) {
1283 NaClLog(2,
1284 ("NaClSysMmap: end address (0x%08"PRIxPTR") is beyond"
1285 " the end of the address space\n"),
1286 endaddr);
1287 retval = -NACL_ABI_EINVAL;
1288 goto cleanup;
1291 if (NaClSysCommonAddrRangeContainsExecutablePages_mu(natp->nap,
1292 usraddr,
1293 length)) {
1294 NaClLog(2, "NaClSysMmap: region contains executable pages\n");
1295 retval = -NACL_ABI_EINVAL;
1296 goto cleanup;
1300 * Force NACL_ABI_MAP_FIXED, since we are specifying address in NaCl
1301 * app address space.
1303 flags |= NACL_ABI_MAP_FIXED;
1306 * Never allow users to say that mmapped pages are executable. This
1307 * is primarily for the service runtime's own bookkeeping -- prot is
1308 * used in NaClCommonUtilUpdateAddrMap -- since %cs restriction
1309 * makes page protection irrelevant, it doesn't matter that on many
1310 * systems (w/o NX) PROT_READ implies PROT_EXEC.
1312 /* prot &= ~NACL_ABI_PROT_EXEC; */
1315 * Exactly one of NACL_ABI_MAP_SHARED and NACL_ABI_MAP_PRIVATE is set.
1317 if ((0 == (flags & NACL_ABI_MAP_SHARED))
1318 == (0 == (flags & NACL_ABI_MAP_PRIVATE))) {
1319 retval = -NACL_ABI_EINVAL;
1320 goto cleanup;
1323 sysaddr = NaClUserToSys(natp->nap, usraddr);
1325 /* [0, length) */
1326 if (length > 0) {
1327 if (NULL == ndp) {
1328 NaClLog(4,
1329 ("NaClSysMmap: NaClDescIoDescMap(,,0x%08"PRIxPTR","
1330 "0x%08"PRIxS",0x%x,0x%x,0x%08"PRIxPTR")\n"),
1331 sysaddr, length, prot, flags, (uintptr_t) offset);
1332 map_result = (void *) NaClDescIoDescMap(NULL,
1333 natp->effp,
1334 (void *) sysaddr,
1335 length,
1336 prot,
1337 flags,
1338 (off_t) offset);
1339 } else {
1340 NaClLog(4,
1341 ("NaClSysMmap: (*ndp->vtbl->Map)(,,0x%08"PRIxPTR","
1342 "0x%08"PRIxS",0x%x,0x%x,0x%08"PRIxPTR")\n"),
1343 sysaddr, length, prot, flags, (uintptr_t) offset);
1345 if ((prot & NACL_ABI_PROT_EXEC) == 0) {
1346 map_result = (void *) (*ndp->vtbl->Map)(ndp,
1347 natp->effp,
1348 (void *) sysaddr,
1349 length,
1350 prot,
1351 flags,
1352 (off_t) offset);
1354 else {
1355 /* We could map the code into the data segment as well, if
1356 there are programs that really need this, but so far that
1357 is not necessary. */
1358 uintptr_t sysaddr_code = natp->nap->code_mem_start + usraddr;
1359 retval = VerifyAndMapCode(natp, ndp, sysaddr_code, offset, length);
1360 if (NaClIsNegErrno(retval))
1361 goto cleanup;
1362 map_result = (void *) sysaddr;
1366 * "Small" negative integers are errno values. Larger ones are
1367 * virtual addresses.
1369 if (NaClIsNegErrno((int) map_result)) {
1370 NaClLog(LOG_FATAL,
1371 ("NaClSysMmap: Map failed, but we"
1372 " cannot handle address space move, error %d"),
1373 (int) map_result);
1375 if (map_result != (void *) sysaddr) {
1376 NaClLog(LOG_FATAL, "system mmap did not honor NACL_ABI_MAP_FIXED\n");
1378 if (prot == NACL_ABI_PROT_NONE) {
1380 * windows nacl_host_desc implementation requires that PROT_NONE
1381 * memory be freed using VirtualFree rather than
1382 * UnmapViewOfFile. TODO: remove this ugliness.
1384 NaClCommonUtilUpdateAddrMap(natp, sysaddr, length, PROT_NONE,
1385 NULL, file_size, offset, 0);
1386 } else {
1387 /* record change for file-backed memory */
1388 NaClCommonUtilUpdateAddrMap(natp, sysaddr, length, NaClProtMap(prot),
1389 ndp, file_size, offset, 0);
1391 } else {
1392 map_result = (void *) sysaddr;
1394 /* zero fill [length, start_of_inaccessible) */
1395 if (length < start_of_inaccessible) {
1396 size_t map_len = start_of_inaccessible - length;
1398 NaClLog(2,
1399 ("zero-filling pages for memory range"
1400 " [0x%08"PRIxPTR", 0x%08"PRIxPTR"), length 0x%"PRIxS"\n"),
1401 sysaddr + length, sysaddr + start_of_inaccessible, map_len);
1402 retval = NaClHostDescMap((struct NaClHostDesc *) NULL,
1403 (void *) (sysaddr + length),
1404 map_len,
1405 prot,
1406 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
1407 (off_t) 0);
1408 if (NaClIsNegErrno(retval)) {
1409 NaClLog(LOG_ERROR,
1410 ("Could not create zero-filled pages for memory range"
1411 " [0x%08"PRIxPTR", 0x%08"PRIxPTR")\n"),
1412 sysaddr + length, sysaddr + start_of_inaccessible);
1413 goto cleanup;
1415 NaClCommonUtilUpdateAddrMap(natp, sysaddr + length, map_len,
1416 NaClProtMap(prot),
1417 (struct NaClDesc *) NULL, 0, (off_t) 0, 0);
1419 /* inaccessible: [start_of_inaccessible, alloc_rounded_length) */
1420 if (start_of_inaccessible < alloc_rounded_length) {
1421 size_t map_len = alloc_rounded_length - start_of_inaccessible;
1423 NaClLog(2,
1424 ("inaccessible pages for memory range"
1425 " [0x%08"PRIxPTR", 0x%08"PRIxPTR"), length 0x%"PRIxS"\n"),
1426 sysaddr + start_of_inaccessible,
1427 sysaddr + alloc_rounded_length,
1428 map_len);
1429 retval = NaClHostDescMap((struct NaClHostDesc *) NULL,
1430 (void *) (sysaddr + start_of_inaccessible),
1431 map_len,
1432 NACL_ABI_PROT_NONE,
1433 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
1434 (off_t) 0);
1435 if (NaClIsNegErrno(retval)) {
1436 NaClLog(LOG_ERROR,
1437 ("Could not create inaccessible pages for memory range"
1438 " [0x%08"PRIxPTR", 0x%08"PRIxPTR"), length 0x%"PRIxS"\n"),
1439 sysaddr + start_of_inaccessible,
1440 sysaddr + alloc_rounded_length,
1441 map_len);
1443 NaClCommonUtilUpdateAddrMap(natp, sysaddr + start_of_inaccessible,
1444 map_len, PROT_NONE,
1445 (struct NaClDesc *) NULL, 0,
1446 (off_t) 0, 0);
1448 NaClLog(3, "NaClSysMmap: got address 0x%08"PRIxPTR"\n",
1449 (uintptr_t) map_result);
1451 retval = usraddr;
1452 cleanup:
1453 if (holding_app_lock) {
1454 NaClXMutexUnlock(&natp->nap->mu);
1456 if (NULL != ndp) {
1457 NaClDescUnref(ndp);
1459 if (NaClIsNegErrno((uintptr_t) retval)) {
1460 free(nmop);
1463 NaClSysCommonThreadSyscallLeave(natp);
1465 NaClLog(3, "NaClSysMmap: returning 0x%08x\n", retval);
1466 return retval;
1469 int32_t NaClCommonSysImc_MakeBoundSock(struct NaClAppThread *natp,
1470 int *sap)
1473 * Create a bound socket descriptor and a socket address descriptor.
1476 int32_t retval = -NACL_ABI_EINVAL;
1477 uintptr_t sys_sap;
1478 struct NaClDesc *pair[2];
1480 NaClLog(3,
1481 ("Entered NaClCommonSysImc_MakeBoundSock(0x%08"PRIxPTR","
1482 " 0x%08"PRIxPTR")\n"),
1483 (uintptr_t) natp, (uintptr_t) sap);
1485 NaClSysCommonThreadSyscallEnter(natp);
1487 sys_sap = NaClUserToSysAddrRange(natp->nap,
1488 (uintptr_t) sap,
1489 2 * sizeof *sap);
1490 if (kNaClBadAddress == sys_sap) {
1491 NaClLog(3, " illegal address\n");
1492 retval = -NACL_ABI_EFAULT;
1493 goto cleanup;
1496 retval = NaClCommonDescMakeBoundSock(pair);
1497 if (0 != retval) {
1498 goto cleanup;
1501 ((int *) sys_sap)[0] = NaClSetAvail(natp->nap, pair[0]);
1502 ((int *) sys_sap)[1] = NaClSetAvail(natp->nap, pair[1]);
1503 retval = 0;
1504 cleanup:
1505 NaClSysCommonThreadSyscallLeave(natp);
1507 return retval;
1510 int32_t NaClCommonSysImc_Accept(struct NaClAppThread *natp,
1511 int d)
1513 int32_t retval = -NACL_ABI_EINVAL;
1514 struct NaClDesc *ndp;
1516 NaClLog(4, "Entered NaClSysImc_Accept(0x%08"PRIxPTR", %d)\n",
1517 (uintptr_t) natp, d);
1519 NaClSysCommonThreadSyscallEnter(natp);
1521 ndp = NaClGetDesc(natp->nap, d);
1522 if (NULL == ndp) {
1523 retval = -NACL_ABI_EBADF;
1524 } else {
1525 retval = (*ndp->vtbl->AcceptConn)(ndp, natp->effp);
1526 NaClDescUnref(ndp);
1529 NaClSysCommonThreadSyscallLeave(natp);
1530 return retval;
1533 int32_t NaClCommonSysImc_Connect(struct NaClAppThread *natp,
1534 int d)
1536 int32_t retval = -NACL_ABI_EINVAL;
1537 struct NaClDesc *ndp;
1539 NaClLog(4, "Entered NaClSysImc_ConnectAddr(0x%08"PRIxPTR", %d)\n",
1540 (uintptr_t) natp, d);
1542 NaClSysCommonThreadSyscallEnter(natp);
1544 ndp = NaClGetDesc(natp->nap, d);
1545 if (NULL == ndp) {
1546 retval = -NACL_ABI_EBADF;
1547 } else {
1548 retval = (*ndp->vtbl->ConnectAddr)(ndp, natp->effp);
1549 NaClDescUnref(ndp);
1552 NaClSysCommonThreadSyscallLeave(natp);
1553 return retval;
1557 * This function converts addresses from user addresses to system
1558 * addresses, copying into kernel space as needed to avoid TOCvTOU
1559 * races, then invoke NaClImcSendTypedMessage from the nrd_xfer
1560 * library.
1562 int32_t NaClCommonSysImc_Sendmsg(struct NaClAppThread *natp,
1563 int d,
1564 struct NaClImcMsgHdr *nimhp,
1565 int flags)
1567 int32_t retval = -NACL_ABI_EINVAL;
1568 uintptr_t sysaddr;
1569 /* copy of user-space data for validation */
1570 struct NaClImcMsgHdr kern_nimh;
1571 struct NaClImcMsgIoVec kern_iov[NACL_ABI_IMC_IOVEC_MAX];
1572 /* kernel-side representatin of descriptors */
1573 struct NaClDesc *kern_desc[NACL_ABI_IMC_USER_DESC_MAX];
1574 struct NaClImcTypedMsgHdr kern_msg_hdr;
1575 struct NaClDesc *ndp;
1576 size_t i;
1578 NaClLog(3,
1579 ("Entered NaClCommonSysImc_Sendmsg(0x%08"PRIxPTR", %d,"
1580 " 0x%08"PRIxPTR", 0x%x)\n"),
1581 (uintptr_t) natp, d, (uintptr_t) nimhp, flags);
1583 NaClSysCommonThreadSyscallEnter(natp);
1585 sysaddr = NaClUserToSysAddrRange(natp->nap,
1586 (uintptr_t) nimhp,
1587 sizeof *nimhp);
1588 if (kNaClBadAddress == sysaddr) {
1589 NaClLog(4, "NaClImcMsgHdr not in user address space\n");
1590 retval = -NACL_ABI_EFAULT;
1591 goto cleanup_leave;
1594 kern_nimh = *(struct NaClImcMsgHdr *) sysaddr; /* copy before validating */
1597 * Some of these checks duplicate checks that will be done in the
1598 * nrd xfer library, but it is better to check before doing the
1599 * address translation of memory/descriptor vectors if those vectors
1600 * might be too long. Plus, we need to copy and validate vectors
1601 * for TOCvTOU race protection, and we must prevent overflows. The
1602 * nrd xfer library's checks should never fire when called from the
1603 * service runtime, but the nrd xfer library might be called from
1604 * other code.
1606 if (kern_nimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
1607 NaClLog(4, "gather/scatter array too large\n");
1608 retval = -NACL_ABI_EINVAL;
1609 goto cleanup_leave;
1611 if (kern_nimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
1612 NaClLog(4, "handle vector too long\n");
1613 retval = -NACL_ABI_EINVAL;
1614 goto cleanup_leave;
1617 if (kern_nimh.iov_length > 0) {
1618 sysaddr = NaClUserToSysAddrRange(natp->nap,
1619 (uintptr_t) kern_nimh.iov,
1620 (kern_nimh.iov_length
1621 * sizeof *kern_nimh.iov));
1622 if (kNaClBadAddress == sysaddr) {
1623 NaClLog(4, "gather/scatter array not in user address space\n");
1624 retval = -NACL_ABI_EFAULT;
1625 goto cleanup_leave;
1628 memcpy(kern_iov, (void *) sysaddr,
1629 kern_nimh.iov_length * sizeof *kern_nimh.iov);
1631 for (i = 0; i < kern_nimh.iov_length; ++i) {
1632 sysaddr = NaClUserToSysAddrRange(natp->nap,
1633 (uintptr_t) kern_iov[i].base,
1634 kern_iov[i].length);
1635 if (kNaClBadAddress == sysaddr) {
1636 retval = -NACL_ABI_EFAULT;
1637 goto cleanup_leave;
1639 kern_iov[i].base = (void *) sysaddr;
1643 ndp = NaClGetDesc(natp->nap, d);
1644 if (NULL == ndp) {
1645 retval = -NACL_ABI_EBADF;
1646 goto cleanup_leave;
1650 * make things easier for cleaup exit processing
1652 memset(kern_desc, 0, sizeof kern_desc);
1653 retval = -NACL_ABI_EINVAL;
1655 kern_msg_hdr.iov = kern_iov;
1656 kern_msg_hdr.iov_length = kern_nimh.iov_length;
1658 if (0 == kern_nimh.desc_length) {
1659 kern_msg_hdr.ndescv = 0;
1660 kern_msg_hdr.ndesc_length = 0;
1661 } else {
1662 sysaddr = NaClUserToSysAddrRange(natp->nap,
1663 (uintptr_t) kern_nimh.descv,
1664 kern_nimh.desc_length * sizeof(int));
1665 if (kNaClBadAddress == sysaddr) {
1666 retval = -NACL_ABI_EFAULT;
1667 goto cleanup;
1671 * NB: for each descv entry, we read from NaCl app address space
1672 * exactly once.
1674 for (i = 0; i < kern_nimh.desc_length; ++i) {
1675 kern_desc[i] = NaClGetDesc(natp->nap, ((int *) sysaddr)[i]);
1676 if (NULL == kern_desc[i]) {
1677 retval = -NACL_ABI_EBADF;
1678 goto cleanup;
1681 kern_msg_hdr.ndescv = kern_desc;
1682 kern_msg_hdr.ndesc_length = kern_nimh.desc_length;
1684 kern_msg_hdr.flags = kern_nimh.flags;
1686 retval = NaClImcSendTypedMessage(ndp, natp->effp, &kern_msg_hdr, flags);
1688 if (retval < 0) {
1690 * NaClWouldBlock uses TSD (for both the errno-based and
1691 * GetLastError()-based implementations), so this is threadsafe.
1693 if (0 != (flags & NACL_DONT_WAIT) && NaClWouldBlock()) {
1694 retval = -NACL_ABI_EAGAIN;
1695 } else {
1697 * TODO: the else case is some mysterious internal error.
1698 * Should we destroy the ndp or otherwise mark it as bad? Was
1699 * the failure atomic? Did it send some partial data? Linux
1700 * implementation appears okay.
1702 retval = -NACL_ABI_EIO;
1706 cleanup:
1707 for (i = 0; i < kern_nimh.desc_length; ++i) {
1708 if (NULL != kern_desc[i]) {
1709 NaClDescUnref(kern_desc[i]);
1710 kern_desc[i] = NULL;
1713 NaClDescUnref(ndp);
1714 cleanup_leave:
1715 NaClSysCommonThreadSyscallLeave(natp);
1716 NaClLog(3, "NaClCommonSysImc_Sendmsg: returning %d\n", retval);
1717 return retval;
1720 int32_t NaClCommonSysImc_Recvmsg(struct NaClAppThread *natp,
1721 int d,
1722 struct NaClImcMsgHdr *nimhp,
1723 int flags)
1725 int retval = -NACL_ABI_EINVAL;
1726 uintptr_t sysaddr;
1727 struct NaClImcMsgHdr *kern_nimhp;
1728 size_t i;
1729 struct NaClDesc *ndp;
1730 struct NaClImcMsgHdr kern_nimh;
1731 struct NaClImcMsgIoVec kern_iov[NACL_ABI_IMC_IOVEC_MAX];
1732 int *kern_descv;
1733 struct NaClImcTypedMsgHdr recv_hdr;
1734 struct NaClDesc *new_desc[NACL_ABI_IMC_DESC_MAX];
1735 size_t num_user_desc;
1737 NaClLog(3,
1738 ("Entered NaClCommonSysImc_RecvMsg(0x%08"PRIxPTR", %d,"
1739 " 0x%08"PRIxPTR")\n"),
1740 (uintptr_t) natp, d, (uintptr_t) nimhp);
1742 NaClSysCommonThreadSyscallEnter(natp);
1745 * First, we validate user-supplied message headers before
1746 * allocating a receive buffer.
1748 sysaddr = NaClUserToSysAddrRange(natp->nap,
1749 (uintptr_t) nimhp,
1750 sizeof *nimhp);
1751 if (kNaClBadAddress == sysaddr) {
1752 NaClLog(4, "NaClImcMsgHdr not in user address space\n");
1753 retval = -NACL_ABI_EFAULT;
1754 goto cleanup_leave;
1756 kern_nimhp = (struct NaClImcMsgHdr *) sysaddr;
1757 kern_nimh = *kern_nimhp; /* copy before validating */
1758 if (kern_nimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
1759 NaClLog(4, "gather/scatter array too large\n");
1760 retval = -NACL_ABI_EINVAL;
1761 goto cleanup_leave;
1763 if (kern_nimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
1764 NaClLog(4, "handle vector too long\n");
1765 retval = -NACL_ABI_EINVAL;
1766 goto cleanup_leave;
1769 if (kern_nimh.iov_length > 0) {
1770 sysaddr = NaClUserToSysAddrRange(natp->nap,
1771 (uintptr_t) kern_nimh.iov,
1772 (kern_nimh.iov_length
1773 * sizeof *kern_nimh.iov));
1774 if (kNaClBadAddress == sysaddr) {
1775 NaClLog(4, "gather/scatter array not in user address space\n");
1776 retval = -NACL_ABI_EFAULT;
1777 goto cleanup_leave;
1780 * Copy IOV array into kernel space. Validate this snapshot and do
1781 * user->kernel address conversions on this snapshot.
1783 memcpy(kern_iov, (void *) sysaddr,
1784 kern_nimh.iov_length * sizeof *kern_nimh.iov);
1786 * Convert every IOV base from user to system address, validate
1787 * range of bytes are really in user address space.
1790 for (i = 0; i < kern_nimh.iov_length; ++i) {
1791 sysaddr = NaClUserToSysAddrRange(natp->nap,
1792 (uintptr_t) kern_iov[i].base,
1793 kern_iov[i].length);
1794 if (kNaClBadAddress == sysaddr) {
1795 NaClLog(4, "iov number %"PRIdS" not entirely in user space\n", i);
1796 retval = -NACL_ABI_EFAULT;
1797 goto cleanup_leave;
1799 kern_iov[i].base = (void *) sysaddr;
1803 if (kern_nimh.desc_length > 0) {
1804 sysaddr = NaClUserToSysAddrRange(natp->nap,
1805 (uintptr_t) kern_nimh.descv,
1806 kern_nimh.desc_length * sizeof(int));
1807 if (kNaClBadAddress == sysaddr) {
1808 retval = -NACL_ABI_EFAULT;
1809 goto cleanup_leave;
1811 kern_descv = (int *) sysaddr;
1812 } else {
1813 /* ensure we will SEGV if there's a bug below */
1814 kern_descv = (int *) NULL;
1817 ndp = NaClGetDesc(natp->nap, d);
1818 if (NULL == ndp) {
1819 NaClLog(4, "receiving descriptor invalid\n");
1820 retval = -NACL_ABI_EBADF;
1821 goto cleanup_leave;
1824 recv_hdr.iov = kern_iov;
1825 recv_hdr.iov_length = kern_nimh.iov_length;
1827 recv_hdr.ndescv = new_desc;
1828 recv_hdr.ndesc_length = sizeof new_desc / sizeof new_desc[0];
1829 memset(new_desc, 0, sizeof new_desc);
1831 recv_hdr.flags = 0; /* just to make it obvious; IMC will clear it for us */
1833 retval = NaClImcRecvTypedMessage(ndp, natp->effp, &recv_hdr, flags);
1835 * retval is number of user payload bytes received and excludes the
1836 * header bytes.
1838 NaClLog(3, "NaClCommonSysImc_RecvMsg: NaClImcRecvTypedMessage returned %d\n",
1839 retval);
1840 if (retval < 0) {
1841 goto cleanup;
1845 * NB: recv_hdr.flags may contain NACL_ABI_MESSAGE_TRUNCATED and/or
1846 * NACL_ABI_HANDLES_TRUNCATED.
1849 kern_nimh.flags = recv_hdr.flags;
1852 * Now internalize the NaClHandles as NaClDesc objects.
1854 num_user_desc = recv_hdr.ndesc_length;
1856 if (kern_nimh.desc_length < num_user_desc) {
1857 kern_nimh.flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
1858 for (i = kern_nimh.desc_length; i < num_user_desc; ++i) {
1859 NaClDescUnref(new_desc[i]);
1860 new_desc[i] = NULL;
1862 num_user_desc = kern_nimh.desc_length;
1865 for (i = 0; i < num_user_desc; ++i) {
1866 /* write out to user space the descriptor numbers */
1867 kern_descv[i] = NaClSetAvail(natp->nap, new_desc[i]);
1868 new_desc[i] = NULL;
1871 kern_nimh.desc_length = num_user_desc;
1872 *kern_nimhp = kern_nimh;
1873 /* copy out updated desc count, flags */
1874 cleanup:
1875 if (retval < 0) {
1876 for (i = 0; i < sizeof new_desc/sizeof new_desc[0]; ++i) {
1877 if (NULL != new_desc[i]) {
1878 NaClDescUnref(new_desc[i]);
1879 new_desc[i] = NULL;
1883 NaClDescUnref(ndp);
1884 NaClLog(3, "NaClCommonSysImc_RecvMsg: returning %d\n", retval);
1885 cleanup_leave:
1886 NaClSysCommonThreadSyscallLeave(natp);
1887 return retval;
1890 int32_t NaClCommonSysImc_Mem_Obj_Create(struct NaClAppThread *natp,
1891 size_t size)
1893 int32_t retval = -NACL_ABI_EINVAL;
1894 struct NaClDescImcShm *shmp;
1895 NaClHandle mem_obj;
1896 off_t size_as_off;
1898 if (0 != (size & (NACL_MAP_PAGESIZE - 1))) {
1899 return -NACL_ABI_EINVAL;
1902 * TODO: policy about maximum shm object size should be
1903 * enforced here.
1905 size_as_off = (off_t) size;
1906 if (size_as_off < 0) {
1907 return -NACL_ABI_EINVAL;
1910 shmp = NULL;
1911 mem_obj = NACL_INVALID_HANDLE;
1913 NaClSysCommonThreadSyscallEnter(natp);
1915 shmp = malloc(sizeof *shmp);
1916 if (NULL == shmp) {
1917 retval = -NACL_ABI_ENOMEM;
1918 goto cleanup;
1920 mem_obj = NaClCreateMemoryObject(size);
1921 if (NACL_INVALID_HANDLE == mem_obj) {
1922 retval = -NACL_ABI_ENOMEM;
1923 goto cleanup;
1926 if (!NaClDescImcShmCtor(shmp, mem_obj, size_as_off)) {
1927 retval = -NACL_ABI_ENOMEM; /* is this reasonable? */
1928 goto cleanup;
1930 mem_obj = NACL_INVALID_HANDLE;
1932 retval = NaClSetAvail(natp->nap, (struct NaClDesc *) shmp);
1933 shmp = NULL;
1934 cleanup:
1935 if (shmp) {
1936 free(shmp);
1938 if (NACL_INVALID_HANDLE != mem_obj) {
1939 (void) NaClClose(mem_obj);
1941 NaClSysCommonThreadSyscallLeave(natp);
1943 return retval;
1946 int32_t NaClCommonDescSocketPair(struct NaClDesc **pair)
1948 int32_t retval = -NACL_ABI_EIO;
1949 struct NaClDescImcDesc *d0;
1950 struct NaClDescImcDesc *d1;
1951 NaClHandle sock_pair[2];
1954 * mark resources to enable easy cleanup
1956 d0 = NULL;
1957 d1 = NULL;
1958 sock_pair[0] = NACL_INVALID_HANDLE;
1959 sock_pair[1] = NACL_INVALID_HANDLE;
1961 if (NULL == (d0 = malloc(sizeof *d0))) {
1962 retval = -NACL_ABI_ENOMEM;
1963 goto cleanup;
1965 if (NULL == (d1 = malloc(sizeof *d1))) {
1966 retval = -NACL_ABI_ENOMEM;
1967 goto cleanup;
1969 if (0 != NaClSocketPair(sock_pair)) {
1970 NaClLog(1,
1971 "NaClCommonSysImc_Socket_Pair: IMC socket pair creation failed\n");
1972 retval = -NACL_ABI_ENFILE;
1973 goto cleanup;
1975 if (!NaClDescImcDescCtor(d0, sock_pair[0])) {
1976 retval = -NACL_ABI_ENFILE;
1977 goto cleanup;
1979 sock_pair[0] = NACL_INVALID_HANDLE; /* ctor took ownership */
1980 if (!NaClDescImcDescCtor(d1, sock_pair[1])) {
1981 retval = -NACL_ABI_ENFILE;
1982 goto cleanup;
1984 sock_pair[1] = NACL_INVALID_HANDLE; /* ctor took ownership */
1986 pair[0] = (struct NaClDesc *) d0;
1987 d0 = NULL;
1989 pair[1] = (struct NaClDesc *) d1;
1990 d1 = NULL;
1992 retval = 0;
1994 cleanup:
1995 if (NULL != d0) {
1996 NaClDescImcDescDtor((struct NaClDesc *) d0);
1998 if (NULL != d1) {
1999 NaClDescImcDescDtor((struct NaClDesc *) d1);
2001 if (NACL_INVALID_HANDLE != sock_pair[0]) {
2002 NaClClose(sock_pair[0]);
2004 if (NACL_INVALID_HANDLE != sock_pair[1]) {
2005 NaClClose(sock_pair[1]);
2008 free(d0);
2009 free(d1);
2011 return retval;
2014 int32_t NaClCommonSysImc_SocketPair(struct NaClAppThread *natp,
2015 int32_t *d_out)
2017 uintptr_t sysaddr;
2018 struct NaClDesc *pair[2];
2019 int32_t retval;
2021 NaClSysCommonThreadSyscallEnter(natp);
2023 sysaddr = NaClUserToSysAddrRange(natp->nap,
2024 (uintptr_t) d_out,
2025 2 * sizeof *d_out);
2026 if (kNaClBadAddress == sysaddr) {
2027 NaClLog(1,
2028 ("NaClCommonSysImc_Socket_Pair: bad output descriptor array "
2029 " (0x%08"PRIxPTR")\n"),
2030 (uintptr_t) d_out);
2031 retval = -NACL_ABI_EFAULT;
2032 goto cleanup;
2035 d_out = (int *) sysaddr;
2036 retval = NaClCommonDescSocketPair(pair);
2037 if (0 != retval) {
2038 goto cleanup;
2041 d_out[0] = NaClSetAvail(natp->nap, pair[0]);
2042 d_out[1] = NaClSetAvail(natp->nap, pair[1]);
2044 retval = 0;
2045 cleanup:
2046 NaClSysCommonThreadSyscallLeave(natp);
2047 return retval;
2050 int32_t NaClCommonSysTls_Init(struct NaClAppThread *natp,
2051 void *tdb,
2052 size_t size)
2054 int32_t retval = -NACL_ABI_EINVAL;
2055 uintptr_t sysaddr;
2057 NaClSysCommonThreadSyscallEnter(natp);
2059 /* Verify that the address in the app's range */
2060 sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) tdb, size);
2061 if (kNaClBadAddress == sysaddr) {
2062 retval = -NACL_ABI_EFAULT;
2063 goto cleanup;
2066 if (0 == NaClLdtChangeByteSelector(natp->user.gs >> 3,
2067 NACL_LDT_DESCRIPTOR_DATA,
2069 (void *) sysaddr,
2070 size)) {
2071 retval = -NACL_ABI_EINVAL;
2072 goto cleanup;
2074 retval = 0;
2075 cleanup:
2076 NaClSysCommonThreadSyscallLeave(natp);
2077 return retval;
2080 int32_t NaClCommonSysThread_Create(struct NaClAppThread *natp,
2081 void *eip,
2082 void *esp,
2083 void *tdb,
2084 size_t tdb_size)
2086 int32_t retval = -NACL_ABI_EINVAL;
2087 uintptr_t sys_tdb;
2089 NaClSysCommonThreadSyscallEnter(natp);
2091 /* make sure that the thread start function is in the text region */
2092 /* MarkS: this check shouldn't be necessary if the branch is done
2093 after segments are set up. */
2094 if ((uintptr_t) eip >= natp->nap->text_region_end) {
2095 retval = -NACL_ABI_EFAULT;
2096 goto cleanup;
2098 /* make sure that the thread start function is aligned */
2099 if (0 != ((natp->nap->align_boundary - 1) & (uintptr_t) eip)) {
2100 retval = -NACL_ABI_EINVAL;
2101 goto cleanup;
2103 /* we do not enforce stack alignment */
2104 if (kNaClBadAddress == NaClUserToSysAddr(natp->nap, (uintptr_t) esp)) {
2105 retval = -NACL_ABI_EFAULT;
2106 goto cleanup;
2108 sys_tdb = NaClUserToSysAddrRange(natp->nap, (uintptr_t) tdb, tdb_size);
2109 if (kNaClBadAddress == sys_tdb) {
2110 retval = -NACL_ABI_EFAULT;
2111 goto cleanup;
2113 retval = NaClCreateAdditionalThread(natp->nap,
2114 (uintptr_t) eip,
2115 (uintptr_t) esp,
2116 sys_tdb,
2117 tdb_size);
2118 cleanup:
2119 NaClSysCommonThreadSyscallLeave(natp);
2120 return retval;
2123 #if defined(HAVE_SDL)
2125 int32_t NaClCommonSysMultimedia_Init(struct NaClAppThread *natp,
2126 int subsys)
2128 int32_t retval = -NACL_ABI_EINVAL;
2130 NaClLog(3, "NaClBotSysMultimedia_Init is 0x%08"PRIxPTR"\n",
2131 (uintptr_t) NaClBotSysMultimedia_Init);
2132 NaClLog(3, "NaClClosure2Run_Init is 0x%08"PRIxPTR"\n",
2133 (uintptr_t) NaClClosure2Run);
2135 NaClSysCommonThreadSyscallEnter(natp);
2137 if (!natp->is_privileged && natp->nap->restrict_to_main_thread) {
2138 retval = -NACL_ABI_EIO;
2139 goto cleanup;
2142 NaClStartAsyncOp(natp,
2143 ((struct NaClClosure *)
2144 NaClClosure2Ctor(((void (*)(void *, void *))
2145 NaClBotSysMultimedia_Init),
2146 (void *) natp,
2147 (void *) subsys)));
2148 retval = NaClWaitForAsyncOp(natp);
2149 cleanup:
2150 NaClSysCommonThreadSyscallLeave(natp);
2151 return retval;
2155 int32_t NaClCommonSysMultimedia_Shutdown(struct NaClAppThread *natp)
2157 int32_t retval = -NACL_ABI_EINVAL;
2159 NaClLog(3, "NaClBotSysMultimedia_Shudown is 0x%08"PRIxPTR"\n",
2160 (uintptr_t) NaClBotSysMultimedia_Shutdown);
2161 NaClLog(3, "NaClClosure1Run_Init is 0x%08"PRIxPTR"\n",
2162 (uintptr_t) NaClClosure1Run);
2164 NaClSysCommonThreadSyscallEnter(natp);
2166 if (!natp->is_privileged && natp->nap->restrict_to_main_thread) {
2167 retval = -NACL_ABI_EIO;
2168 goto cleanup;
2171 NaClStartAsyncOp(natp,
2172 ((struct NaClClosure *)
2173 NaClClosure1Ctor(((void (*)(void *))
2174 NaClBotSysMultimedia_Shutdown),
2175 (void *) natp)));
2176 retval = NaClWaitForAsyncOp(natp);
2177 cleanup:
2178 NaClSysCommonThreadSyscallLeave(natp);
2179 return retval;
2183 int32_t NaClCommonSysVideo_Init(struct NaClAppThread *natp,
2184 int width,
2185 int height
2188 int32_t retval = -NACL_ABI_EINVAL;
2190 NaClSysCommonThreadSyscallEnter(natp);
2192 /* privileged syscall: forward to main thread */
2193 if (!natp->is_privileged && natp->nap->restrict_to_main_thread) {
2194 retval = -NACL_ABI_EIO;
2195 goto cleanup;
2198 /* make sure width & height are not unreasonable */
2199 if ((width < kNaClVideoMinWindowSize) ||
2200 (width > kNaClVideoMaxWindowSize) ||
2201 (height < kNaClVideoMinWindowSize) ||
2202 (height > kNaClVideoMaxWindowSize)) {
2203 NaClLog(LOG_ERROR, "NaClSysVideo_Init: invalid window size!\n");
2204 retval = -NACL_ABI_EINVAL;
2205 goto cleanup;
2208 /* width and height must also be multiples of 4 */
2209 if ((0 != (width & 0x3)) || (0 != (height & 0x3))) {
2210 NaClLog(LOG_ERROR,
2211 "NaClSysVideo_Init: width & height must be a multiple of 4!\n");
2212 retval = -NACL_ABI_EINVAL;
2213 goto cleanup;
2216 NaClLog(3, "NaClBotSysVideo_Init is 0x%08"PRIxPTR"\n",
2217 (uintptr_t) NaClBotSysVideo_Init);
2218 NaClLog(3, "NaClClosure4Run_Init is 0x%08"PRIxPTR"\n",
2219 (uintptr_t) NaClClosure4Run);
2220 NaClStartAsyncOp(natp,
2221 ((struct NaClClosure *)
2222 NaClClosure3Ctor(((void (*)(void *, void *, void *))
2223 NaClBotSysVideo_Init),
2224 (void *) natp,
2225 (void *) width,
2226 (void *) height)));
2227 retval = NaClWaitForAsyncOp(natp);
2228 cleanup:
2229 NaClSysCommonThreadSyscallLeave(natp);
2230 return retval;
2233 int32_t NaClCommonSysVideo_Shutdown(struct NaClAppThread *natp)
2235 int32_t retval;
2237 NaClSysCommonThreadSyscallEnter(natp);
2239 if (!natp->is_privileged && natp->nap->restrict_to_main_thread) {
2240 retval = -NACL_ABI_EIO;
2241 goto cleanup;
2244 NaClStartAsyncOp(natp,
2245 ((struct NaClClosure *)
2246 NaClClosure1Ctor(((void (*)(void *))
2247 NaClBotSysVideo_Shutdown),
2248 (void *) natp)));
2249 retval = NaClWaitForAsyncOp(natp);
2250 cleanup:
2251 NaClSysCommonThreadSyscallLeave(natp);
2252 return retval;
2256 int32_t NaClCommonSysVideo_Update(struct NaClAppThread *natp,
2257 const void *data)
2259 int32_t retval = -NACL_ABI_EINVAL;
2261 NaClSysCommonThreadSyscallEnter(natp);
2263 if (NULL == data) {
2264 retval = -NACL_ABI_EFAULT;
2265 goto cleanup;
2268 * further validation of data argument is deferred until bottom half
2269 * (the size of the data is not available from here)
2271 NaClStartAsyncOp(natp,
2272 ((struct NaClClosure *)
2273 NaClClosure2Ctor(((void (*)(void *, void *))
2274 NaClBotSysVideo_Update),
2275 (void *) natp,
2276 (void *) data)));
2277 retval = NaClWaitForAsyncOp(natp);
2278 cleanup:
2279 NaClSysCommonThreadSyscallLeave(natp);
2280 return retval;
2284 int32_t NaClCommonSysVideo_Poll_Event(struct NaClAppThread *natp,
2285 union NaClMultimediaEvent *event)
2287 int32_t retval = -NACL_ABI_EINVAL;
2288 uintptr_t sysaddr;
2290 NaClLog(3, "NaClBotSysVideo_Poll_Event is 0x%08"PRIxPTR"\n",
2291 (uintptr_t) NaClBotSysVideo_Poll_Event);
2292 NaClLog(3, "NaClClosure2Run_Init is 0x%08"PRIxPTR"\n",
2293 (uintptr_t) NaClClosure2Run);
2295 NaClSysCommonThreadSyscallEnter(natp);
2297 if (!natp->is_privileged && natp->nap->restrict_to_main_thread) {
2298 retval = -NACL_ABI_EIO;
2299 goto cleanup;
2301 sysaddr = NaClUserToSysAddrRange(natp->nap,
2302 (uintptr_t) event,
2303 sizeof(*event));
2304 if (kNaClBadAddress == sysaddr) {
2305 NaClLog(1, "NaClCommonSysVideo_Poll_Event: data address invalid\n");
2306 retval = -NACL_ABI_EFAULT;
2307 goto cleanup;
2309 NaClStartAsyncOp(natp,
2310 ((struct NaClClosure *)
2311 NaClClosure2Ctor(((void (*)(void *, void *))
2312 NaClBotSysVideo_Poll_Event),
2313 (void *) natp,
2314 (void *) sysaddr)));
2315 retval = NaClWaitForAsyncOp(natp);
2316 cleanup:
2317 NaClSysCommonThreadSyscallLeave(natp);
2318 return retval;
2322 int32_t NaClCommonSysAudio_Init(struct NaClAppThread *natp,
2323 enum NaClAudioFormat format,
2324 int desired_samples,
2325 int *obtained_samples)
2327 int32_t retval = -NACL_ABI_EINVAL;
2328 uintptr_t sysaddr;
2330 NaClLog(3, "NaClBotSysAudio_Init is 0x%08"PRIxPTR"\n",
2331 (uintptr_t) NaClBotSysAudio_Init);
2332 NaClLog(3, "NaClClosure4Run_Init is 0x%08"PRIxPTR"\n",
2333 (uintptr_t) NaClClosure4Run);
2335 NaClSysCommonThreadSyscallEnter(natp);
2337 if (!natp->is_privileged && natp->nap->restrict_to_main_thread) {
2338 retval = -NACL_ABI_EIO;
2339 goto cleanup;
2342 sysaddr = NaClUserToSysAddrRange(natp->nap,
2343 (uintptr_t) obtained_samples,
2344 sizeof(*obtained_samples));
2345 if (kNaClBadAddress == sysaddr) {
2346 NaClLog(1, "NaClCommonSysAudio_Init: input address invalid\n");
2347 retval = -NACL_ABI_EFAULT;
2348 goto cleanup;
2351 NaClStartAsyncOp(natp,
2352 ((struct NaClClosure *)
2353 NaClClosure4Ctor(((void (*)(void *, void *,
2354 void *, void *))
2355 NaClBotSysAudio_Init),
2356 (void *) natp,
2357 (void *) format,
2358 (void *) desired_samples,
2359 (void *) sysaddr)));
2360 retval = NaClWaitForAsyncOp(natp);
2361 cleanup:
2362 NaClSysCommonThreadSyscallLeave(natp);
2363 return retval;
2367 int32_t NaClCommonSysAudio_Shutdown(struct NaClAppThread *natp)
2369 int32_t retval = -NACL_ABI_EINVAL;
2371 NaClLog(3, "NaClBotSysAudio_Shutdown is 0x%08"PRIxPTR"\n",
2372 (uintptr_t) NaClBotSysAudio_Shutdown);
2373 NaClLog(3, "NaClClosure1Run_Init is 0x%08"PRIxPTR"\n",
2374 (uintptr_t) NaClClosure1Run);
2376 NaClSysCommonThreadSyscallEnter(natp);
2378 if (!natp->is_privileged && natp->nap->restrict_to_main_thread) {
2379 retval = -NACL_ABI_EIO;
2380 goto cleanup;
2383 NaClStartAsyncOp(natp,
2384 ((struct NaClClosure *)
2385 NaClClosure1Ctor(((void (*)(void *))
2386 NaClBotSysAudio_Shutdown),
2387 (void *) natp)));
2388 retval = NaClWaitForAsyncOp(natp);
2389 cleanup:
2390 NaClSysCommonThreadSyscallLeave(natp);
2391 return retval;
2394 #endif
2396 int32_t NaClCommonSysMutex_Create(struct NaClAppThread *natp)
2398 int32_t retval = -NACL_ABI_EINVAL;
2399 struct NaClDescMutex *desc;
2401 NaClSysCommonThreadSyscallEnter(natp);
2403 desc = malloc(sizeof(*desc));
2405 if (!desc || !NaClDescMutexCtor(desc)) {
2406 retval = -NACL_ABI_ENOMEM;
2407 goto cleanup;
2410 retval = NaClSetAvail(natp->nap, (struct NaClDesc *)desc);
2411 desc = NULL;
2412 cleanup:
2413 free(desc);
2414 NaClSysCommonThreadSyscallLeave(natp);
2415 return retval;
2418 int32_t NaClCommonSysMutex_Lock(struct NaClAppThread *natp,
2419 int32_t mutex_handle)
2421 int32_t retval = -NACL_ABI_EINVAL;
2422 struct NaClDesc *desc;
2424 NaClSysCommonThreadSyscallEnter(natp);
2426 desc = NaClGetDesc(natp->nap, mutex_handle);
2428 if (NULL == desc) {
2429 retval = -NACL_ABI_EBADF;
2430 goto cleanup;
2433 retval = (*desc->vtbl->Lock)(desc, natp->effp);
2434 NaClDescUnref(desc);
2436 cleanup:
2437 NaClSysCommonThreadSyscallLeave(natp);
2438 return retval;
2441 int32_t NaClCommonSysMutex_Unlock(struct NaClAppThread *natp,
2442 int32_t mutex_handle)
2444 int32_t retval = -NACL_ABI_EINVAL;
2445 struct NaClDesc *desc;
2447 NaClSysCommonThreadSyscallEnter(natp);
2449 desc = NaClGetDesc(natp->nap, mutex_handle);
2451 if (NULL == desc) {
2452 retval = -NACL_ABI_EBADF;
2453 goto cleanup;
2456 retval = (*desc->vtbl->Unlock)(desc, natp->effp);
2457 NaClDescUnref(desc);
2459 cleanup:
2460 NaClSysCommonThreadSyscallLeave(natp);
2461 return retval;
2464 int32_t NaClCommonSysMutex_Trylock(struct NaClAppThread *natp,
2465 int32_t mutex_handle)
2467 int32_t retval = -NACL_ABI_EINVAL;
2468 struct NaClDesc *desc;
2470 NaClSysCommonThreadSyscallEnter(natp);
2472 desc = NaClGetDesc(natp->nap, mutex_handle);
2474 if (NULL == desc) {
2475 retval = -NACL_ABI_EBADF;
2476 goto cleanup;
2479 retval = (*desc->vtbl->TryLock)(desc, natp->effp);
2480 NaClDescUnref(desc);
2482 cleanup:
2483 NaClSysCommonThreadSyscallLeave(natp);
2484 return retval;
2487 int32_t NaClCommonSysCond_Create(struct NaClAppThread *natp)
2489 int32_t retval = -NACL_ABI_EINVAL;
2490 struct NaClDescCondVar *desc;
2492 NaClSysCommonThreadSyscallEnter(natp);
2494 desc = malloc(sizeof(*desc));
2496 if (!desc || !NaClDescCondVarCtor(desc)) {
2497 retval = -NACL_ABI_ENOMEM;
2498 goto cleanup;
2501 retval = NaClSetAvail(natp->nap, (struct NaClDesc *)desc);
2502 desc = NULL;
2503 cleanup:
2504 free(desc);
2505 NaClSysCommonThreadSyscallLeave(natp);
2506 return retval;
2509 int32_t NaClCommonSysCond_Wait(struct NaClAppThread *natp,
2510 int32_t cond_handle,
2511 int32_t mutex_handle)
2513 int32_t retval = -NACL_ABI_EINVAL;
2514 struct NaClDesc *cv_desc;
2515 struct NaClDesc *mutex_desc;
2517 NaClSysCommonThreadSyscallEnter(natp);
2519 cv_desc = NaClGetDesc(natp->nap, cond_handle);
2521 if (NULL == cv_desc) {
2522 retval = -NACL_ABI_EBADF;
2523 goto cleanup;
2526 mutex_desc = NaClGetDesc(natp->nap, mutex_handle);
2527 if (NULL == mutex_desc) {
2528 NaClDescUnref(cv_desc);
2529 retval = -NACL_ABI_EBADF;
2530 goto cleanup;
2533 retval = (*cv_desc->vtbl->Wait)(cv_desc, natp->effp, mutex_desc);
2534 NaClDescUnref(cv_desc);
2535 NaClDescUnref(mutex_desc);
2537 cleanup:
2538 NaClSysCommonThreadSyscallLeave(natp);
2539 return retval;
2542 int32_t NaClCommonSysCond_Signal(struct NaClAppThread *natp,
2543 int32_t cond_handle)
2545 int32_t retval = -NACL_ABI_EINVAL;
2546 struct NaClDesc *desc;
2548 NaClSysCommonThreadSyscallEnter(natp);
2550 desc = NaClGetDesc(natp->nap, cond_handle);
2552 if (NULL == desc) {
2553 retval = -NACL_ABI_EBADF;
2554 goto cleanup;
2557 retval = (*desc->vtbl->Signal)(desc, natp->effp);
2558 NaClDescUnref(desc);
2559 cleanup:
2560 NaClSysCommonThreadSyscallLeave(natp);
2561 return retval;
2564 int32_t NaClCommonSysCond_Broadcast(struct NaClAppThread *natp,
2565 int32_t cond_handle)
2567 struct NaClDesc *desc;
2568 int32_t retval = -NACL_ABI_EINVAL;
2570 NaClSysCommonThreadSyscallEnter(natp);
2572 desc = NaClGetDesc(natp->nap, cond_handle);
2574 if (NULL == desc) {
2575 retval = -NACL_ABI_EBADF;
2576 goto cleanup;
2579 retval = (*desc->vtbl->Broadcast)(desc, natp->effp);
2580 NaClDescUnref(desc);
2582 cleanup:
2583 NaClSysCommonThreadSyscallLeave(natp);
2584 return retval;
2587 int32_t NaClCommonSysCond_Timed_Wait_Abs(struct NaClAppThread *natp,
2588 int32_t cond_handle,
2589 int32_t mutex_handle,
2590 struct nacl_abi_timespec *ts)
2592 int32_t retval = -NACL_ABI_EINVAL;
2593 struct NaClDesc *cv_desc;
2594 struct NaClDesc *mutex_desc;
2595 uintptr_t sys_ts;
2596 struct nacl_abi_timespec trusted_ts;
2598 NaClSysCommonThreadSyscallEnter(natp);
2600 sys_ts = NaClUserToSysAddrRange(natp->nap,
2601 (uintptr_t) ts,
2602 sizeof(*ts));
2603 if (kNaClBadAddress == sys_ts) {
2604 retval = -NACL_ABI_EFAULT;
2605 goto cleanup;
2607 /* TODO: validate ts - do we have a limit for time to wait? */
2608 memcpy(&trusted_ts, (void*) sys_ts, sizeof(trusted_ts));
2610 cv_desc = NaClGetDesc(natp->nap, cond_handle);
2611 if (NULL == cv_desc) {
2612 retval = -NACL_ABI_EBADF;
2613 goto cleanup;
2616 mutex_desc = NaClGetDesc(natp->nap, mutex_handle);
2617 if (NULL == mutex_desc) {
2618 NaClDescUnref(cv_desc);
2619 retval = -NACL_ABI_EBADF;
2620 goto cleanup;
2623 retval = (*cv_desc->vtbl->TimedWaitAbs)(cv_desc, natp->effp, mutex_desc,
2624 &trusted_ts);
2625 NaClDescUnref(cv_desc);
2626 NaClDescUnref(mutex_desc);
2627 cleanup:
2628 NaClSysCommonThreadSyscallLeave(natp);
2629 return retval;
2632 int32_t NaClCommonSysSem_Create(struct NaClAppThread *natp,
2633 int32_t init_value)
2635 int32_t retval = -NACL_ABI_EINVAL;
2636 struct NaClDescSemaphore *desc;
2638 NaClSysCommonThreadSyscallEnter(natp);
2640 desc = malloc(sizeof(*desc));
2642 if (!desc || !NaClDescSemaphoreCtor(desc, init_value)) {
2643 retval = -NACL_ABI_ENOMEM;
2644 goto cleanup;
2647 retval = NaClSetAvail(natp->nap, (struct NaClDesc *) desc);
2648 desc = NULL;
2649 cleanup:
2650 free(desc);
2651 NaClSysCommonThreadSyscallLeave(natp);
2652 return retval;
2656 int32_t NaClCommonSysSem_Wait(struct NaClAppThread *natp,
2657 int32_t sem_handle)
2659 int32_t retval = -NACL_ABI_EINVAL;
2660 struct NaClDesc *desc;
2662 NaClSysCommonThreadSyscallEnter(natp);
2664 desc = NaClGetDesc(natp->nap, sem_handle);
2666 if (NULL == desc) {
2667 retval = -NACL_ABI_EBADF;
2668 goto cleanup;
2672 * TODO: we have to decide on the syscall API: do we
2673 * switch to read/write/ioctl API or do we stay with the more
2674 * detailed API. Anyway, using a single syscall for waiting on all
2675 * synchronization objects makes sense.
2677 retval = (*desc->vtbl->SemWait)(desc, natp->effp);
2678 NaClDescUnref(desc);
2679 cleanup:
2680 NaClSysCommonThreadSyscallLeave(natp);
2681 return retval;
2684 int32_t NaClCommonSysSem_Post(struct NaClAppThread *natp,
2685 int32_t sem_handle)
2687 int32_t retval = -NACL_ABI_EINVAL;
2688 struct NaClDesc *desc;
2690 NaClSysCommonThreadSyscallEnter(natp);
2692 desc = NaClGetDesc(natp->nap, sem_handle);
2694 if (NULL == desc) {
2695 retval = -NACL_ABI_EBADF;
2696 goto cleanup;
2699 retval = (*desc->vtbl->Post)(desc, natp->effp);
2700 NaClDescUnref(desc);
2701 cleanup:
2702 NaClSysCommonThreadSyscallLeave(natp);
2703 return retval;
2706 int32_t NaClCommonSysSem_Get_Value(struct NaClAppThread *natp,
2707 int32_t sem_handle)
2709 int32_t retval = -NACL_ABI_EINVAL;
2710 struct NaClDesc *desc;
2712 NaClSysCommonThreadSyscallEnter(natp);
2714 desc = NaClGetDesc(natp->nap, sem_handle);
2716 if (NULL == desc) {
2717 retval = -NACL_ABI_EBADF;
2718 goto cleanup;
2721 retval = (*desc->vtbl->GetValue)(desc, natp->effp);
2722 NaClDescUnref(desc);
2723 cleanup:
2724 NaClSysCommonThreadSyscallLeave(natp);
2725 return retval;