2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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.
37 #include <sys/types.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"
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"
90 # error "what target platform are you on?"
94 # include "native_client/service_runtime/include/sys/audio_video.h"
95 # include "native_client/service_runtime/nacl_bottom_half.h"
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
)
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
);
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");
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
:
168 case NACL_APP_THREAD_SUICIDE_PENDING
:
169 NaClXMutexUnlock(&natp
->mu
);
170 NaClSysCommonThreadSuicide(natp
);
173 case NACL_APP_THREAD_DEAD
:
174 NaClLog(LOG_FATAL
, "Dead thread at NaClSysCommonThreadSyscallLeave\n");
178 NaClXMutexUnlock(&natp
->mu
);
181 int32_t NaClSetBreak(struct NaClAppThread
*natp
,
186 struct NaClVmmapIter iter
;
187 struct NaClVmmapEntry
*ent
;
188 struct NaClVmmapEntry
*next_ent
;
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
;
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",
214 goto cleanup_no_lock
;
216 if (new_break
< nap
->data_end
) {
219 if (new_break
<= nap
->break_addr
) {
221 nap
->break_addr
= new_break
;
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
,
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
;
265 NaClVmmapIterIncr(&iter
);
266 if (!NaClVmmapIterAtEnd(&iter
)
267 && ((next_ent
= NaClVmmapIterStar(&iter
))->page_num
268 <= last_internal_page
)) {
269 /* ran into next segment! */
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
);
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
)
287 if (0 != NaCl_mprotect((void *) NaClUserToSys(nap
, start_new_region
),
289 PROT_READ
| PROT_WRITE
)) {
291 ("Could not mprotect(0x%08"PRIxPTR
", 0x%08"PRIxPTR
", "
292 "PROT_READ|PROT_WRITE)\n"),
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
;
304 (void) NaClMutexUnlock(&nap
->mu
);
306 NaClSysCommonThreadSyscallLeave(natp
);
308 NaClLog(2, "NaClSetBreak: returning 0x%08"PRIx32
"\n", 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
,
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");\
351 FLOG(flags
, NACL_ABI_O_CREAT
);
352 FLOG(flags
, NACL_ABI_O_TRUNC
);
353 FLOG(flags
, NACL_ABI_O_APPEND
);
356 if (NaClAclBypassChecks
) {
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
,
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.
378 "NaClStatAclCheck(0x%08"PRIxPTR
", %s)\n", (uintptr_t) nap
, path
);
379 if (NaClAclBypassChecks
) {
382 return -NACL_ABI_EACCES
;
385 int32_t NaClIoctlAclCheck(struct NaClApp
*nap
,
386 struct NaClDesc
*ndp
,
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
) {
396 return -NACL_ABI_EINVAL
;
399 int32_t NaClCommonSysExit(struct NaClAppThread
*natp
,
404 NaClSysCommonThreadSyscallEnter(natp
);
407 NaClSyncQueueQuit(&nap
->work_queue
);
409 NaClXMutexLock(&nap
->mu
);
410 nap
->exit_status
= status
;
412 NaClCondVarSignal(&nap
->cv
);
413 NaClXMutexUnlock(&nap
->mu
);
415 NaClSysCommonThreadSuicide(natp
);
417 return -NACL_ABI_EINVAL
;
420 int32_t NaClCommonSysThreadExit(struct NaClAppThread
*natp
,
423 uintptr_t sys_stack_flag
;
426 NaClLog(4, "NaclCommonSysThreadExit(0x%08"PRIxPTR
", 0x%08"PRIxPTR
"\n",
428 (uintptr_t) stack_flag
);
429 NaClSysCommonThreadSyscallEnter(natp
);
431 * NB: NaClThreads are never joinable, but the abstraction for NaClApps
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
);
449 return -NACL_ABI_EINVAL
;
452 int32_t NaClCommonSysOpen(struct NaClAppThread
*natp
,
457 uint32_t retval
= -NACL_ABI_EINVAL
;
459 char path
[NACL_CONFIG_PATH_MAX
];
461 struct nacl_abi_stat stbuf
;
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
;
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",
480 flags
&= allowed_flags
;
482 if (0 != (mode
& ~0600)) {
483 NaClLog(LOG_INFO
, "IGNORING Invalid access mode bits 0%o\n", mode
);
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
);
500 * make sure sysaddr is a string, and the whole string is in app
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
;
514 retval
= NaClOpenAclCheck(natp
->nap
, path
, flags
, mode
);
516 NaClLog(3, "Open ACL check rejected \"%s\".\n", path
);
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
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
);
537 retval
= -NACL_ABI_ENOMEM
;
540 retval
= NaClHostDirOpen(hd
, path
);
541 NaClLog(LOG_INFO
, "NaClHostDirOpen(0x%08"PRIxPTR
", %s) returned %d\n",
542 (uintptr_t) hd
, path
, retval
);
544 retval
= NaClSetAvail(natp
->nap
,
545 ((struct NaClDesc
*) NaClDescDirDescMake(hd
)));
546 NaClLog(LOG_INFO
, "Entered directory into open file table at %d\n",
550 struct NaClHostDesc
*hd
;
552 hd
= malloc(sizeof *hd
);
554 retval
= -NACL_ABI_ENOMEM
;
557 retval
= NaClHostDescOpen(hd
, path
, flags
, mode
);
559 "NaClHostDescOpen(0x%08"PRIxPTR
", %s, 0%o, 0%o) returned %d\n",
560 (uintptr_t) hd
, path
, flags
, mode
, retval
);
562 retval
= NaClSetAvail(natp
->nap
,
563 ((struct NaClDesc
*) NaClDescIoDescMake(hd
)));
564 NaClLog(LOG_INFO
, "Entered into open file table at %d\n", retval
);
568 NaClSysCommonThreadSyscallLeave(natp
);
573 int32_t NaClCommonSysClose(struct NaClAppThread
*natp
,
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
);
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",
593 retval
= (*ndp
->vtbl
->Close
)(ndp
, natp
->effp
); /* Unref */
596 NaClSysCommonThreadSyscallLeave(natp
);
600 int32_t NaClCommonSysGetdents(struct NaClAppThread
*natp
,
605 int retval
= -NACL_ABI_EINVAL
;
607 struct NaClDesc
*ndp
;
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
;
622 ndp
= NaClGetDesc(natp
->nap
, d
);
624 retval
= -NACL_ABI_EBADF
;
627 retval
= (*ndp
->vtbl
->Getdents
)(ndp
, natp
->effp
, (void *) sysaddr
, count
);
629 NaClLog(4, "getdents returned %d bytes\n", retval
);
630 NaClLog(8, "getdents result: %.*s\n", retval
, (char *) sysaddr
);
632 NaClLog(4, "getdents returned %d\n", retval
);
637 NaClSysCommonThreadSyscallLeave(natp
);
642 int32_t NaClCommonSysRead(struct NaClAppThread
*natp
,
647 int32_t retval
= -NACL_ABI_EINVAL
;
649 struct NaClDesc
*ndp
;
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
;
663 ndp
= NaClGetDesc(natp
->nap
, d
);
665 retval
= -NACL_ABI_EBADF
;
668 retval
= (*ndp
->vtbl
->Read
)(ndp
, natp
->effp
, (void *) sysaddr
, count
);
670 NaClLog(4, "read returned %d bytes\n", retval
);
671 NaClLog(8, "read result: %.*s\n",
672 retval
, (char *) sysaddr
);
674 NaClLog(4, "read returned %d\n", retval
);
678 NaClSysCommonThreadSyscallLeave(natp
);
683 int32_t NaClCommonSysWrite(struct NaClAppThread
*natp
,
688 int32_t retval
= -NACL_ABI_EINVAL
;
690 struct NaClDesc
*ndp
;
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
;
705 NaClLog(4, "In NaClSysWrite(%d, %.*s, %"PRIdS
")\n",
706 d
, (int) count
, (char *) sysaddr
, count
);
708 ndp
= NaClGetDesc(natp
->nap
, d
);
710 retval
= -NACL_ABI_EBADF
;
713 retval
= (*ndp
->vtbl
->Write
)(ndp
, natp
->effp
, (void *) sysaddr
, count
);
717 NaClSysCommonThreadSyscallLeave(natp
);
722 int32_t NaClCommonSysLseek(struct NaClAppThread
*natp
,
727 int retval
= -NACL_ABI_EINVAL
;
728 struct NaClDesc
*ndp
;
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
);
739 retval
= -NACL_ABI_EBADF
;
742 retval
= (*ndp
->vtbl
->Seek
)(ndp
, natp
->effp
, offset
, whence
);
745 NaClSysCommonThreadSyscallLeave(natp
);
749 int32_t NaClCommonSysIoctl(struct NaClAppThread
*natp
,
754 int retval
= -NACL_ABI_EINVAL
;
756 struct NaClDesc
*ndp
;
758 NaClLog(4, "In NaClSysIoctl(%d, %d, 0x%08"PRIxPTR
")\n", d
, request
,
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
);
779 NaClLog(4, "bad desc\n");
780 retval
= -NACL_ABI_EBADF
;
784 retval
= NaClIoctlAclCheck(natp
->nap
, ndp
, request
, arg
);
786 NaClLog(3, "Ioctl ACL check rejected descriptor %d\n", d
);
790 retval
= (*ndp
->vtbl
->Ioctl
)(ndp
, natp
->effp
, request
, (void *) sysaddr
);
794 NaClSysCommonThreadSyscallLeave(natp
);
798 int32_t NaClCommonSysFstat(struct NaClAppThread
*natp
,
800 struct nacl_abi_stat
*nasp
)
802 int32_t retval
= -NACL_ABI_EINVAL
;
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
;
817 ndp
= NaClGetDesc(natp
->nap
, d
);
819 NaClLog(4, "bad desc\n");
820 retval
= -NACL_ABI_EBADF
;
823 retval
= (*ndp
->vtbl
->Fstat
)(ndp
, natp
->effp
,
824 (struct nacl_abi_stat
*) sysaddr
);
827 NaClSysCommonThreadSyscallLeave(natp
);
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
];
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
;
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
);
867 * make sure sysaddr is a string, and the whole string is in app
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
;
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
;
890 retval
= NaClStatAclCheck(natp
->nap
, path
);
896 * Perform a host stat.
898 retval
= NaClHostDescStat(path
, (struct nacl_abi_stat
*) sysbufaddr
);
900 NaClSysCommonThreadSyscallLeave(natp
);
904 void NaClCommonUtilUpdateAddrMap(struct NaClAppThread
*natp
,
908 struct NaClDesc
*backing_desc
,
909 size_t backing_bytes
,
914 struct NaClMemObj
*nmop
;
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
,
923 usraddr
= NaClSysToUser(natp
->nap
, sysaddr
);
925 /* delete_mem -> NULL == backing_desc */
926 if (NULL
!= backing_desc
) {
929 ("invariant of delete_mem implies backing_desc NULL"
932 nmop
= NaClMemObjMake(backing_desc
, backing_bytes
, offset_bytes
);
935 NaClVmmapUpdate(&natp
->nap
->mem_map
,
936 usraddr
>> NACL_PAGESHIFT
,
937 nbytes
>> NACL_PAGESHIFT
,
944 int NaClSysCommonAddrRangeContainsExecutablePages_mu(struct NaClApp
*nap
,
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
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
;
970 VerifyAndMapCode(struct NaClAppThread
*natp
, struct NaClDesc
*ndp
,
971 uintptr_t dest_addr
, nacl_abi_off_t offset
, size_t length
)
974 struct NCValidatorState
*vstate
;
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
);
992 read_size
= ndp
->vtbl
->Read(ndp
, natp
->effp
, temp_addr
, length
);
997 if (read_size
!= length
) {
998 retval
= -NACL_ABI_EINVAL
;
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
;
1009 NCValidateSegment((uint8_t *) temp_addr
, (uintptr_t) temp_addr
,
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
;
1019 if (mprotect(temp_addr
, length
, PROT_READ
| PROT_EXEC
) < 0) {
1020 retval
= -NACL_ABI_EPERM
;
1023 /* Linux-specific */
1024 if (mremap(temp_addr
, length
, length
, MREMAP_MAYMOVE
| MREMAP_FIXED
,
1025 dest_addr
) == MAP_FAILED
) {
1026 retval
= -NACL_ABI_EPERM
;
1032 if (munmap(temp_addr
, length
))
1033 NaClLog(LOG_ERROR
, "munmap of temporary space failed");
1039 /* Warning: sizeof(nacl_abi_off_t)!=sizeof(off_t) on OSX */
1040 int32_t NaClCommonSysMmap(struct NaClAppThread
*natp
,
1046 nacl_abi_off_t offset
)
1048 int32_t retval
= -NACL_ABI_EINVAL
;
1050 struct NaClDesc
*ndp
;
1056 int holding_app_lock
;
1057 struct NaClMemObj
*nmop
;
1058 struct nacl_abi_stat stbuf
;
1059 size_t alloc_rounded_length
;
1062 size_t alloc_rounded_file_bytes
;
1063 size_t start_of_inaccessible
;
1065 holding_app_lock
= 0;
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
;
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
1093 ndp
= NaClGetDesc(natp
->nap
, fd
);
1095 retval
= -NACL_ABI_EBADF
;
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
)) {
1113 ("NaClSysMmap: file offset 0x%08"PRIxPTR
" not multiple"
1114 " of allocation size\n"),
1115 (uintptr_t) offset
);
1116 retval
= -NACL_ABI_EINVAL
;
1121 retval
= -NACL_ABI_EINVAL
;
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
);
1132 * sentinel values that are bigger than the addr space
1135 file_bytes
= file_size
;
1136 alloc_rounded_file_bytes
= file_size
;
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
);
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
;
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
;
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
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.
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
);
1223 retval
= -NACL_ABI_ENOMEM
;
1226 usraddr
= usrpage
<< NACL_PAGESHIFT
;
1227 NaClLog(4, "NaClSysMmap: new starting addr: 0x%08"PRIxPTR
"\n", usraddr
);
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
,
1236 (alloc_rounded_length
1237 >> NACL_PAGESHIFT
));
1238 NaClLog(4, "NaClSysMmap: FindSpaceAboveHint: page 0x%05"PRIxPTR
"\n",
1241 NaClLog(4, "NaClSysMmap: hint failed, doing generic allocation\n");
1242 usrpage
= NaClVmmapFindMapSpace(&natp
->nap
->mem_map
,
1243 alloc_rounded_length
>> NACL_PAGESHIFT
);
1246 retval
= -NACL_ABI_ENOMEM
;
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
)) {
1259 ("NaClSysMmap: start address (0x%08"PRIxPTR
") outside address"
1262 retval
= -NACL_ABI_EINVAL
;
1265 endaddr
= usraddr
+ alloc_rounded_length
;
1266 if (endaddr
< usraddr
) {
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
;
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
)) {
1284 ("NaClSysMmap: end address (0x%08"PRIxPTR
") is beyond"
1285 " the end of the address space\n"),
1287 retval
= -NACL_ABI_EINVAL
;
1291 if (NaClSysCommonAddrRangeContainsExecutablePages_mu(natp
->nap
,
1294 NaClLog(2, "NaClSysMmap: region contains executable pages\n");
1295 retval
= -NACL_ABI_EINVAL
;
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
;
1323 sysaddr
= NaClUserToSys(natp
->nap
, usraddr
);
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
,
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
,
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
))
1362 map_result
= (void *) sysaddr
;
1366 * "Small" negative integers are errno values. Larger ones are
1367 * virtual addresses.
1369 if (NaClIsNegErrno((int) map_result
)) {
1371 ("NaClSysMmap: Map failed, but we"
1372 " cannot handle address space move, error %d"),
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);
1387 /* record change for file-backed memory */
1388 NaClCommonUtilUpdateAddrMap(natp
, sysaddr
, length
, NaClProtMap(prot
),
1389 ndp
, file_size
, offset
, 0);
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
;
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
),
1406 NACL_ABI_MAP_ANONYMOUS
| NACL_ABI_MAP_PRIVATE
,
1408 if (NaClIsNegErrno(retval
)) {
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
);
1415 NaClCommonUtilUpdateAddrMap(natp
, sysaddr
+ length
, map_len
,
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
;
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
,
1429 retval
= NaClHostDescMap((struct NaClHostDesc
*) NULL
,
1430 (void *) (sysaddr
+ start_of_inaccessible
),
1433 NACL_ABI_MAP_ANONYMOUS
| NACL_ABI_MAP_PRIVATE
,
1435 if (NaClIsNegErrno(retval
)) {
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
,
1443 NaClCommonUtilUpdateAddrMap(natp
, sysaddr
+ start_of_inaccessible
,
1445 (struct NaClDesc
*) NULL
, 0,
1448 NaClLog(3, "NaClSysMmap: got address 0x%08"PRIxPTR
"\n",
1449 (uintptr_t) map_result
);
1453 if (holding_app_lock
) {
1454 NaClXMutexUnlock(&natp
->nap
->mu
);
1459 if (NaClIsNegErrno((uintptr_t) retval
)) {
1463 NaClSysCommonThreadSyscallLeave(natp
);
1465 NaClLog(3, "NaClSysMmap: returning 0x%08x\n", retval
);
1469 int32_t NaClCommonSysImc_MakeBoundSock(struct NaClAppThread
*natp
,
1473 * Create a bound socket descriptor and a socket address descriptor.
1476 int32_t retval
= -NACL_ABI_EINVAL
;
1478 struct NaClDesc
*pair
[2];
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
,
1490 if (kNaClBadAddress
== sys_sap
) {
1491 NaClLog(3, " illegal address\n");
1492 retval
= -NACL_ABI_EFAULT
;
1496 retval
= NaClCommonDescMakeBoundSock(pair
);
1501 ((int *) sys_sap
)[0] = NaClSetAvail(natp
->nap
, pair
[0]);
1502 ((int *) sys_sap
)[1] = NaClSetAvail(natp
->nap
, pair
[1]);
1505 NaClSysCommonThreadSyscallLeave(natp
);
1510 int32_t NaClCommonSysImc_Accept(struct NaClAppThread
*natp
,
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
);
1523 retval
= -NACL_ABI_EBADF
;
1525 retval
= (*ndp
->vtbl
->AcceptConn
)(ndp
, natp
->effp
);
1529 NaClSysCommonThreadSyscallLeave(natp
);
1533 int32_t NaClCommonSysImc_Connect(struct NaClAppThread
*natp
,
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
);
1546 retval
= -NACL_ABI_EBADF
;
1548 retval
= (*ndp
->vtbl
->ConnectAddr
)(ndp
, natp
->effp
);
1552 NaClSysCommonThreadSyscallLeave(natp
);
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
1562 int32_t NaClCommonSysImc_Sendmsg(struct NaClAppThread
*natp
,
1564 struct NaClImcMsgHdr
*nimhp
,
1567 int32_t retval
= -NACL_ABI_EINVAL
;
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
;
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
,
1588 if (kNaClBadAddress
== sysaddr
) {
1589 NaClLog(4, "NaClImcMsgHdr not in user address space\n");
1590 retval
= -NACL_ABI_EFAULT
;
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
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
;
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
;
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
;
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
;
1639 kern_iov
[i
].base
= (void *) sysaddr
;
1643 ndp
= NaClGetDesc(natp
->nap
, d
);
1645 retval
= -NACL_ABI_EBADF
;
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;
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
;
1671 * NB: for each descv entry, we read from NaCl app address space
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
;
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
);
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
;
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
;
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
;
1715 NaClSysCommonThreadSyscallLeave(natp
);
1716 NaClLog(3, "NaClCommonSysImc_Sendmsg: returning %d\n", retval
);
1720 int32_t NaClCommonSysImc_Recvmsg(struct NaClAppThread
*natp
,
1722 struct NaClImcMsgHdr
*nimhp
,
1725 int retval
= -NACL_ABI_EINVAL
;
1727 struct NaClImcMsgHdr
*kern_nimhp
;
1729 struct NaClDesc
*ndp
;
1730 struct NaClImcMsgHdr kern_nimh
;
1731 struct NaClImcMsgIoVec kern_iov
[NACL_ABI_IMC_IOVEC_MAX
];
1733 struct NaClImcTypedMsgHdr recv_hdr
;
1734 struct NaClDesc
*new_desc
[NACL_ABI_IMC_DESC_MAX
];
1735 size_t num_user_desc
;
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
,
1751 if (kNaClBadAddress
== sysaddr
) {
1752 NaClLog(4, "NaClImcMsgHdr not in user address space\n");
1753 retval
= -NACL_ABI_EFAULT
;
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
;
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
;
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
;
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
;
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
;
1811 kern_descv
= (int *) sysaddr
;
1813 /* ensure we will SEGV if there's a bug below */
1814 kern_descv
= (int *) NULL
;
1817 ndp
= NaClGetDesc(natp
->nap
, d
);
1819 NaClLog(4, "receiving descriptor invalid\n");
1820 retval
= -NACL_ABI_EBADF
;
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
1838 NaClLog(3, "NaClCommonSysImc_RecvMsg: NaClImcRecvTypedMessage returned %d\n",
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
]);
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
]);
1871 kern_nimh
.desc_length
= num_user_desc
;
1872 *kern_nimhp
= kern_nimh
;
1873 /* copy out updated desc count, flags */
1876 for (i
= 0; i
< sizeof new_desc
/sizeof new_desc
[0]; ++i
) {
1877 if (NULL
!= new_desc
[i
]) {
1878 NaClDescUnref(new_desc
[i
]);
1884 NaClLog(3, "NaClCommonSysImc_RecvMsg: returning %d\n", retval
);
1886 NaClSysCommonThreadSyscallLeave(natp
);
1890 int32_t NaClCommonSysImc_Mem_Obj_Create(struct NaClAppThread
*natp
,
1893 int32_t retval
= -NACL_ABI_EINVAL
;
1894 struct NaClDescImcShm
*shmp
;
1898 if (0 != (size
& (NACL_MAP_PAGESIZE
- 1))) {
1899 return -NACL_ABI_EINVAL
;
1902 * TODO: policy about maximum shm object size should be
1905 size_as_off
= (off_t
) size
;
1906 if (size_as_off
< 0) {
1907 return -NACL_ABI_EINVAL
;
1911 mem_obj
= NACL_INVALID_HANDLE
;
1913 NaClSysCommonThreadSyscallEnter(natp
);
1915 shmp
= malloc(sizeof *shmp
);
1917 retval
= -NACL_ABI_ENOMEM
;
1920 mem_obj
= NaClCreateMemoryObject(size
);
1921 if (NACL_INVALID_HANDLE
== mem_obj
) {
1922 retval
= -NACL_ABI_ENOMEM
;
1926 if (!NaClDescImcShmCtor(shmp
, mem_obj
, size_as_off
)) {
1927 retval
= -NACL_ABI_ENOMEM
; /* is this reasonable? */
1930 mem_obj
= NACL_INVALID_HANDLE
;
1932 retval
= NaClSetAvail(natp
->nap
, (struct NaClDesc
*) shmp
);
1938 if (NACL_INVALID_HANDLE
!= mem_obj
) {
1939 (void) NaClClose(mem_obj
);
1941 NaClSysCommonThreadSyscallLeave(natp
);
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
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
;
1965 if (NULL
== (d1
= malloc(sizeof *d1
))) {
1966 retval
= -NACL_ABI_ENOMEM
;
1969 if (0 != NaClSocketPair(sock_pair
)) {
1971 "NaClCommonSysImc_Socket_Pair: IMC socket pair creation failed\n");
1972 retval
= -NACL_ABI_ENFILE
;
1975 if (!NaClDescImcDescCtor(d0
, sock_pair
[0])) {
1976 retval
= -NACL_ABI_ENFILE
;
1979 sock_pair
[0] = NACL_INVALID_HANDLE
; /* ctor took ownership */
1980 if (!NaClDescImcDescCtor(d1
, sock_pair
[1])) {
1981 retval
= -NACL_ABI_ENFILE
;
1984 sock_pair
[1] = NACL_INVALID_HANDLE
; /* ctor took ownership */
1986 pair
[0] = (struct NaClDesc
*) d0
;
1989 pair
[1] = (struct NaClDesc
*) d1
;
1996 NaClDescImcDescDtor((struct NaClDesc
*) d0
);
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]);
2014 int32_t NaClCommonSysImc_SocketPair(struct NaClAppThread
*natp
,
2018 struct NaClDesc
*pair
[2];
2021 NaClSysCommonThreadSyscallEnter(natp
);
2023 sysaddr
= NaClUserToSysAddrRange(natp
->nap
,
2026 if (kNaClBadAddress
== sysaddr
) {
2028 ("NaClCommonSysImc_Socket_Pair: bad output descriptor array "
2029 " (0x%08"PRIxPTR
")\n"),
2031 retval
= -NACL_ABI_EFAULT
;
2035 d_out
= (int *) sysaddr
;
2036 retval
= NaClCommonDescSocketPair(pair
);
2041 d_out
[0] = NaClSetAvail(natp
->nap
, pair
[0]);
2042 d_out
[1] = NaClSetAvail(natp
->nap
, pair
[1]);
2046 NaClSysCommonThreadSyscallLeave(natp
);
2050 int32_t NaClCommonSysTls_Init(struct NaClAppThread
*natp
,
2054 int32_t retval
= -NACL_ABI_EINVAL
;
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
;
2066 if (0 == NaClLdtChangeByteSelector(natp
->user
.gs
>> 3,
2067 NACL_LDT_DESCRIPTOR_DATA
,
2071 retval
= -NACL_ABI_EINVAL
;
2076 NaClSysCommonThreadSyscallLeave(natp
);
2080 int32_t NaClCommonSysThread_Create(struct NaClAppThread
*natp
,
2086 int32_t retval
= -NACL_ABI_EINVAL
;
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
;
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
;
2103 /* we do not enforce stack alignment */
2104 if (kNaClBadAddress
== NaClUserToSysAddr(natp
->nap
, (uintptr_t) esp
)) {
2105 retval
= -NACL_ABI_EFAULT
;
2108 sys_tdb
= NaClUserToSysAddrRange(natp
->nap
, (uintptr_t) tdb
, tdb_size
);
2109 if (kNaClBadAddress
== sys_tdb
) {
2110 retval
= -NACL_ABI_EFAULT
;
2113 retval
= NaClCreateAdditionalThread(natp
->nap
,
2119 NaClSysCommonThreadSyscallLeave(natp
);
2123 #if defined(HAVE_SDL)
2125 int32_t NaClCommonSysMultimedia_Init(struct NaClAppThread
*natp
,
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
;
2142 NaClStartAsyncOp(natp
,
2143 ((struct NaClClosure
*)
2144 NaClClosure2Ctor(((void (*)(void *, void *))
2145 NaClBotSysMultimedia_Init
),
2148 retval
= NaClWaitForAsyncOp(natp
);
2150 NaClSysCommonThreadSyscallLeave(natp
);
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
;
2171 NaClStartAsyncOp(natp
,
2172 ((struct NaClClosure
*)
2173 NaClClosure1Ctor(((void (*)(void *))
2174 NaClBotSysMultimedia_Shutdown
),
2176 retval
= NaClWaitForAsyncOp(natp
);
2178 NaClSysCommonThreadSyscallLeave(natp
);
2183 int32_t NaClCommonSysVideo_Init(struct NaClAppThread
*natp
,
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
;
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
;
2208 /* width and height must also be multiples of 4 */
2209 if ((0 != (width
& 0x3)) || (0 != (height
& 0x3))) {
2211 "NaClSysVideo_Init: width & height must be a multiple of 4!\n");
2212 retval
= -NACL_ABI_EINVAL
;
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
),
2227 retval
= NaClWaitForAsyncOp(natp
);
2229 NaClSysCommonThreadSyscallLeave(natp
);
2233 int32_t NaClCommonSysVideo_Shutdown(struct NaClAppThread
*natp
)
2237 NaClSysCommonThreadSyscallEnter(natp
);
2239 if (!natp
->is_privileged
&& natp
->nap
->restrict_to_main_thread
) {
2240 retval
= -NACL_ABI_EIO
;
2244 NaClStartAsyncOp(natp
,
2245 ((struct NaClClosure
*)
2246 NaClClosure1Ctor(((void (*)(void *))
2247 NaClBotSysVideo_Shutdown
),
2249 retval
= NaClWaitForAsyncOp(natp
);
2251 NaClSysCommonThreadSyscallLeave(natp
);
2256 int32_t NaClCommonSysVideo_Update(struct NaClAppThread
*natp
,
2259 int32_t retval
= -NACL_ABI_EINVAL
;
2261 NaClSysCommonThreadSyscallEnter(natp
);
2264 retval
= -NACL_ABI_EFAULT
;
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
),
2277 retval
= NaClWaitForAsyncOp(natp
);
2279 NaClSysCommonThreadSyscallLeave(natp
);
2284 int32_t NaClCommonSysVideo_Poll_Event(struct NaClAppThread
*natp
,
2285 union NaClMultimediaEvent
*event
)
2287 int32_t retval
= -NACL_ABI_EINVAL
;
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
;
2301 sysaddr
= NaClUserToSysAddrRange(natp
->nap
,
2304 if (kNaClBadAddress
== sysaddr
) {
2305 NaClLog(1, "NaClCommonSysVideo_Poll_Event: data address invalid\n");
2306 retval
= -NACL_ABI_EFAULT
;
2309 NaClStartAsyncOp(natp
,
2310 ((struct NaClClosure
*)
2311 NaClClosure2Ctor(((void (*)(void *, void *))
2312 NaClBotSysVideo_Poll_Event
),
2314 (void *) sysaddr
)));
2315 retval
= NaClWaitForAsyncOp(natp
);
2317 NaClSysCommonThreadSyscallLeave(natp
);
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
;
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
;
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
;
2351 NaClStartAsyncOp(natp
,
2352 ((struct NaClClosure
*)
2353 NaClClosure4Ctor(((void (*)(void *, void *,
2355 NaClBotSysAudio_Init
),
2358 (void *) desired_samples
,
2359 (void *) sysaddr
)));
2360 retval
= NaClWaitForAsyncOp(natp
);
2362 NaClSysCommonThreadSyscallLeave(natp
);
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
;
2383 NaClStartAsyncOp(natp
,
2384 ((struct NaClClosure
*)
2385 NaClClosure1Ctor(((void (*)(void *))
2386 NaClBotSysAudio_Shutdown
),
2388 retval
= NaClWaitForAsyncOp(natp
);
2390 NaClSysCommonThreadSyscallLeave(natp
);
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
;
2410 retval
= NaClSetAvail(natp
->nap
, (struct NaClDesc
*)desc
);
2414 NaClSysCommonThreadSyscallLeave(natp
);
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
);
2429 retval
= -NACL_ABI_EBADF
;
2433 retval
= (*desc
->vtbl
->Lock
)(desc
, natp
->effp
);
2434 NaClDescUnref(desc
);
2437 NaClSysCommonThreadSyscallLeave(natp
);
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
);
2452 retval
= -NACL_ABI_EBADF
;
2456 retval
= (*desc
->vtbl
->Unlock
)(desc
, natp
->effp
);
2457 NaClDescUnref(desc
);
2460 NaClSysCommonThreadSyscallLeave(natp
);
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
);
2475 retval
= -NACL_ABI_EBADF
;
2479 retval
= (*desc
->vtbl
->TryLock
)(desc
, natp
->effp
);
2480 NaClDescUnref(desc
);
2483 NaClSysCommonThreadSyscallLeave(natp
);
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
;
2501 retval
= NaClSetAvail(natp
->nap
, (struct NaClDesc
*)desc
);
2505 NaClSysCommonThreadSyscallLeave(natp
);
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
;
2526 mutex_desc
= NaClGetDesc(natp
->nap
, mutex_handle
);
2527 if (NULL
== mutex_desc
) {
2528 NaClDescUnref(cv_desc
);
2529 retval
= -NACL_ABI_EBADF
;
2533 retval
= (*cv_desc
->vtbl
->Wait
)(cv_desc
, natp
->effp
, mutex_desc
);
2534 NaClDescUnref(cv_desc
);
2535 NaClDescUnref(mutex_desc
);
2538 NaClSysCommonThreadSyscallLeave(natp
);
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
);
2553 retval
= -NACL_ABI_EBADF
;
2557 retval
= (*desc
->vtbl
->Signal
)(desc
, natp
->effp
);
2558 NaClDescUnref(desc
);
2560 NaClSysCommonThreadSyscallLeave(natp
);
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
);
2575 retval
= -NACL_ABI_EBADF
;
2579 retval
= (*desc
->vtbl
->Broadcast
)(desc
, natp
->effp
);
2580 NaClDescUnref(desc
);
2583 NaClSysCommonThreadSyscallLeave(natp
);
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
;
2596 struct nacl_abi_timespec trusted_ts
;
2598 NaClSysCommonThreadSyscallEnter(natp
);
2600 sys_ts
= NaClUserToSysAddrRange(natp
->nap
,
2603 if (kNaClBadAddress
== sys_ts
) {
2604 retval
= -NACL_ABI_EFAULT
;
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
;
2616 mutex_desc
= NaClGetDesc(natp
->nap
, mutex_handle
);
2617 if (NULL
== mutex_desc
) {
2618 NaClDescUnref(cv_desc
);
2619 retval
= -NACL_ABI_EBADF
;
2623 retval
= (*cv_desc
->vtbl
->TimedWaitAbs
)(cv_desc
, natp
->effp
, mutex_desc
,
2625 NaClDescUnref(cv_desc
);
2626 NaClDescUnref(mutex_desc
);
2628 NaClSysCommonThreadSyscallLeave(natp
);
2632 int32_t NaClCommonSysSem_Create(struct NaClAppThread
*natp
,
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
;
2647 retval
= NaClSetAvail(natp
->nap
, (struct NaClDesc
*) desc
);
2651 NaClSysCommonThreadSyscallLeave(natp
);
2656 int32_t NaClCommonSysSem_Wait(struct NaClAppThread
*natp
,
2659 int32_t retval
= -NACL_ABI_EINVAL
;
2660 struct NaClDesc
*desc
;
2662 NaClSysCommonThreadSyscallEnter(natp
);
2664 desc
= NaClGetDesc(natp
->nap
, sem_handle
);
2667 retval
= -NACL_ABI_EBADF
;
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
);
2680 NaClSysCommonThreadSyscallLeave(natp
);
2684 int32_t NaClCommonSysSem_Post(struct NaClAppThread
*natp
,
2687 int32_t retval
= -NACL_ABI_EINVAL
;
2688 struct NaClDesc
*desc
;
2690 NaClSysCommonThreadSyscallEnter(natp
);
2692 desc
= NaClGetDesc(natp
->nap
, sem_handle
);
2695 retval
= -NACL_ABI_EBADF
;
2699 retval
= (*desc
->vtbl
->Post
)(desc
, natp
->effp
);
2700 NaClDescUnref(desc
);
2702 NaClSysCommonThreadSyscallLeave(natp
);
2706 int32_t NaClCommonSysSem_Get_Value(struct NaClAppThread
*natp
,
2709 int32_t retval
= -NACL_ABI_EINVAL
;
2710 struct NaClDesc
*desc
;
2712 NaClSysCommonThreadSyscallEnter(natp
);
2714 desc
= NaClGetDesc(natp
->nap
, sem_handle
);
2717 retval
= -NACL_ABI_EBADF
;
2721 retval
= (*desc
->vtbl
->GetValue
)(desc
, natp
->effp
);
2722 NaClDescUnref(desc
);
2724 NaClSysCommonThreadSyscallLeave(natp
);