1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl service run-time, non-platform specific system call helper routines.
9 : */
10 : #include <sys/types.h>
11 : #include <sys/stat.h>
12 :
13 : #include <stdio.h>
14 :
15 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
16 :
17 : #include "native_client/src/include/nacl_assert.h"
18 : #include "native_client/src/include/nacl_macros.h"
19 : #include "native_client/src/include/nacl_platform.h"
20 : #include "native_client/src/include/portability_string.h"
21 :
22 : #include "native_client/src/shared/platform/nacl_clock.h"
23 : #include "native_client/src/shared/platform/nacl_exit.h"
24 : #include "native_client/src/shared/platform/nacl_host_desc.h"
25 : #include "native_client/src/shared/platform/nacl_host_dir.h"
26 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
27 :
28 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
29 : #include "native_client/src/trusted/desc/nacl_desc_cond.h"
30 : #include "native_client/src/trusted/desc/nacl_desc_dir.h"
31 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
32 : #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
33 : #include "native_client/src/trusted/desc/nacl_desc_invalid.h"
34 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
35 : #include "native_client/src/trusted/desc/nacl_desc_mutex.h"
36 : #include "native_client/src/trusted/desc/nacl_desc_semaphore.h"
37 : #include "native_client/src/trusted/desc/nrd_xfer.h"
38 :
39 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
40 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
41 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
42 : #include "native_client/src/trusted/service_runtime/nacl_thread_nice.h"
43 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
44 : #include "native_client/src/trusted/service_runtime/nacl_tls.h"
45 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
46 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
47 :
48 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
49 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
50 : #include "native_client/src/trusted/service_runtime/include/sys/mman.h"
51 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
52 :
53 :
54 : struct NaClDescQuotaInterface;
55 :
56 : /*
57 : * OSX defines SIZE_T_MAX in i386/limits.h; Linux has SIZE_MAX;
58 : * Windows has none.
59 : *
60 : * TODO(bsy): remove when we put SIZE_T_MAX in a common header file.
61 : */
62 : #if !defined(SIZE_T_MAX)
63 : # define SIZE_T_MAX (~(size_t) 0)
64 : #endif
65 :
66 : static const size_t kMaxUsableFileSize = (SIZE_T_MAX >> 1);
67 :
68 9 : static INLINE size_t size_min(size_t a, size_t b) {
69 9 : return (a < b) ? a : b;
70 : }
71 :
72 : static int const kKnownInvalidDescNumber = -1;
73 :
74 251 : void NaClSysCommonThreadSyscallEnter(struct NaClAppThread *natp) {
75 : UNREFERENCED_PARAMETER(natp);
76 251 : }
77 :
78 248 : void NaClSysCommonThreadSyscallLeave(struct NaClAppThread *natp) {
79 248 : NaClXMutexLock(&natp->mu);
80 248 : switch (natp->state) {
81 : case NACL_APP_THREAD_ALIVE:
82 248 : break;
83 : case NACL_APP_THREAD_SUICIDE_PENDING:
84 0 : NaClXMutexUnlock(&natp->mu);
85 0 : NaClAppThreadTeardown(natp);
86 : /* NOTREACHED */
87 0 : break;
88 : case NACL_APP_THREAD_DEAD:
89 0 : NaClLog(LOG_FATAL, "Dead thread at NaClSysCommonThreadSyscallLeave\n");
90 : /* NOTREACHED */
91 : break;
92 : }
93 248 : NaClXMutexUnlock(&natp->mu);
94 248 : }
95 :
96 : int32_t NaClSetBreak(struct NaClAppThread *natp,
97 10 : uintptr_t new_break) {
98 : struct NaClApp *nap;
99 : uintptr_t break_addr;
100 10 : int32_t rv = -NACL_ABI_EINVAL;
101 : struct NaClVmmapIter iter;
102 : struct NaClVmmapEntry *ent;
103 : struct NaClVmmapEntry *next_ent;
104 : uintptr_t sys_break;
105 : uintptr_t sys_new_break;
106 : uintptr_t usr_last_data_page;
107 : uintptr_t usr_new_last_data_page;
108 : uintptr_t last_internal_data_addr;
109 : uintptr_t last_internal_page;
110 : uintptr_t start_new_region;
111 : uintptr_t region_size;
112 :
113 10 : nap = natp->nap;
114 10 : break_addr = nap->break_addr;
115 :
116 10 : NaClLog(3, "Entered NaClSetBreak(new_break 0x%08"NACL_PRIxPTR")\n",
117 : new_break);
118 :
119 10 : NaClSysCommonThreadSyscallEnter(natp);
120 :
121 10 : sys_new_break = NaClUserToSysAddr(natp->nap, new_break);
122 10 : NaClLog(3, "sys_new_break 0x%08"NACL_PRIxPTR"\n", sys_new_break);
123 :
124 10 : if (kNaClBadAddress == sys_new_break) {
125 3 : goto cleanup_no_lock;
126 : }
127 7 : if (NACL_SYNC_OK != NaClMutexLock(&nap->mu)) {
128 0 : NaClLog(LOG_ERROR, "Could not get app lock for 0x%08"NACL_PRIxPTR"\n",
129 : (uintptr_t) nap);
130 0 : goto cleanup_no_lock;
131 : }
132 7 : if (new_break < nap->data_end) {
133 0 : NaClLog(4, "new_break before data_end (0x%"NACL_PRIxPTR")\n",
134 : nap->data_end);
135 0 : goto cleanup;
136 : }
137 7 : if (new_break <= nap->break_addr) {
138 : /* freeing memory */
139 0 : NaClLog(4, "new_break before break (0x%"NACL_PRIxPTR"); freeing\n",
140 : nap->break_addr);
141 0 : nap->break_addr = new_break;
142 0 : break_addr = new_break;
143 : } else {
144 : /*
145 : * See if page containing new_break is in mem_map; if so, we are
146 : * essentially done -- just update break_addr. Otherwise, we
147 : * extend the VM map entry from the page containing the current
148 : * break to the page containing new_break.
149 : */
150 :
151 7 : sys_break = NaClUserToSys(nap, nap->break_addr);
152 :
153 7 : usr_last_data_page = (nap->break_addr - 1) >> NACL_PAGESHIFT;
154 :
155 7 : usr_new_last_data_page = (new_break - 1) >> NACL_PAGESHIFT;
156 :
157 7 : last_internal_data_addr = NaClRoundAllocPage(new_break) - 1;
158 7 : last_internal_page = last_internal_data_addr >> NACL_PAGESHIFT;
159 :
160 7 : NaClLog(4, ("current break sys addr 0x%08"NACL_PRIxPTR", "
161 : "usr last data page 0x%"NACL_PRIxPTR"\n"),
162 : sys_break, usr_last_data_page);
163 7 : NaClLog(4, "new break usr last data page 0x%"NACL_PRIxPTR"\n",
164 : usr_new_last_data_page);
165 7 : NaClLog(4, "last internal data addr 0x%08"NACL_PRIxPTR"\n",
166 : last_internal_data_addr);
167 :
168 7 : if (NULL == NaClVmmapFindPageIter(&nap->mem_map,
169 : usr_last_data_page,
170 : &iter)
171 : || NaClVmmapIterAtEnd(&iter)) {
172 0 : NaClLog(LOG_FATAL, ("current break (0x%08"NACL_PRIxPTR", "
173 : "sys 0x%08"NACL_PRIxPTR") "
174 : "not in address map\n"),
175 : nap->break_addr, sys_break);
176 : }
177 7 : ent = NaClVmmapIterStar(&iter);
178 7 : NaClLog(4, ("segment containing current break"
179 : ": page_num 0x%08"NACL_PRIxPTR", npages 0x%"NACL_PRIxS"\n"),
180 : ent->page_num, ent->npages);
181 7 : if (usr_new_last_data_page < ent->page_num + ent->npages) {
182 6 : NaClLog(4, "new break within break segment, just bumping addr\n");
183 6 : nap->break_addr = new_break;
184 6 : break_addr = new_break;
185 : } else {
186 1 : NaClVmmapIterIncr(&iter);
187 1 : if (!NaClVmmapIterAtEnd(&iter)
188 : && ((next_ent = NaClVmmapIterStar(&iter))->page_num
189 : <= last_internal_page)) {
190 : /* ran into next segment! */
191 0 : NaClLog(4,
192 : ("new break request of usr address "
193 : "0x%08"NACL_PRIxPTR" / usr page 0x%"NACL_PRIxPTR
194 : " runs into next region, page_num 0x%"NACL_PRIxPTR", "
195 : "npages 0x%"NACL_PRIxS"\n"),
196 : new_break, usr_new_last_data_page,
197 : next_ent->page_num, next_ent->npages);
198 0 : goto cleanup;
199 : }
200 1 : NaClLog(4,
201 : "extending segment: page_num 0x%08"NACL_PRIxPTR", "
202 : "npages 0x%"NACL_PRIxS"\n",
203 : ent->page_num, ent->npages);
204 : /* go ahead and extend ent to cover, and make pages accessible */
205 1 : start_new_region = (ent->page_num + ent->npages) << NACL_PAGESHIFT;
206 1 : ent->npages = (last_internal_page - ent->page_num + 1);
207 1 : region_size = (((last_internal_page + 1) << NACL_PAGESHIFT)
208 : - start_new_region);
209 1 : if (0 != NaCl_mprotect((void *) NaClUserToSys(nap, start_new_region),
210 : region_size,
211 : PROT_READ | PROT_WRITE)) {
212 0 : NaClLog(LOG_FATAL,
213 : ("Could not mprotect(0x%08"NACL_PRIxPTR", "
214 : "0x%08"NACL_PRIxPTR", "
215 : "PROT_READ|PROT_WRITE)\n"),
216 : start_new_region,
217 : region_size);
218 : }
219 1 : NaClLog(4, "segment now: page_num 0x%08"NACL_PRIxPTR", "
220 : "npages 0x%"NACL_PRIxS"\n",
221 : ent->page_num, ent->npages);
222 1 : nap->break_addr = new_break;
223 1 : break_addr = new_break;
224 : }
225 : /*
226 : * Zero out memory between old break and new break.
227 : */
228 7 : ASSERT(sys_new_break > sys_break);
229 7 : memset((void *) sys_break, 0, sys_new_break - sys_break);
230 : }
231 :
232 :
233 :
234 7 : cleanup:
235 7 : NaClXMutexUnlock(&nap->mu);
236 10 : cleanup_no_lock:
237 10 : NaClSysCommonThreadSyscallLeave(natp);
238 :
239 : /*
240 : * This cast is safe because the incoming value (new_break) cannot
241 : * exceed the user address space--even though its type (uintptr_t)
242 : * theoretically allows larger values.
243 : */
244 10 : rv = (int32_t) break_addr;
245 :
246 10 : NaClLog(3, "NaClSetBreak: returning 0x%08"NACL_PRIx32"\n", rv);
247 10 : return rv;
248 : }
249 :
250 : int NaClAclBypassChecks = 0;
251 :
252 3 : void NaClInsecurelyBypassAllAclChecks(void) {
253 3 : NaClLog(LOG_WARNING, "BYPASSING ALL ACL CHECKS\n");
254 3 : NaClAclBypassChecks = 1;
255 3 : }
256 :
257 1 : int NaClHighResolutionTimerEnabled() {
258 1 : return NaClAclBypassChecks;
259 : }
260 :
261 : /*
262 : * NaClOpenAclCheck: Is the NaCl app authorized to open this file? The
263 : * return value is syscall return convention, so 0 is success and
264 : * small negative numbers are negated errno values.
265 : */
266 : int32_t NaClOpenAclCheck(struct NaClApp *nap,
267 : char const *path,
268 : int flags,
269 16 : int mode) {
270 : /*
271 : * TODO(bsy): provide some minimal authorization check, based on
272 : * whether a debug flag is set; eventually provide a data-driven
273 : * authorization configuration mechanism, perhaps persisted via
274 : * gears. need GUI for user configuration, as well as designing an
275 : * appropriate language (with sufficient expressiveness), however.
276 : */
277 16 : NaClLog(1, "NaClOpenAclCheck(0x%08"NACL_PRIxPTR", %s, 0%o, 0%o)\n",
278 : (uintptr_t) nap, path, flags, mode);
279 16 : if (3 < NaClLogGetVerbosity()) {
280 0 : NaClLog(0, "O_ACCMODE: 0%o\n", flags & NACL_ABI_O_ACCMODE);
281 0 : NaClLog(0, "O_RDONLY = %d\n", NACL_ABI_O_RDONLY);
282 0 : NaClLog(0, "O_WRONLY = %d\n", NACL_ABI_O_WRONLY);
283 0 : NaClLog(0, "O_RDWR = %d\n", NACL_ABI_O_RDWR);
284 : #define FLOG(VAR, BIT) do {\
285 : NaClLog(1, "%s: %s\n", #BIT, (VAR & BIT) ? "yes" : "no");\
286 : } while (0)
287 0 : FLOG(flags, NACL_ABI_O_CREAT);
288 0 : FLOG(flags, NACL_ABI_O_TRUNC);
289 0 : FLOG(flags, NACL_ABI_O_APPEND);
290 : #undef FLOG
291 : }
292 16 : if (NaClAclBypassChecks) {
293 16 : return 0;
294 : }
295 0 : return -NACL_ABI_EACCES;
296 : }
297 :
298 : /*
299 : * NaClStatAclCheck: Is the NaCl app authorized to stat this pathname? The
300 : * return value is syscall return convention, so 0 is success and
301 : * small negative numbers are negated errno values.
302 : *
303 : * This is primarily for debug use. File access should be through
304 : * SRPC-based file servers.
305 : */
306 : int32_t NaClStatAclCheck(struct NaClApp *nap,
307 0 : char const *path) {
308 0 : NaClLog(2,
309 : "NaClStatAclCheck(0x%08"NACL_PRIxPTR", %s)\n", (uintptr_t) nap, path);
310 0 : if (NaClAclBypassChecks) {
311 0 : return 0;
312 : }
313 0 : return -NACL_ABI_EACCES;
314 : }
315 :
316 : int32_t NaClIoctlAclCheck(struct NaClApp *nap,
317 : struct NaClDesc *ndp,
318 : int request,
319 0 : void *arg) {
320 0 : NaClLog(2,
321 : ("NaClIoctlAclCheck(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR","
322 : " %d, 0x%08"NACL_PRIxPTR"\n"),
323 : (uintptr_t) nap, (uintptr_t) ndp, request, (uintptr_t) arg);
324 0 : if (NaClAclBypassChecks) {
325 0 : return 0;
326 : }
327 0 : return -NACL_ABI_EINVAL;
328 : }
329 :
330 : int32_t NaClCommonSysExit(struct NaClAppThread *natp,
331 3 : int status) {
332 : struct NaClApp *nap;
333 :
334 3 : NaClLog(1, "Exit syscall handler: %d\n", status);
335 3 : NaClSysCommonThreadSyscallEnter(natp);
336 :
337 3 : nap = natp->nap;
338 :
339 3 : (void) NaClReportExitStatus(nap, status);
340 :
341 3 : NaClAppThreadTeardown(natp);
342 : /* NOTREACHED */
343 0 : return -NACL_ABI_EINVAL;
344 : }
345 :
346 : int32_t NaClCommonSysThreadExit(struct NaClAppThread *natp,
347 0 : int32_t *stack_flag) {
348 : uintptr_t sys_stack_flag;
349 :
350 0 : NaClLog(4, "NaclCommonSysThreadExit(0x%08"NACL_PRIxPTR", "
351 : "0x%08"NACL_PRIxPTR"\n",
352 : (uintptr_t) natp,
353 : (uintptr_t) stack_flag);
354 0 : NaClSysCommonThreadSyscallEnter(natp);
355 : /*
356 : * NB: NaClThreads are never joinable, but the abstraction for NaClApps
357 : * are.
358 : */
359 :
360 0 : if (NULL != stack_flag) {
361 0 : NaClLog(4,
362 : "NaClCommonSysThreadExit: stack_flag is %"NACL_PRIxPTR"\n",
363 : (uintptr_t) stack_flag);
364 0 : sys_stack_flag = NaClUserToSysAddrRange(natp->nap,
365 : (uintptr_t) stack_flag,
366 : sizeof(int32_t));
367 0 : NaClLog(4,
368 : "NaClCommonSysThreadExit: sys_stack_flag is %"NACL_PRIxPTR"\n",
369 : sys_stack_flag);
370 0 : if (kNaClBadAddress != sys_stack_flag) {
371 : /*
372 : * We don't return failure if the address is illegal because
373 : * this function is not supposed to return.
374 : */
375 0 : NaClLog(4,
376 : "NaClCommonSysThreadExit: clearing stack flag\n");
377 0 : *(volatile int32_t *) sys_stack_flag = 0;
378 : }
379 : }
380 :
381 0 : NaClAppThreadTeardown(natp);
382 : /* NOTREACHED */
383 0 : return -NACL_ABI_EINVAL;
384 : }
385 :
386 : int32_t NaClCommonSysNameService(struct NaClAppThread *natp,
387 0 : int32_t *desc_addr) {
388 0 : int32_t retval = -NACL_ABI_EINVAL;
389 : uintptr_t sysaddr;
390 : int32_t desc;
391 :
392 0 : NaClLog(3,
393 : ("NaClCommonSysNameService(0x%08"NACL_PRIxPTR","
394 : " 0x%08"NACL_PRIxPTR")\n"),
395 : (uintptr_t) natp,
396 : (uintptr_t) desc_addr);
397 0 : NaClSysCommonThreadSyscallEnter(natp);
398 :
399 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
400 : (uintptr_t) desc_addr,
401 : sizeof(uint32_t));
402 0 : if (kNaClBadAddress == sysaddr) {
403 0 : NaClLog(LOG_ERROR,
404 : "Invalid address argument to NaClCommonSysNameService\n");
405 0 : retval = -NACL_ABI_EFAULT;
406 0 : goto done;
407 : }
408 :
409 0 : desc = *(int32_t volatile *) sysaddr;
410 0 : if (-1 == desc) {
411 : /* read */
412 0 : desc = NaClSetAvail(natp->nap,
413 : NaClDescRef(natp->nap->name_service_conn_cap));
414 0 : *(int32_t volatile *) sysaddr = desc;
415 0 : retval = 0;
416 : } else {
417 0 : struct NaClDesc *desc_obj_ptr = NaClGetDesc(natp->nap, desc);
418 :
419 0 : if (NULL == desc_obj_ptr) {
420 0 : retval = -NACL_ABI_EBADF;
421 0 : goto done;
422 : }
423 0 : if (NACL_DESC_CONN_CAP != NACL_VTBL(NaClDesc, desc_obj_ptr)->typeTag &&
424 : NACL_DESC_CONN_CAP_FD != NACL_VTBL(NaClDesc, desc_obj_ptr)->typeTag) {
425 0 : retval = -NACL_ABI_EINVAL;
426 0 : goto done;
427 : }
428 : /* write */
429 0 : NaClXMutexLock(&natp->nap->mu);
430 0 : NaClDescUnref(natp->nap->name_service_conn_cap);
431 0 : natp->nap->name_service_conn_cap = desc_obj_ptr;
432 0 : NaClXMutexUnlock(&natp->nap->mu);
433 0 : retval = 0;
434 : }
435 :
436 0 : done:
437 0 : NaClSysCommonThreadSyscallLeave(natp);
438 0 : return retval;
439 : }
440 :
441 : int32_t NaClCommonSysDup(struct NaClAppThread *natp,
442 0 : int oldfd) {
443 : int retval;
444 : struct NaClDesc *old_nd;
445 :
446 0 : NaClLog(3, "NaClCommonSysDup(0x%08"NACL_PRIxPTR", %d)\n",
447 : (uintptr_t) natp, oldfd);
448 0 : NaClSysCommonThreadSyscallEnter(natp);
449 0 : old_nd = NaClGetDesc(natp->nap, oldfd);
450 0 : if (NULL == old_nd) {
451 0 : retval = -NACL_ABI_EBADF;
452 0 : goto done;
453 : }
454 0 : retval = NaClSetAvail(natp->nap, old_nd);
455 0 : done:
456 0 : NaClSysCommonThreadSyscallLeave(natp);
457 0 : return retval;
458 : }
459 :
460 : int32_t NaClCommonSysDup2(struct NaClAppThread *natp,
461 : int oldfd,
462 0 : int newfd) {
463 : int retval;
464 : struct NaClDesc *old_nd;
465 :
466 0 : NaClLog(3, "NaClCommonSysDup(0x%08"NACL_PRIxPTR", %d, %d)\n",
467 : (uintptr_t) natp, oldfd, newfd);
468 0 : NaClSysCommonThreadSyscallEnter(natp);
469 0 : if (newfd < 0) {
470 0 : retval = -NACL_ABI_EINVAL;
471 0 : goto done;
472 : }
473 : /*
474 : * TODO(bsy): is this a reasonable largest sane value? The
475 : * descriptor array shouldn't get too large.
476 : */
477 0 : if (newfd >= NACL_MAX_FD) {
478 0 : retval = -NACL_ABI_EINVAL;
479 0 : goto done;
480 : }
481 0 : old_nd = NaClGetDesc(natp->nap, oldfd);
482 0 : if (NULL == old_nd) {
483 0 : retval = -NACL_ABI_EBADF;
484 0 : goto done;
485 : }
486 0 : NaClSetDesc(natp->nap, newfd, old_nd);
487 0 : retval = newfd;
488 0 : done:
489 0 : NaClSysCommonThreadSyscallLeave(natp);
490 0 : return retval;
491 : }
492 :
493 : int32_t NaClCommonSysOpen(struct NaClAppThread *natp,
494 : char *pathname,
495 : int flags,
496 16 : int mode) {
497 16 : uint32_t retval = -NACL_ABI_EINVAL;
498 : uintptr_t sysaddr;
499 : char path[NACL_CONFIG_PATH_MAX];
500 : size_t len;
501 : nacl_host_stat_t stbuf;
502 : int allowed_flags;
503 :
504 16 : NaClLog(3, "NaClCommonSysOpen(0x%08"NACL_PRIxPTR", "
505 : "0x%08"NACL_PRIxPTR", 0x%x, 0x%x)\n",
506 : (uintptr_t) natp, (uintptr_t) pathname, flags, mode);
507 :
508 16 : NaClSysCommonThreadSyscallEnter(natp);
509 :
510 16 : sysaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) pathname);
511 16 : if (kNaClBadAddress == sysaddr) {
512 0 : NaClLog(LOG_ERROR, "Invalid address for pathname\n");
513 0 : retval = -NACL_ABI_EFAULT;
514 0 : goto cleanup;
515 : }
516 16 : allowed_flags = (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
517 : | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
518 16 : if (0 != (flags & ~allowed_flags)) {
519 0 : NaClLog(LOG_WARNING, "Invalid open flags 0%o, ignoring extraneous bits\n",
520 : flags);
521 0 : flags &= allowed_flags;
522 : }
523 16 : if (0 != (mode & ~0600)) {
524 0 : NaClLog(1, "IGNORING Invalid access mode bits 0%o\n", mode);
525 0 : mode &= 0600;
526 : }
527 16 : NaClLog(4, " attempting to copy path via sysaddr 0x%08"NACL_PRIxPTR
528 : "\n", sysaddr);
529 16 : NaClLog(4, " first 4 bytes: %.4s\n", (char *) sysaddr);
530 : /*
531 : * strncpy may (try to) get bytes that is outside the app's address
532 : * space and generate a fault.
533 : */
534 16 : strncpy(path, (char *) sysaddr, sizeof path);
535 : /*
536 : * survived the copy, but did there happen to be data beyond the end?
537 : */
538 16 : path[sizeof path - 1] = '\0'; /* always null terminate */
539 16 : NaClLog(1, "NaClSysOpen: Path: %s\n", path);
540 16 : len = strlen(path);
541 : /*
542 : * make sure sysaddr is a string, and the whole string is in app
543 : * address space...
544 : *
545 : * address space is convex, so it is impossible for beginning and
546 : * end to be both in the address space and yet have an intermediate
547 : * byte not be in the address space.
548 : */
549 16 : if (kNaClBadAddress == NaClUserToSysAddr(natp->nap,
550 : len + (uintptr_t) pathname)) {
551 0 : NaClLog(LOG_ERROR, "String ends outside addrspace\n");
552 0 : retval = -NACL_ABI_EFAULT;
553 0 : goto cleanup;
554 : }
555 :
556 16 : retval = NaClOpenAclCheck(natp->nap, path, flags, mode);
557 16 : if (0 != retval) {
558 0 : NaClLog(3, "Open ACL check rejected \"%s\".\n", path);
559 0 : goto cleanup;
560 : }
561 :
562 : /*
563 : * Perform a stat to determine whether the file is a directory.
564 : *
565 : * NB: it is okay for the stat to fail, since the request may be to
566 : * create a new file.
567 : *
568 : * There is a race conditions here: between the stat and the
569 : * open-as-a-file and open-as-a-dir, the type of the object that the
570 : * path refers to can change.
571 : */
572 16 : retval = NaClHostDescStat(path, &stbuf);
573 :
574 : /* Windows does not have S_ISDIR(m) macro */
575 18 : if (0 == retval && S_IFDIR == (S_IFDIR & stbuf.st_mode)) {
576 : struct NaClHostDir *hd;
577 :
578 2 : hd = malloc(sizeof *hd);
579 2 : if (NULL == hd) {
580 0 : retval = -NACL_ABI_ENOMEM;
581 0 : goto cleanup;
582 : }
583 2 : retval = NaClHostDirOpen(hd, path);
584 2 : NaClLog(1, "NaClHostDirOpen(0x%08"NACL_PRIxPTR", %s) returned %d\n",
585 : (uintptr_t) hd, path, retval);
586 2 : if (0 == retval) {
587 2 : retval = NaClSetAvail(natp->nap,
588 : ((struct NaClDesc *) NaClDescDirDescMake(hd)));
589 2 : NaClLog(1, "Entered directory into open file table at %d\n",
590 : retval);
591 : }
592 : } else {
593 : struct NaClHostDesc *hd;
594 :
595 14 : hd = malloc(sizeof *hd);
596 14 : if (NULL == hd) {
597 0 : retval = -NACL_ABI_ENOMEM;
598 0 : goto cleanup;
599 : }
600 14 : retval = NaClHostDescOpen(hd, path, flags, mode);
601 14 : NaClLog(1,
602 : "NaClHostDescOpen(0x%08"NACL_PRIxPTR", %s, 0%o, 0%o) returned %d\n",
603 : (uintptr_t) hd, path, flags, mode, retval);
604 14 : if (0 == retval) {
605 10 : retval = NaClSetAvail(natp->nap,
606 : ((struct NaClDesc *) NaClDescIoDescMake(hd)));
607 10 : NaClLog(1, "Entered into open file table at %d\n", retval);
608 : }
609 : }
610 16 : cleanup:
611 16 : NaClSysCommonThreadSyscallLeave(natp);
612 :
613 16 : return retval;
614 : }
615 :
616 : int32_t NaClCommonSysClose(struct NaClAppThread *natp,
617 26 : int d) {
618 26 : int retval = -NACL_ABI_EBADF;
619 : struct NaClDesc *ndp;
620 :
621 26 : NaClLog(3, "Entered NaClCommonSysClose(0x%08"NACL_PRIxPTR", %d)\n",
622 : (uintptr_t) natp, d);
623 :
624 26 : NaClSysCommonThreadSyscallEnter(natp);
625 :
626 26 : NaClXMutexLock(&natp->nap->desc_mu);
627 26 : ndp = NaClGetDescMu(natp->nap, d);
628 26 : if (NULL != ndp) {
629 21 : NaClSetDescMu(natp->nap, d, NULL); /* Unref the desc_tbl */
630 : }
631 26 : NaClXMutexUnlock(&natp->nap->desc_mu);
632 26 : NaClLog(5, "Invoking Close virtual function of object 0x%08"NACL_PRIxPTR"\n",
633 : (uintptr_t) ndp);
634 26 : if (NULL != ndp) {
635 21 : NaClDescUnref(ndp);
636 21 : retval = 0;
637 : }
638 :
639 26 : NaClSysCommonThreadSyscallLeave(natp);
640 26 : return retval;
641 : }
642 :
643 : int32_t NaClCommonSysGetdents(struct NaClAppThread *natp,
644 : int d,
645 : void *dirp,
646 0 : size_t count) {
647 0 : int32_t retval = -NACL_ABI_EINVAL;
648 : ssize_t getdents_ret;
649 : uintptr_t sysaddr;
650 : struct NaClDesc *ndp;
651 :
652 0 : NaClLog(3,
653 : ("Entered NaClCommonSysGetdents(0x%08"NACL_PRIxPTR", "
654 : "%d, 0x%08"NACL_PRIxPTR", "
655 : "%"NACL_PRIdS"[0x%"NACL_PRIxS"])\n"),
656 : (uintptr_t) natp, d, (uintptr_t) dirp, count, count);
657 :
658 0 : NaClSysCommonThreadSyscallEnter(natp);
659 :
660 0 : ndp = NaClGetDesc(natp->nap, d);
661 0 : if (NULL == ndp) {
662 0 : retval = -NACL_ABI_EBADF;
663 0 : goto cleanup;
664 : }
665 :
666 0 : sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) dirp, count);
667 0 : if (kNaClBadAddress == sysaddr) {
668 0 : NaClLog(4, " illegal address for directory data\n");
669 0 : retval = -NACL_ABI_EFAULT;
670 0 : goto cleanup_unref;
671 : }
672 :
673 : /*
674 : * Clamp count to INT32_MAX to avoid the possibility of Getdents returning
675 : * a value that is outside the range of an int32.
676 : */
677 0 : if (count > INT32_MAX) {
678 0 : count = INT32_MAX;
679 : }
680 0 : getdents_ret = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
681 : Getdents)(ndp,
682 : (void *) sysaddr,
683 : count);
684 : if ((getdents_ret < INT32_MIN && !NaClSSizeIsNegErrno(&getdents_ret))
685 : || INT32_MAX < getdents_ret) {
686 : /* This should never happen, because we already clamped the input count */
687 : NaClLog(LOG_FATAL, "Overflow in Getdents: return value is %"NACL_PRIxS,
688 : getdents_ret);
689 : } else {
690 0 : retval = (int32_t) getdents_ret;
691 : }
692 0 : if (retval > 0) {
693 0 : NaClLog(4, "getdents returned %d bytes\n", retval);
694 0 : NaClLog(8, "getdents result: %.*s\n", retval, (char *) sysaddr);
695 : } else {
696 0 : NaClLog(4, "getdents returned %d\n", retval);
697 : }
698 :
699 0 : cleanup_unref:
700 0 : NaClDescUnref(ndp);
701 :
702 0 : cleanup:
703 0 : NaClSysCommonThreadSyscallLeave(natp);
704 :
705 0 : return retval;
706 : }
707 :
708 : int32_t NaClCommonSysRead(struct NaClAppThread *natp,
709 : int d,
710 : void *buf,
711 16 : size_t count) {
712 16 : int32_t retval = -NACL_ABI_EINVAL;
713 16 : ssize_t read_result = -NACL_ABI_EINVAL;
714 : uintptr_t sysaddr;
715 : struct NaClDesc *ndp;
716 :
717 :
718 16 : NaClLog(3,
719 : ("Entered NaClCommonSysRead(0x%08"NACL_PRIxPTR", "
720 : "%d, 0x%08"NACL_PRIxPTR", "
721 : "%"NACL_PRIdS"[0x%"NACL_PRIxS"])\n"),
722 : (uintptr_t) natp, d, (uintptr_t) buf, count, count);
723 :
724 16 : NaClSysCommonThreadSyscallEnter(natp);
725 :
726 16 : ndp = NaClGetDesc(natp->nap, d);
727 16 : if (NULL == ndp) {
728 2 : retval = -NACL_ABI_EBADF;
729 2 : goto cleanup;
730 : }
731 :
732 14 : sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, count);
733 14 : if (kNaClBadAddress == sysaddr) {
734 1 : NaClDescUnref(ndp);
735 1 : retval = -NACL_ABI_EFAULT;
736 1 : goto cleanup;
737 : }
738 :
739 : /*
740 : * The maximum length for read and write is INT32_MAX--anything larger and
741 : * the return value would overflow. Passing larger values isn't an error--
742 : * we'll just clamp the request size if it's too large.
743 : */
744 13 : if (count > INT32_MAX) {
745 0 : count = INT32_MAX;
746 : }
747 :
748 13 : read_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
749 : Read)(ndp, (void *) sysaddr, count);
750 13 : if (read_result > 0) {
751 9 : NaClLog(4, "read returned %"NACL_PRIdS" bytes\n", read_result);
752 9 : NaClLog(8, "read result: %.*s\n",
753 : (int) read_result,
754 : (char *) sysaddr);
755 : } else {
756 4 : NaClLog(4, "read returned %"NACL_PRIdS"\n", read_result);
757 : }
758 13 : NaClDescUnref(ndp);
759 :
760 : /* This cast is safe because we clamped count above.*/
761 13 : retval = (int32_t) read_result;
762 16 : cleanup:
763 16 : NaClSysCommonThreadSyscallLeave(natp);
764 :
765 16 : return retval;
766 : }
767 :
768 : int32_t NaClCommonSysWrite(struct NaClAppThread *natp,
769 : int d,
770 : void *buf,
771 151 : size_t count) {
772 151 : int32_t retval = -NACL_ABI_EINVAL;
773 151 : ssize_t write_result = -NACL_ABI_EINVAL;
774 : uintptr_t sysaddr;
775 : struct NaClDesc *ndp;
776 :
777 151 : NaClLog(3,
778 : "Entered NaClCommonSysWrite(0x%08"NACL_PRIxPTR", "
779 : "%d, 0x%08"NACL_PRIxPTR", "
780 : "%"NACL_PRIdS"[0x%"NACL_PRIxS"])\n",
781 : (uintptr_t) natp, d, (uintptr_t) buf, count, count);
782 :
783 151 : NaClSysCommonThreadSyscallEnter(natp);
784 :
785 151 : ndp = NaClGetDesc(natp->nap, d);
786 151 : NaClLog(4, " ndp = %"NACL_PRIxPTR"\n", (uintptr_t) ndp);
787 151 : if (NULL == ndp) {
788 1 : retval = -NACL_ABI_EBADF;
789 1 : goto cleanup;
790 : }
791 :
792 150 : sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, count);
793 150 : if (kNaClBadAddress == sysaddr) {
794 1 : NaClDescUnref(ndp);
795 1 : retval = -NACL_ABI_EFAULT;
796 1 : goto cleanup;
797 : }
798 :
799 149 : NaClLog(4, "In NaClSysWrite(%d, %.*s, %"NACL_PRIdS")\n",
800 : d, (int) count, (char *) sysaddr, count);
801 :
802 : /*
803 : * The maximum length for read and write is INT32_MAX--anything larger and
804 : * the return value would overflow. Passing larger values isn't an error--
805 : * we'll just clamp the request size if it's too large.
806 : */
807 149 : if (count > INT32_MAX) {
808 0 : count = INT32_MAX;
809 : }
810 :
811 149 : write_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
812 : Write)(ndp, (void *) sysaddr, count);
813 :
814 149 : NaClDescUnref(ndp);
815 :
816 : /* This cast is safe because we clamped count above.*/
817 149 : retval = (int32_t) write_result;
818 :
819 151 : cleanup:
820 151 : NaClSysCommonThreadSyscallLeave(natp);
821 :
822 151 : return retval;
823 : }
824 :
825 : /*
826 : * This is not lseek64, so the return value on success can be
827 : * E_OVERFLOW if it does not fit in a 32-bit off_t.
828 : */
829 : int32_t NaClCommonSysLseek(struct NaClAppThread *natp,
830 : int d,
831 : nacl_abi_off_t *offp,
832 9 : int whence) {
833 : uintptr_t sysaddr;
834 : nacl_abi_off_t offset;
835 : nacl_off64_t retval64;
836 9 : int32_t retval = -NACL_ABI_EINVAL;
837 : struct NaClDesc *ndp;
838 :
839 9 : NaClLog(3,
840 : ("Entered NaClCommonSysLseek(0x%08"NACL_PRIxPTR", %d,"
841 : " 0x%08"NACL_PRIxPTR", %d)\n"),
842 : (uintptr_t) natp, d, (uintptr_t) offp, whence);
843 :
844 9 : NaClSysCommonThreadSyscallEnter(natp);
845 :
846 9 : ndp = NaClGetDesc(natp->nap, d);
847 9 : if (NULL == ndp) {
848 1 : retval = -NACL_ABI_EBADF;
849 1 : goto cleanup;
850 : }
851 :
852 8 : sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) offp, sizeof offset);
853 8 : if (kNaClBadAddress == sysaddr) {
854 0 : retval = -NACL_ABI_EFAULT;
855 0 : goto cleanup_unref;
856 : }
857 8 : offset = *(nacl_abi_off_t volatile *) sysaddr;
858 8 : NaClLog(4, "offset 0x%08"NACL_PRIxNACL_OFF"\n", offset);
859 :
860 8 : retval64 = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
861 : Seek)(ndp, (nacl_off64_t) offset, whence);
862 8 : if (NaClOff64IsNegErrno(&retval64)) {
863 2 : retval = (int32_t) retval64;
864 : } else {
865 6 : *(nacl_abi_off_t volatile *) sysaddr = retval64;
866 6 : retval = 0;
867 : }
868 8 : cleanup_unref:
869 8 : NaClDescUnref(ndp);
870 9 : cleanup:
871 9 : NaClSysCommonThreadSyscallLeave(natp);
872 9 : return retval;
873 : }
874 :
875 : int32_t NaClCommonSysIoctl(struct NaClAppThread *natp,
876 : int d,
877 : int request,
878 0 : void *arg) {
879 0 : int retval = -NACL_ABI_EINVAL;
880 : uintptr_t sysaddr;
881 : struct NaClDesc *ndp;
882 :
883 0 : NaClLog(3,
884 : ("Entered NaClSysIoctl(0x%08"NACL_PRIxPTR
885 : ", %d, %d, 0x%08"NACL_PRIxPTR")\n"),
886 : (uintptr_t) natp, d, request,
887 : (uintptr_t) arg);
888 :
889 0 : NaClSysCommonThreadSyscallEnter(natp);
890 : /*
891 : * Note that NaClUserToSysAddrRange is not feasible right now, since
892 : * the size of the arg argument depends on the request. We do not
893 : * have an enumeration of allowed ioctl requests yet.
894 : *
895 : * Furthermore, some requests take no arguments, so sysaddr might
896 : * end up being kNaClBadAddress and that is perfectly okay.
897 : */
898 0 : sysaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) arg);
899 : /*
900 : ****************************************
901 : * NOTE: sysaddr may be kNaClBadAddress *
902 : ****************************************
903 : */
904 :
905 0 : ndp = NaClGetDesc(natp->nap, d);
906 0 : if (NULL == ndp) {
907 0 : NaClLog(4, "bad desc\n");
908 0 : retval = -NACL_ABI_EBADF;
909 0 : goto cleanup;
910 : }
911 :
912 0 : retval = NaClIoctlAclCheck(natp->nap, ndp, request, arg);
913 0 : if (0 != retval) {
914 0 : NaClLog(3, "Ioctl ACL check rejected descriptor %d\n", d);
915 0 : goto cleanup_unref;
916 : }
917 :
918 0 : retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
919 : Ioctl)(ndp, request, (void *) sysaddr);
920 0 : cleanup_unref:
921 0 : NaClDescUnref(ndp);
922 0 : cleanup:
923 0 : NaClSysCommonThreadSyscallLeave(natp);
924 0 : return retval;
925 : }
926 :
927 :
928 : int32_t NaClCommonSysFstat(struct NaClAppThread *natp,
929 : int d,
930 5 : struct nacl_abi_stat *nasp) {
931 5 : int32_t retval = -NACL_ABI_EINVAL;
932 : uintptr_t sysaddr;
933 : struct NaClDesc *ndp;
934 :
935 5 : NaClLog(3,
936 : ("Entered NaClSysFstat(0x%08"NACL_PRIxPTR
937 : ", %d, 0x%08"NACL_PRIxPTR")\n"),
938 : (uintptr_t) natp,
939 : d, (uintptr_t) nasp);
940 :
941 5 : NaClSysCommonThreadSyscallEnter(natp);
942 :
943 5 : NaClLog(4,
944 : " sizeof(struct nacl_abi_stat) = %"NACL_PRIdS" (0x%"NACL_PRIxS")\n",
945 : sizeof *nasp, sizeof *nasp);
946 :
947 5 : ndp = NaClGetDesc(natp->nap, d);
948 5 : if (NULL == ndp) {
949 0 : NaClLog(4, "bad desc\n");
950 0 : retval = -NACL_ABI_EBADF;
951 0 : goto cleanup;
952 : }
953 :
954 5 : sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) nasp, sizeof *nasp);
955 5 : if (kNaClBadAddress == sysaddr) {
956 0 : NaClLog(4, "bad addr\n");
957 0 : retval = -NACL_ABI_EFAULT;
958 : } else {
959 5 : retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
960 : Fstat)(ndp, (struct nacl_abi_stat *) sysaddr);
961 : }
962 :
963 5 : NaClDescUnref(ndp);
964 5 : cleanup:
965 5 : NaClSysCommonThreadSyscallLeave(natp);
966 :
967 5 : return retval;
968 : }
969 :
970 : int32_t NaClCommonSysStat(struct NaClAppThread *natp,
971 : const char *pathname,
972 0 : struct nacl_abi_stat *buf) {
973 0 : int32_t retval = -NACL_ABI_EINVAL;
974 : uintptr_t syspathaddr;
975 : uintptr_t sysbufaddr;
976 : char path[NACL_CONFIG_PATH_MAX];
977 : size_t len;
978 : nacl_host_stat_t stbuf;
979 :
980 0 : NaClLog(3,
981 : ("Entered NaClCommonSysStat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR","
982 : " 0x%08"NACL_PRIxPTR")\n"),
983 : (uintptr_t) natp, (uintptr_t) pathname, (uintptr_t) buf);
984 :
985 0 : NaClSysCommonThreadSyscallEnter(natp);
986 :
987 0 : syspathaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) pathname);
988 0 : if (kNaClBadAddress == syspathaddr) {
989 0 : NaClLog(LOG_ERROR, "Invalid address for pathname\n");
990 0 : retval = -NACL_ABI_EFAULT;
991 0 : goto cleanup;
992 : }
993 : /*
994 : * strncpy may (try to) get bytes that is outside the app's address
995 : * space and generate a fault.
996 : */
997 0 : strncpy(path, (char *) syspathaddr, sizeof path);
998 : /*
999 : * survived the copy, but did there happen to be data beyond the end?
1000 : */
1001 0 : path[sizeof path - 1] = '\0'; /* always null terminate */
1002 0 : NaClLog(2, "NaClCommonSysStat: Path: %s\n", path);
1003 0 : len = strlen(path);
1004 : /*
1005 : * make sure sysaddr is a string, and the whole string is in app
1006 : * address space...
1007 : *
1008 : * address space is convex, so it is impossible for beginning and
1009 : * end to be both in the address space and yet have an intermediate
1010 : * byte not be in the address space.
1011 : */
1012 0 : if (kNaClBadAddress == NaClUserToSysAddr(natp->nap,
1013 : len + (uintptr_t) pathname)) {
1014 0 : NaClLog(LOG_ERROR, "String ends outside addrspace\n");
1015 0 : retval = -NACL_ABI_EFAULT;
1016 0 : goto cleanup;
1017 : }
1018 :
1019 : /*
1020 : * Make sure result buffer is in the app's address space.
1021 : */
1022 0 : sysbufaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, sizeof *buf);
1023 0 : if (kNaClBadAddress == sysbufaddr) {
1024 0 : retval = -NACL_ABI_EFAULT;
1025 0 : goto cleanup;
1026 : }
1027 :
1028 0 : retval = NaClStatAclCheck(natp->nap, path);
1029 0 : if (0 != retval) {
1030 0 : goto cleanup;
1031 : }
1032 :
1033 : /*
1034 : * Perform a host stat.
1035 : */
1036 0 : retval = NaClHostDescStat(path, &stbuf);
1037 0 : if (0 == retval) {
1038 0 : retval = NaClAbiStatHostDescStatXlateCtor((struct nacl_abi_stat *)
1039 : sysbufaddr,
1040 : &stbuf);
1041 : }
1042 0 : cleanup:
1043 0 : NaClSysCommonThreadSyscallLeave(natp);
1044 0 : return retval;
1045 : }
1046 :
1047 : void NaClCommonUtilUpdateAddrMap(struct NaClApp *nap,
1048 : uintptr_t sysaddr,
1049 : size_t nbytes,
1050 : int sysprot,
1051 : struct NaClDesc *backing_desc,
1052 : nacl_off64_t backing_bytes,
1053 : nacl_off64_t offset_bytes,
1054 4 : int delete_mem) {
1055 : uintptr_t usraddr;
1056 : struct NaClMemObj *nmop;
1057 :
1058 4 : NaClLog(3,
1059 : ("NaClCommonUtilUpdateAddrMap(0x%08"NACL_PRIxPTR", "
1060 : "0x%08"NACL_PRIxPTR", "
1061 : "0x%"NACL_PRIxS", 0x%x, 0x%08"NACL_PRIxPTR", 0x%"NACL_PRIx64", "
1062 : "0x%"NACL_PRIx64", %d)\n"),
1063 : (uintptr_t) nap, sysaddr, nbytes,
1064 : sysprot, (uintptr_t) backing_desc, backing_bytes,
1065 : offset_bytes,
1066 : delete_mem);
1067 4 : usraddr = NaClSysToUser(nap, sysaddr);
1068 4 : nmop = NULL;
1069 : /* delete_mem -> NULL == backing_desc */
1070 4 : if (NULL != backing_desc) {
1071 1 : if (delete_mem) {
1072 0 : NaClLog(LOG_FATAL,
1073 : ("invariant of delete_mem implies backing_desc NULL"
1074 : " violated.\n"));
1075 : }
1076 1 : nmop = NaClMemObjMake(backing_desc, backing_bytes, offset_bytes);
1077 : }
1078 :
1079 4 : NaClVmmapUpdate(&nap->mem_map,
1080 : usraddr >> NACL_PAGESHIFT,
1081 : nbytes >> NACL_PAGESHIFT,
1082 : sysprot,
1083 : nmop,
1084 : delete_mem);
1085 4 : }
1086 :
1087 :
1088 : int NaClSysCommonAddrRangeContainsExecutablePages_mu(struct NaClApp *nap,
1089 : uintptr_t usraddr,
1090 7 : size_t length) {
1091 : /*
1092 : * NOTE: currently only trampoline and text region are executable,
1093 : * and they are at the beginning of the address space, so this code
1094 : * is fine. We will probably never allow users to mark other pages
1095 : * as executable; but if so, we will have to revisit how this check
1096 : * is implemented.
1097 : *
1098 : * nap->static_text_end is a multiple of 4K, the memory protection
1099 : * granularity. Since this routine is used for checking whether
1100 : * memory map adjustments / allocations -- which has 64K granularity
1101 : * -- is okay, usraddr must be an allocation granularity value. Our
1102 : * callers (as of this writing) does this, but we truncate it down
1103 : * to an allocation boundary to be sure.
1104 : */
1105 : UNREFERENCED_PARAMETER(length);
1106 7 : usraddr = NaClTruncAllocPage(usraddr);
1107 7 : return usraddr < nap->dynamic_text_end;
1108 : }
1109 :
1110 :
1111 : /* Warning: sizeof(nacl_abi_off_t)!=sizeof(off_t) on OSX */
1112 : int32_t NaClCommonSysMmapIntern(struct NaClApp *nap,
1113 : void *start,
1114 : size_t length,
1115 : int prot,
1116 : int flags,
1117 : int d,
1118 5 : nacl_abi_off_t offset) {
1119 : int allowed_flags;
1120 : struct NaClDesc *ndp;
1121 : uintptr_t usraddr;
1122 : uintptr_t usrpage;
1123 : uintptr_t sysaddr;
1124 : uintptr_t endaddr;
1125 : uintptr_t map_result;
1126 : int holding_app_lock;
1127 : struct NaClMemObj *nmop;
1128 : struct nacl_abi_stat stbuf;
1129 : size_t alloc_rounded_length;
1130 : nacl_off64_t file_size;
1131 : nacl_off64_t file_bytes;
1132 : nacl_off64_t host_rounded_file_bytes;
1133 : size_t alloc_rounded_file_bytes;
1134 : size_t start_of_inaccessible;
1135 :
1136 5 : holding_app_lock = 0;
1137 5 : nmop = NULL;
1138 5 : ndp = NULL;
1139 :
1140 5 : allowed_flags = (NACL_ABI_MAP_FIXED | NACL_ABI_MAP_SHARED
1141 : | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS);
1142 :
1143 5 : usraddr = (uintptr_t) start;
1144 :
1145 5 : if (0 != (flags & ~allowed_flags)) {
1146 0 : NaClLog(LOG_WARNING, "invalid mmap flags 0%o, ignoring extraneous bits\n",
1147 : flags);
1148 0 : flags &= allowed_flags;
1149 : }
1150 :
1151 5 : if (0 != (flags & NACL_ABI_MAP_ANONYMOUS)) {
1152 : /*
1153 : * anonymous mmap, so backing store is just swap: no descriptor is
1154 : * involved, and no memory object will be created to represent the
1155 : * descriptor.
1156 : */
1157 4 : ndp = NULL;
1158 : } else {
1159 1 : ndp = NaClGetDesc(nap, d);
1160 1 : if (NULL == ndp) {
1161 0 : map_result = -NACL_ABI_EBADF;
1162 0 : goto cleanup;
1163 : }
1164 : }
1165 :
1166 : /*
1167 : * Starting address must be aligned to worst-case allocation
1168 : * granularity. (Windows.)
1169 : */
1170 5 : if (!NaClIsAllocPageMultiple(usraddr)) {
1171 1 : NaClLog(2, "NaClSysMmap: address not allocation granularity aligned\n");
1172 1 : map_result = -NACL_ABI_EINVAL;
1173 1 : goto cleanup;
1174 : }
1175 : /*
1176 : * Offset should be non-negative (nacl_abi_off_t is signed). This
1177 : * condition is caught when the file is stat'd and checked, and
1178 : * offset is ignored for anonymous mappings.
1179 : */
1180 4 : if (offset < 0) {
1181 0 : NaClLog(1, /* application bug */
1182 : "NaClSysMmap: negative file offset: %"NACL_PRIdNACL_OFF"\n",
1183 : offset);
1184 0 : map_result = -NACL_ABI_EINVAL;
1185 0 : goto cleanup;
1186 : }
1187 : /*
1188 : * And offset must be a multiple of the allocation unit.
1189 : */
1190 4 : if (!NaClIsAllocPageMultiple((uintptr_t) offset)) {
1191 0 : NaClLog(1,
1192 : ("NaClSysMmap: file offset 0x%08"NACL_PRIxPTR" not multiple"
1193 : " of allocation size\n"),
1194 : (uintptr_t) offset);
1195 0 : map_result = -NACL_ABI_EINVAL;
1196 0 : goto cleanup;
1197 : }
1198 :
1199 4 : if (0 == length) {
1200 0 : map_result = -NACL_ABI_EINVAL;
1201 0 : goto cleanup;
1202 : }
1203 4 : alloc_rounded_length = NaClRoundAllocPage(length);
1204 4 : if (alloc_rounded_length != length) {
1205 1 : NaClLog(1,
1206 : "mmap: rounded length to 0x%"NACL_PRIxS"\n",
1207 : alloc_rounded_length);
1208 : }
1209 :
1210 4 : if (NULL == ndp) {
1211 : /*
1212 : * Note: sentinel values are bigger than the NaCl module addr space.
1213 : */
1214 3 : file_size = kMaxUsableFileSize;
1215 3 : file_bytes = kMaxUsableFileSize;
1216 3 : host_rounded_file_bytes = kMaxUsableFileSize;
1217 3 : alloc_rounded_file_bytes = kMaxUsableFileSize;
1218 : } else {
1219 : /*
1220 : * We stat the file to figure out its actual size.
1221 : *
1222 : * This is needed since we allow an app to mmap in a odd-sized
1223 : * file and will zero fill the allocation page containing the last
1224 : * byte(s) of the file, but if the app asked for a length that
1225 : * goes beyond the last allocation page, that memory is actually
1226 : * inaccessible. Of course, the underlying OS deals with real
1227 : * pages, and we may need to simulate this behavior (i.e., OSX and
1228 : * Linux, we will need to put zero-filled pages between the last
1229 : * 4K system page containing file data and the rest of the
1230 : * simulated windows allocation 64K page.
1231 : */
1232 1 : map_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
1233 : Fstat)(ndp, &stbuf);
1234 1 : if (0 != map_result) {
1235 0 : goto cleanup;
1236 : }
1237 : /*
1238 : * BUG(bsy): there's a race between this fstat and the actual mmap
1239 : * below. It's probably insoluble. Even if we fstat again after
1240 : * mmap and compared, the mmap could have "seen" the file with a
1241 : * different size, after which the racing thread restored back to
1242 : * the same value before the 2nd fstat takes place.
1243 : */
1244 1 : file_size = stbuf.nacl_abi_st_size;
1245 :
1246 1 : if (file_size < offset) {
1247 0 : map_result = -NACL_ABI_EINVAL;
1248 0 : goto cleanup;
1249 : }
1250 :
1251 1 : file_bytes = file_size - offset;
1252 1 : NaClLog(4,
1253 : "NaClCommonSysMmapIntern: file_bytes 0x%016"NACL_PRIxNACL_OFF"\n",
1254 : file_bytes);
1255 1 : if ((nacl_off64_t) kMaxUsableFileSize < file_bytes) {
1256 0 : host_rounded_file_bytes = kMaxUsableFileSize;
1257 : } else {
1258 1 : host_rounded_file_bytes = NaClRoundHostAllocPage((size_t) file_bytes);
1259 : }
1260 :
1261 1 : ASSERT(host_rounded_file_bytes <= (nacl_off64_t) kMaxUsableFileSize);
1262 : /*
1263 : * We need to deal with NaClRoundHostAllocPage rounding up to zero
1264 : * from ~0u - n, where n < 4096 or 65536 (== 1 alloc page).
1265 : *
1266 : * Luckily, file_bytes is at most kMaxUsableFileSize which is
1267 : * smaller than SIZE_T_MAX, so it should never happen, but we
1268 : * leave the explicit check below as defensive programming.
1269 : */
1270 1 : alloc_rounded_file_bytes =
1271 : NaClRoundAllocPage((size_t) host_rounded_file_bytes);
1272 :
1273 1 : if (0 == alloc_rounded_file_bytes && 0 != host_rounded_file_bytes) {
1274 0 : map_result = -NACL_ABI_ENOMEM;
1275 0 : goto cleanup;
1276 : }
1277 :
1278 : /*
1279 : * NB: host_rounded_file_bytes and alloc_rounded_file_bytes can be
1280 : * zero. Such an mmap just makes memory (offset relative to
1281 : * usraddr) in the range [0, alloc_rounded_length) inaccessible.
1282 : */
1283 : }
1284 :
1285 : /*
1286 : * host_rounded_file_bytes is how many bytes we can map from the
1287 : * file, given the user-supplied starting offset. It is at least
1288 : * one page. If it came from a real file, it is a multiple of
1289 : * host-OS allocation size. it cannot be larger than
1290 : * kMaxUsableFileSize.
1291 : */
1292 4 : length = size_min(alloc_rounded_length, (size_t) host_rounded_file_bytes);
1293 4 : start_of_inaccessible = size_min(alloc_rounded_length,
1294 : alloc_rounded_file_bytes);
1295 :
1296 : /*
1297 : * Now, we map, relative to usraddr, bytes [0, length) from the file
1298 : * starting at offset, zero-filled pages for the memory region
1299 : * [length, start_of_inaccessible), and inaccessible pages for the
1300 : * memory region [start_of_inaccessible, alloc_rounded_length).
1301 : */
1302 :
1303 : /*
1304 : * Lock the addr space.
1305 : */
1306 4 : NaClXMutexLock(&nap->mu);
1307 :
1308 8 : while (0 != nap->threads_launching) {
1309 0 : NaClXCondVarWait(&nap->cv, &nap->mu);
1310 : }
1311 4 : nap->vm_hole_may_exist = 1;
1312 4 : NaClUntrustedThreadsSuspend(nap);
1313 :
1314 4 : holding_app_lock = 1;
1315 :
1316 4 : if (0 == (flags & NACL_ABI_MAP_FIXED)) {
1317 : /*
1318 : * The user wants us to pick an address range.
1319 : */
1320 3 : if (0 == usraddr) {
1321 : /*
1322 : * Pick a hole in addr space of appropriate size, anywhere.
1323 : * We pick one that's best for the system.
1324 : */
1325 3 : usrpage = NaClVmmapFindMapSpace(&nap->mem_map,
1326 : alloc_rounded_length >> NACL_PAGESHIFT);
1327 3 : NaClLog(4, "NaClSysMmap: FindMapSpace: page 0x%05"NACL_PRIxPTR"\n",
1328 : usrpage);
1329 3 : if (0 == usrpage) {
1330 0 : map_result = -NACL_ABI_ENOMEM;
1331 0 : goto cleanup;
1332 : }
1333 3 : usraddr = usrpage << NACL_PAGESHIFT;
1334 3 : NaClLog(4, "NaClSysMmap: new starting addr: 0x%08"NACL_PRIxPTR
1335 : "\n", usraddr);
1336 : } else {
1337 : /*
1338 : * user supplied an addr, but it's to be treated as a hint; we
1339 : * find a hole of the right size in the app's address space,
1340 : * according to the usual mmap semantics.
1341 : */
1342 0 : usrpage = NaClVmmapFindMapSpaceAboveHint(&nap->mem_map,
1343 : usraddr,
1344 : (alloc_rounded_length
1345 : >> NACL_PAGESHIFT));
1346 0 : NaClLog(4, "NaClSysMmap: FindSpaceAboveHint: page 0x%05"NACL_PRIxPTR"\n",
1347 : usrpage);
1348 0 : if (0 == usrpage) {
1349 0 : NaClLog(4, "NaClSysMmap: hint failed, doing generic allocation\n");
1350 0 : usrpage = NaClVmmapFindMapSpace(&nap->mem_map,
1351 : alloc_rounded_length >> NACL_PAGESHIFT);
1352 : }
1353 0 : if (0 == usrpage) {
1354 0 : map_result = -NACL_ABI_ENOMEM;
1355 0 : goto cleanup;
1356 : }
1357 0 : usraddr = usrpage << NACL_PAGESHIFT;
1358 0 : NaClLog(4, "NaClSysMmap: new starting addr: 0x%08"NACL_PRIxPTR"\n",
1359 : usraddr);
1360 : }
1361 : }
1362 :
1363 : /*
1364 : * Validate [usraddr, endaddr) is okay.
1365 : */
1366 4 : if (usraddr >= ((uintptr_t) 1 << nap->addr_bits)) {
1367 0 : NaClLog(2,
1368 : ("NaClSysMmap: start address (0x%08"NACL_PRIxPTR") outside address"
1369 : " space\n"),
1370 : usraddr);
1371 0 : map_result = -NACL_ABI_EINVAL;
1372 0 : goto cleanup;
1373 : }
1374 4 : endaddr = usraddr + alloc_rounded_length;
1375 4 : if (endaddr < usraddr) {
1376 0 : NaClLog(0,
1377 : ("NaClSysMmap: integer overflow -- "
1378 : "NaClSysMmap(0x%08"NACL_PRIxPTR",0x%"NACL_PRIxS",0x%x,0x%x,%d,"
1379 : "0x%08"NACL_PRIxPTR"\n"),
1380 : usraddr, length, prot, flags, d, (uintptr_t) offset);
1381 0 : map_result = -NACL_ABI_EINVAL;
1382 0 : goto cleanup;
1383 : }
1384 : /*
1385 : * NB: we use > instead of >= here.
1386 : *
1387 : * endaddr is the address of the first byte beyond the target region
1388 : * and it can equal the address space limit. (of course, normally
1389 : * the main thread's stack is there.)
1390 : */
1391 4 : if (endaddr > ((uintptr_t) 1 << nap->addr_bits)) {
1392 0 : NaClLog(2,
1393 : ("NaClSysMmap: end address (0x%08"NACL_PRIxPTR") is beyond"
1394 : " the end of the address space\n"),
1395 : endaddr);
1396 0 : map_result = -NACL_ABI_EINVAL;
1397 0 : goto cleanup;
1398 : }
1399 :
1400 4 : if (NaClSysCommonAddrRangeContainsExecutablePages_mu(nap,
1401 : usraddr,
1402 : length)) {
1403 1 : NaClLog(2, "NaClSysMmap: region contains executable pages\n");
1404 1 : map_result = -NACL_ABI_EINVAL;
1405 1 : goto cleanup;
1406 : }
1407 :
1408 : /*
1409 : * Force NACL_ABI_MAP_FIXED, since we are specifying address in NaCl
1410 : * app address space.
1411 : */
1412 3 : flags |= NACL_ABI_MAP_FIXED;
1413 :
1414 : /*
1415 : * Never allow users to say that mmapped pages are executable. This
1416 : * is primarily for the service runtime's own bookkeeping -- prot is
1417 : * used in NaClCommonUtilUpdateAddrMap -- since %cs restriction
1418 : * makes page protection irrelevant, it doesn't matter that on many
1419 : * systems (w/o NX) PROT_READ implies PROT_EXEC.
1420 : */
1421 3 : prot &= ~NACL_ABI_PROT_EXEC;
1422 :
1423 : /*
1424 : * Exactly one of NACL_ABI_MAP_SHARED and NACL_ABI_MAP_PRIVATE is set.
1425 : */
1426 3 : if ((0 == (flags & NACL_ABI_MAP_SHARED))
1427 : == (0 == (flags & NACL_ABI_MAP_PRIVATE))) {
1428 0 : map_result = -NACL_ABI_EINVAL;
1429 0 : goto cleanup;
1430 : }
1431 :
1432 3 : sysaddr = NaClUserToSys(nap, usraddr);
1433 :
1434 : /* [0, length) */
1435 3 : if (length > 0) {
1436 3 : if (NULL == ndp) {
1437 2 : NaClLog(4,
1438 : ("NaClSysMmap: NaClDescIoDescMap(,,0x%08"NACL_PRIxPTR","
1439 : "0x%08"NACL_PRIxS",0x%x,0x%x,0x%08"NACL_PRIxPTR")\n"),
1440 : sysaddr, length, prot, flags, (uintptr_t) offset);
1441 2 : map_result = NaClDescIoDescMapAnon(nap->effp,
1442 : (void *) sysaddr,
1443 : length,
1444 : prot,
1445 : flags,
1446 : (off_t) offset);
1447 : } else {
1448 : /*
1449 : * This is a fix for Windows, where we cannot pass a size that
1450 : * goes beyond the non-page-rounded end of the file.
1451 : */
1452 1 : size_t length_to_map = size_min(length, (size_t) file_bytes);
1453 :
1454 1 : NaClLog(4,
1455 : ("NaClSysMmap: (*ndp->Map)(,,0x%08"NACL_PRIxPTR","
1456 : "0x%08"NACL_PRIxS",0x%x,0x%x,0x%08"NACL_PRIxPTR")\n"),
1457 : sysaddr, length, prot, flags, (uintptr_t) offset);
1458 :
1459 1 : map_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
1460 : Map)(ndp,
1461 : nap->effp,
1462 : (void *) sysaddr,
1463 : length_to_map,
1464 : prot,
1465 : flags,
1466 : (off_t) offset);
1467 : }
1468 : /*
1469 : * "Small" negative integers are errno values. Larger ones are
1470 : * virtual addresses.
1471 : */
1472 3 : if (NaClPtrIsNegErrno(&map_result)) {
1473 0 : NaClLog(LOG_FATAL,
1474 : ("NaClSysMmap: Map failed, but we"
1475 : " cannot handle address space move, error %"NACL_PRIuS"\n"),
1476 : (size_t) map_result);
1477 : }
1478 3 : if (map_result != sysaddr) {
1479 0 : NaClLog(LOG_FATAL, "system mmap did not honor NACL_ABI_MAP_FIXED\n");
1480 : }
1481 3 : if (prot == NACL_ABI_PROT_NONE) {
1482 : /*
1483 : * windows nacl_host_desc implementation requires that PROT_NONE
1484 : * memory be freed using VirtualFree rather than
1485 : * UnmapViewOfFile. TODO(bsy): remove this ugliness.
1486 : */
1487 1 : NaClCommonUtilUpdateAddrMap(nap, sysaddr, length, PROT_NONE,
1488 : NULL, file_size, offset, 0);
1489 : } else {
1490 : /* record change for file-backed memory */
1491 2 : NaClCommonUtilUpdateAddrMap(nap, sysaddr, length, NaClProtMap(prot),
1492 : ndp, file_size, offset, 0);
1493 : }
1494 : } else {
1495 0 : map_result = sysaddr;
1496 : }
1497 : /* zero fill [length, start_of_inaccessible) */
1498 3 : if (length < start_of_inaccessible) {
1499 1 : size_t map_len = start_of_inaccessible - length;
1500 :
1501 1 : NaClLog(2,
1502 : ("zero-filling pages for memory range"
1503 : " [0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR
1504 : "), length 0x%"NACL_PRIxS"\n"),
1505 : sysaddr + length, sysaddr + start_of_inaccessible, map_len);
1506 1 : map_result = NaClHostDescMap((struct NaClHostDesc *) NULL,
1507 : (void *) (sysaddr + length),
1508 : map_len,
1509 : prot,
1510 : NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
1511 : (off_t) 0);
1512 1 : if (NaClPtrIsNegErrno(&map_result)) {
1513 0 : NaClLog(LOG_ERROR,
1514 : ("Could not create zero-filled pages for memory range"
1515 : " [0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR")\n"),
1516 : sysaddr + length, sysaddr + start_of_inaccessible);
1517 0 : goto cleanup;
1518 : }
1519 1 : NaClCommonUtilUpdateAddrMap(nap, sysaddr + length, map_len,
1520 : NaClProtMap(prot),
1521 : (struct NaClDesc *) NULL, 0, (off_t) 0, 0);
1522 : }
1523 : /* inaccessible: [start_of_inaccessible, alloc_rounded_length) */
1524 3 : if (start_of_inaccessible < alloc_rounded_length) {
1525 0 : size_t map_len = alloc_rounded_length - start_of_inaccessible;
1526 :
1527 0 : NaClLog(2,
1528 : ("inaccessible pages for memory range"
1529 : " [0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR"),"
1530 : " length 0x%"NACL_PRIxS"\n"),
1531 : sysaddr + start_of_inaccessible,
1532 : sysaddr + alloc_rounded_length,
1533 : map_len);
1534 0 : map_result = NaClHostDescMap((struct NaClHostDesc *) NULL,
1535 : (void *) (sysaddr + start_of_inaccessible),
1536 : map_len,
1537 : NACL_ABI_PROT_NONE,
1538 : NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
1539 : (off_t) 0);
1540 0 : if (NaClPtrIsNegErrno(&map_result)) {
1541 0 : NaClLog(LOG_ERROR,
1542 : ("Could not create inaccessible pages for memory range"
1543 : " [0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR
1544 : "), length 0x%"NACL_PRIxS"\n"),
1545 : sysaddr + start_of_inaccessible,
1546 : sysaddr + alloc_rounded_length,
1547 : map_len);
1548 : }
1549 0 : NaClCommonUtilUpdateAddrMap(nap, sysaddr + start_of_inaccessible,
1550 : map_len, PROT_NONE,
1551 : (struct NaClDesc *) NULL, 0,
1552 : (off_t) 0, 0);
1553 : }
1554 3 : NaClLog(3, "NaClSysMmap: got address 0x%08"NACL_PRIxPTR"\n",
1555 : (uintptr_t) map_result);
1556 :
1557 3 : map_result = usraddr;
1558 :
1559 5 : cleanup:
1560 5 : if (holding_app_lock) {
1561 4 : nap->vm_hole_may_exist = 0;
1562 4 : NaClXCondVarBroadcast(&nap->cv);
1563 4 : NaClXMutexUnlock(&nap->mu);
1564 :
1565 4 : NaClUntrustedThreadsResume(nap);
1566 : }
1567 5 : if (NULL != ndp) {
1568 1 : NaClDescUnref(ndp);
1569 : }
1570 5 : if (NaClPtrIsNegErrno(&map_result)) {
1571 2 : free(nmop);
1572 : }
1573 :
1574 : /*
1575 : * Check to ensure that map_result will fit into a 32-bit value. This is
1576 : * a bit tricky because there are two valid ranges: one is the range from
1577 : * 0 to (almost) 2^32, the other is from -1 to -4096 (our error range).
1578 : * For a 32-bit value these ranges would overlap, but if the value is 64-bit
1579 : * they will be disjoint.
1580 : */
1581 : if (map_result > UINT32_MAX
1582 : && !NaClPtrIsNegErrno(&map_result)) {
1583 : NaClLog(LOG_FATAL, "Overflow in NaClSysMmap: return address is "
1584 : "0x%"NACL_PRIxPTR"\n", map_result);
1585 : }
1586 5 : NaClLog(3, "NaClSysMmap: returning 0x%08"NACL_PRIxPTR"\n", map_result);
1587 :
1588 5 : return (int32_t) map_result;
1589 : }
1590 :
1591 : int32_t NaClCommonSysMmap(struct NaClAppThread *natp,
1592 : void *start,
1593 : size_t length,
1594 : int prot,
1595 : int flags,
1596 : int d,
1597 5 : nacl_abi_off_t *offp) {
1598 : int32_t retval;
1599 : uintptr_t sysaddr;
1600 : nacl_abi_off_t offset;
1601 :
1602 5 : NaClLog(3,
1603 : "Entered NaClSysMmap(0x%08"NACL_PRIxPTR",0x%"NACL_PRIxS","
1604 : "0x%x,0x%x,%d,0x%08"NACL_PRIxPTR")\n",
1605 : (uintptr_t) start, length, prot, flags, d, (uintptr_t) offp);
1606 :
1607 5 : if ((nacl_abi_off_t *) 0 == offp) {
1608 : /*
1609 : * This warning is really targetted towards trusted code,
1610 : * especially tests that didn't notice the argument type change.
1611 : * Unfortunatey, zero is a common and legitimate offset value, and
1612 : * the compiler will not complain since an automatic type
1613 : * conversion works.
1614 : */
1615 0 : NaClLog(LOG_WARNING,
1616 : "NaClCommonSysMmap: NULL pointer used"
1617 : " for offset in/out argument\n");
1618 0 : return -NACL_ABI_EINVAL;
1619 : }
1620 :
1621 5 : NaClSysCommonThreadSyscallEnter(natp);
1622 :
1623 5 : sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) offp, sizeof offset);
1624 5 : if (kNaClBadAddress == sysaddr) {
1625 0 : NaClLog(3,
1626 : "NaClCommonSysMmap: offset in a bad untrusted memory location\n");
1627 0 : retval = -NACL_ABI_EFAULT;
1628 0 : goto cleanup;
1629 : }
1630 5 : offset = *(nacl_abi_off_t volatile *) sysaddr;
1631 :
1632 5 : NaClLog(4, " offset = 0x%08"NACL_PRIxNACL_OFF"\n", offset);
1633 :
1634 5 : retval = NaClCommonSysMmapIntern(natp->nap,
1635 : start, length,
1636 : prot,
1637 : flags,
1638 : d, offset);
1639 5 : cleanup:
1640 5 : NaClSysCommonThreadSyscallLeave(natp);
1641 :
1642 5 : return retval;
1643 : }
1644 :
1645 : int32_t NaClCommonSysImc_MakeBoundSock(struct NaClAppThread *natp,
1646 0 : int32_t *sap) {
1647 : /*
1648 : * Create a bound socket descriptor and a socket address descriptor.
1649 : */
1650 :
1651 0 : int32_t retval = -NACL_ABI_EINVAL;
1652 : uintptr_t sys_sap;
1653 : struct NaClDesc *pair[2];
1654 :
1655 0 : NaClLog(3,
1656 : ("Entered NaClCommonSysImc_MakeBoundSock(0x%08"NACL_PRIxPTR","
1657 : " 0x%08"NACL_PRIxPTR")\n"),
1658 : (uintptr_t) natp, (uintptr_t) sap);
1659 :
1660 0 : NaClSysCommonThreadSyscallEnter(natp);
1661 :
1662 0 : sys_sap = NaClUserToSysAddrRange(natp->nap,
1663 : (uintptr_t) sap,
1664 : 2 * sizeof *sap);
1665 0 : if (kNaClBadAddress == sys_sap) {
1666 0 : NaClLog(3, " illegal address\n");
1667 0 : retval = -NACL_ABI_EFAULT;
1668 0 : goto cleanup;
1669 : }
1670 :
1671 0 : retval = NaClCommonDescMakeBoundSock(pair);
1672 0 : if (0 != retval) {
1673 0 : goto cleanup;
1674 : }
1675 :
1676 0 : ((int32_t *) sys_sap)[0] = NaClSetAvail(natp->nap, pair[0]);
1677 0 : ((int32_t *) sys_sap)[1] = NaClSetAvail(natp->nap, pair[1]);
1678 0 : retval = 0;
1679 0 : cleanup:
1680 0 : NaClSysCommonThreadSyscallLeave(natp);
1681 :
1682 0 : return retval;
1683 : }
1684 :
1685 : int32_t NaClCommonSysImc_Accept(struct NaClAppThread *natp,
1686 0 : int d) {
1687 0 : int32_t retval = -NACL_ABI_EINVAL;
1688 : struct NaClDesc *ndp;
1689 :
1690 0 : NaClLog(3, "Entered NaClSysImc_Accept(0x%08"NACL_PRIxPTR", %d)\n",
1691 : (uintptr_t) natp, d);
1692 :
1693 0 : NaClSysCommonThreadSyscallEnter(natp);
1694 :
1695 0 : ndp = NaClGetDesc(natp->nap, d);
1696 0 : if (NULL == ndp) {
1697 0 : retval = -NACL_ABI_EBADF;
1698 : } else {
1699 : struct NaClDesc *result_desc;
1700 0 : retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
1701 : AcceptConn)(ndp, &result_desc);
1702 0 : if (retval == 0) {
1703 0 : retval = NaClSetAvail(natp->nap, result_desc);
1704 : }
1705 0 : NaClDescUnref(ndp);
1706 : }
1707 :
1708 0 : NaClSysCommonThreadSyscallLeave(natp);
1709 0 : return retval;
1710 : }
1711 :
1712 : int32_t NaClCommonSysImc_Connect(struct NaClAppThread *natp,
1713 0 : int d) {
1714 0 : int32_t retval = -NACL_ABI_EINVAL;
1715 : struct NaClDesc *ndp;
1716 :
1717 0 : NaClLog(3, "Entered NaClSysImc_ConnectAddr(0x%08"NACL_PRIxPTR", %d)\n",
1718 : (uintptr_t) natp, d);
1719 :
1720 0 : NaClSysCommonThreadSyscallEnter(natp);
1721 :
1722 0 : ndp = NaClGetDesc(natp->nap, d);
1723 0 : if (NULL == ndp) {
1724 0 : retval = -NACL_ABI_EBADF;
1725 : } else {
1726 : struct NaClDesc *result;
1727 0 : retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
1728 : ConnectAddr)(ndp, &result);
1729 0 : if (retval == 0) {
1730 0 : retval = NaClSetAvail(natp->nap, result);
1731 : }
1732 0 : NaClDescUnref(ndp);
1733 : }
1734 :
1735 0 : NaClSysCommonThreadSyscallLeave(natp);
1736 0 : return retval;
1737 : }
1738 :
1739 : /*
1740 : * This function converts addresses from user addresses to system
1741 : * addresses, copying into kernel space as needed to avoid TOCvTOU
1742 : * races, then invoke NaClImcSendTypedMessage from the nrd_xfer
1743 : * library.
1744 : */
1745 : int32_t NaClCommonSysImc_Sendmsg(struct NaClAppThread *natp,
1746 : int d,
1747 : struct NaClAbiNaClImcMsgHdr *nanimhp,
1748 0 : int flags) {
1749 0 : int32_t retval = -NACL_ABI_EINVAL;
1750 : ssize_t ssize_retval;
1751 : uintptr_t sysaddr;
1752 : /* copy of user-space data for validation */
1753 : struct NaClAbiNaClImcMsgHdr kern_nanimh;
1754 : struct NaClAbiNaClImcMsgIoVec kern_naiov[NACL_ABI_IMC_IOVEC_MAX];
1755 : struct NaClImcMsgIoVec kern_iov[NACL_ABI_IMC_IOVEC_MAX];
1756 : /* kernel-side representatin of descriptors */
1757 : struct NaClDesc *kern_desc[NACL_ABI_IMC_USER_DESC_MAX];
1758 : struct NaClImcTypedMsgHdr kern_msg_hdr;
1759 : struct NaClDesc *ndp;
1760 : size_t i;
1761 :
1762 0 : NaClLog(3,
1763 : ("Entered NaClCommonSysImc_Sendmsg(0x%08"NACL_PRIxPTR", %d,"
1764 : " 0x%08"NACL_PRIxPTR", 0x%x)\n"),
1765 : (uintptr_t) natp, d, (uintptr_t) nanimhp, flags);
1766 :
1767 0 : NaClSysCommonThreadSyscallEnter(natp);
1768 :
1769 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
1770 : (uintptr_t) nanimhp,
1771 : sizeof *nanimhp);
1772 0 : if (kNaClBadAddress == sysaddr) {
1773 0 : NaClLog(4, "NaClImcMsgHdr not in user address space\n");
1774 0 : retval = -NACL_ABI_EFAULT;
1775 0 : goto cleanup_leave;
1776 : }
1777 :
1778 0 : kern_nanimh = *(struct NaClAbiNaClImcMsgHdr volatile *) sysaddr;
1779 : /* copy before validating */
1780 :
1781 : /*
1782 : * Some of these checks duplicate checks that will be done in the
1783 : * nrd xfer library, but it is better to check before doing the
1784 : * address translation of memory/descriptor vectors if those vectors
1785 : * might be too long. Plus, we need to copy and validate vectors
1786 : * for TOCvTOU race protection, and we must prevent overflows. The
1787 : * nrd xfer library's checks should never fire when called from the
1788 : * service runtime, but the nrd xfer library might be called from
1789 : * other code.
1790 : */
1791 0 : if (kern_nanimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
1792 0 : NaClLog(4, "gather/scatter array too large\n");
1793 0 : retval = -NACL_ABI_EINVAL;
1794 0 : goto cleanup_leave;
1795 : }
1796 0 : if (kern_nanimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
1797 0 : NaClLog(4, "handle vector too long\n");
1798 0 : retval = -NACL_ABI_EINVAL;
1799 0 : goto cleanup_leave;
1800 : }
1801 :
1802 0 : if (kern_nanimh.iov_length > 0) {
1803 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
1804 : (uintptr_t) kern_nanimh.iov,
1805 : (kern_nanimh.iov_length
1806 : * sizeof kern_naiov[0]));
1807 0 : if (kNaClBadAddress == sysaddr) {
1808 0 : NaClLog(4, "gather/scatter array not in user address space\n");
1809 0 : retval = -NACL_ABI_EFAULT;
1810 0 : goto cleanup_leave;
1811 : }
1812 :
1813 0 : memcpy(kern_naiov, (void *) sysaddr,
1814 : kern_nanimh.iov_length * sizeof kern_naiov[0]);
1815 :
1816 0 : for (i = 0; i < kern_nanimh.iov_length; ++i) {
1817 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
1818 : (uintptr_t) kern_naiov[i].base,
1819 : kern_naiov[i].length);
1820 0 : if (kNaClBadAddress == sysaddr) {
1821 0 : retval = -NACL_ABI_EFAULT;
1822 0 : goto cleanup_leave;
1823 : }
1824 0 : kern_iov[i].base = (void *) sysaddr;
1825 0 : kern_iov[i].length = kern_naiov[i].length;
1826 : }
1827 : }
1828 :
1829 0 : ndp = NaClGetDesc(natp->nap, d);
1830 0 : if (NULL == ndp) {
1831 0 : retval = -NACL_ABI_EBADF;
1832 0 : goto cleanup_leave;
1833 : }
1834 :
1835 : /*
1836 : * make things easier for cleaup exit processing
1837 : */
1838 0 : memset(kern_desc, 0, sizeof kern_desc);
1839 0 : retval = -NACL_ABI_EINVAL;
1840 :
1841 0 : kern_msg_hdr.iov = kern_iov;
1842 0 : kern_msg_hdr.iov_length = kern_nanimh.iov_length;
1843 :
1844 0 : if (0 == kern_nanimh.desc_length) {
1845 0 : kern_msg_hdr.ndescv = 0;
1846 0 : kern_msg_hdr.ndesc_length = 0;
1847 : } else {
1848 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
1849 : (uintptr_t) kern_nanimh.descv,
1850 : kern_nanimh.desc_length * sizeof(int32_t));
1851 0 : if (kNaClBadAddress == sysaddr) {
1852 0 : retval = -NACL_ABI_EFAULT;
1853 0 : goto cleanup;
1854 : }
1855 :
1856 : /*
1857 : * NB: for each descv entry, we read from NaCl app address space
1858 : * exactly once.
1859 : */
1860 0 : for (i = 0; i < kern_nanimh.desc_length; ++i) {
1861 0 : int32_t user_desc = ((volatile int32_t *) sysaddr)[i];
1862 : /* fetch it once */
1863 :
1864 0 : if (kKnownInvalidDescNumber == user_desc) {
1865 0 : kern_desc[i] = (struct NaClDesc *) NaClDescInvalidMake();
1866 : } else {
1867 : /* NaCl modules are ILP32, so this works on ILP32 and LP64 systems */
1868 0 : kern_desc[i] = NaClGetDesc(natp->nap, user_desc);
1869 : }
1870 0 : if (NULL == kern_desc[i]) {
1871 0 : retval = -NACL_ABI_EBADF;
1872 0 : goto cleanup;
1873 : }
1874 : }
1875 0 : kern_msg_hdr.ndescv = kern_desc;
1876 0 : kern_msg_hdr.ndesc_length = kern_nanimh.desc_length;
1877 : }
1878 0 : kern_msg_hdr.flags = kern_nanimh.flags;
1879 :
1880 0 : ssize_retval = NaClImcSendTypedMessage(ndp, &kern_msg_hdr, flags);
1881 :
1882 0 : if (NaClSSizeIsNegErrno(&ssize_retval)) {
1883 : /*
1884 : * NaClWouldBlock uses TSD (for both the errno-based and
1885 : * GetLastError()-based implementations), so this is threadsafe.
1886 : */
1887 0 : if (0 != (flags & NACL_DONT_WAIT) && NaClWouldBlock()) {
1888 0 : retval = -NACL_ABI_EAGAIN;
1889 0 : } else if (-NACL_ABI_EMSGSIZE == ssize_retval) {
1890 : /*
1891 : * Allow the caller to handle the case when imc_sendmsg fails because
1892 : * the message is too large for the system to send in one piece.
1893 : */
1894 0 : retval = -NACL_ABI_EMSGSIZE;
1895 : } else {
1896 : /*
1897 : * TODO(bsy): the else case is some mysterious internal error.
1898 : * Should we destroy the ndp or otherwise mark it as bad? Was
1899 : * the failure atomic? Did it send some partial data? Linux
1900 : * implementation appears okay.
1901 : */
1902 0 : retval = -NACL_ABI_EIO;
1903 : }
1904 : } else if (ssize_retval > INT32_MAX || ssize_retval < INT32_MIN) {
1905 : retval = -NACL_ABI_EOVERFLOW;
1906 : } else {
1907 : /* cast is safe due to range checks above */
1908 0 : retval = (int32_t)ssize_retval;
1909 : }
1910 :
1911 0 : cleanup:
1912 0 : for (i = 0; i < kern_nanimh.desc_length; ++i) {
1913 0 : if (NULL != kern_desc[i]) {
1914 0 : NaClDescUnref(kern_desc[i]);
1915 0 : kern_desc[i] = NULL;
1916 : }
1917 : }
1918 0 : NaClDescUnref(ndp);
1919 0 : cleanup_leave:
1920 0 : NaClSysCommonThreadSyscallLeave(natp);
1921 0 : NaClLog(3, "NaClCommonSysImc_Sendmsg: returning %d\n", retval);
1922 0 : return retval;
1923 : }
1924 :
1925 : int32_t NaClCommonSysImc_Recvmsg(struct NaClAppThread *natp,
1926 : int d,
1927 : struct NaClAbiNaClImcMsgHdr *nanimhp,
1928 0 : int flags) {
1929 0 : int32_t retval = -NACL_ABI_EINVAL;
1930 : ssize_t ssize_retval;
1931 : uintptr_t sysaddr;
1932 : struct NaClAbiNaClImcMsgHdr volatile *kern_nanimhp;
1933 : size_t i;
1934 : struct NaClDesc *ndp;
1935 : struct NaClAbiNaClImcMsgHdr kern_nanimh;
1936 : struct NaClAbiNaClImcMsgIoVec kern_naiov[NACL_ABI_IMC_IOVEC_MAX];
1937 : struct NaClImcMsgIoVec kern_iov[NACL_ABI_IMC_IOVEC_MAX];
1938 : int32_t volatile *kern_descv;
1939 : struct NaClImcTypedMsgHdr recv_hdr;
1940 : struct NaClDesc *new_desc[NACL_ABI_IMC_DESC_MAX];
1941 : nacl_abi_size_t num_user_desc;
1942 0 : struct NaClDesc *invalid_desc = NULL;
1943 :
1944 0 : NaClLog(3,
1945 : ("Entered NaClCommonSysImc_RecvMsg(0x%08"NACL_PRIxPTR", %d,"
1946 : " 0x%08"NACL_PRIxPTR")\n"),
1947 : (uintptr_t) natp, d, (uintptr_t) nanimhp);
1948 :
1949 0 : NaClSysCommonThreadSyscallEnter(natp);
1950 :
1951 : /*
1952 : * First, we validate user-supplied message headers before
1953 : * allocating a receive buffer.
1954 : */
1955 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
1956 : (uintptr_t) nanimhp,
1957 : sizeof *nanimhp);
1958 0 : if (kNaClBadAddress == sysaddr) {
1959 0 : NaClLog(4, "NaClImcMsgHdr not in user address space\n");
1960 0 : retval = -NACL_ABI_EFAULT;
1961 0 : goto cleanup_leave;
1962 : }
1963 0 : kern_nanimhp = (struct NaClAbiNaClImcMsgHdr volatile *) sysaddr;
1964 0 : kern_nanimh = *kern_nanimhp;
1965 : /* copy before validating */
1966 :
1967 0 : if (kern_nanimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
1968 0 : NaClLog(4, "gather/scatter array too large: %"NACL_PRIdNACL_SIZE"\n",
1969 : kern_nanimh.iov_length);
1970 0 : retval = -NACL_ABI_EINVAL;
1971 0 : goto cleanup_leave;
1972 : }
1973 0 : if (kern_nanimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
1974 0 : NaClLog(4, "handle vector too long: %"NACL_PRIdNACL_SIZE"\n",
1975 : kern_nanimh.desc_length);
1976 0 : retval = -NACL_ABI_EINVAL;
1977 0 : goto cleanup_leave;
1978 : }
1979 :
1980 0 : if (kern_nanimh.iov_length > 0) {
1981 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
1982 : (uintptr_t) kern_nanimh.iov,
1983 : (kern_nanimh.iov_length
1984 : * sizeof kern_naiov[0]));
1985 0 : if (kNaClBadAddress == sysaddr) {
1986 0 : NaClLog(4, "gather/scatter array not in user address space\n");
1987 0 : retval = -NACL_ABI_EFAULT;
1988 0 : goto cleanup_leave;
1989 : }
1990 : /*
1991 : * Copy IOV array into kernel space. Validate this snapshot and do
1992 : * user->kernel address conversions on this snapshot.
1993 : */
1994 0 : memcpy(kern_naiov, (void *) sysaddr,
1995 : kern_nanimh.iov_length * sizeof kern_naiov[0]);
1996 : /*
1997 : * Convert every IOV base from user to system address, validate
1998 : * range of bytes are really in user address space.
1999 : */
2000 :
2001 0 : for (i = 0; i < kern_nanimh.iov_length; ++i) {
2002 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
2003 : (uintptr_t) kern_naiov[i].base,
2004 : kern_naiov[i].length);
2005 0 : if (kNaClBadAddress == sysaddr) {
2006 0 : NaClLog(4, "iov number %"NACL_PRIdS" not entirely in user space\n", i);
2007 0 : retval = -NACL_ABI_EFAULT;
2008 0 : goto cleanup_leave;
2009 : }
2010 0 : kern_iov[i].base = (void *) sysaddr;
2011 0 : kern_iov[i].length = kern_naiov[i].length;
2012 : }
2013 : }
2014 :
2015 0 : if (kern_nanimh.desc_length > 0) {
2016 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
2017 : (uintptr_t) kern_nanimh.descv,
2018 : kern_nanimh.desc_length * sizeof(int32_t));
2019 0 : if (kNaClBadAddress == sysaddr) {
2020 0 : retval = -NACL_ABI_EFAULT;
2021 0 : goto cleanup_leave;
2022 : }
2023 0 : kern_descv = (int32_t volatile *) sysaddr;
2024 : } else {
2025 : /* ensure we will SEGV if there's a bug below */
2026 0 : kern_descv = (int32_t volatile *) NULL;
2027 : }
2028 :
2029 0 : ndp = NaClGetDesc(natp->nap, d);
2030 0 : if (NULL == ndp) {
2031 0 : NaClLog(4, "receiving descriptor invalid\n");
2032 0 : retval = -NACL_ABI_EBADF;
2033 0 : goto cleanup_leave;
2034 : }
2035 :
2036 0 : recv_hdr.iov = kern_iov;
2037 0 : recv_hdr.iov_length = kern_nanimh.iov_length;
2038 :
2039 0 : recv_hdr.ndescv = new_desc;
2040 0 : recv_hdr.ndesc_length = NACL_ARRAY_SIZE(new_desc);
2041 0 : memset(new_desc, 0, sizeof new_desc);
2042 :
2043 0 : recv_hdr.flags = 0; /* just to make it obvious; IMC will clear it for us */
2044 :
2045 0 : ssize_retval = NaClImcRecvTypedMessage(ndp, &recv_hdr, flags,
2046 : (struct NaClDescQuotaInterface *) natp->nap->reverse_quota_interface);
2047 : /*
2048 : * retval is number of user payload bytes received and excludes the
2049 : * header bytes.
2050 : */
2051 0 : NaClLog(3, "NaClCommonSysImc_RecvMsg: "
2052 : "NaClImcRecvTypedMessage returned %"NACL_PRIdS"\n",
2053 : ssize_retval);
2054 0 : if (NaClSSizeIsNegErrno(&ssize_retval)) {
2055 : /* negative error numbers all have valid 32-bit representations,
2056 : * so this cast is safe. */
2057 0 : retval = (int32_t) ssize_retval;
2058 0 : goto cleanup;
2059 : } else if (ssize_retval > INT32_MAX || ssize_retval < INT32_MIN) {
2060 : retval = -NACL_ABI_EOVERFLOW;
2061 : goto cleanup;
2062 : } else {
2063 : /* cast is safe due to range check above */
2064 0 : retval = (int32_t) ssize_retval;
2065 : }
2066 :
2067 : /*
2068 : * NB: recv_hdr.flags may contain NACL_ABI_MESSAGE_TRUNCATED and/or
2069 : * NACL_ABI_HANDLES_TRUNCATED.
2070 : */
2071 :
2072 0 : kern_nanimh.flags = recv_hdr.flags;
2073 :
2074 : /*
2075 : * Now internalize the NaClHandles as NaClDesc objects.
2076 : */
2077 0 : num_user_desc = recv_hdr.ndesc_length;
2078 :
2079 0 : if (kern_nanimh.desc_length < num_user_desc) {
2080 0 : kern_nanimh.flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
2081 0 : for (i = kern_nanimh.desc_length; i < num_user_desc; ++i) {
2082 0 : NaClDescUnref(new_desc[i]);
2083 0 : new_desc[i] = NULL;
2084 : }
2085 0 : num_user_desc = kern_nanimh.desc_length;
2086 : }
2087 :
2088 0 : invalid_desc = (struct NaClDesc *) NaClDescInvalidMake();
2089 0 : for (i = 0; i < num_user_desc; ++i) {
2090 : /* write out to user space the descriptor numbers */
2091 0 : if (invalid_desc == new_desc[i]) {
2092 0 : kern_descv[i] = kKnownInvalidDescNumber;
2093 : } else {
2094 0 : kern_descv[i] = NaClSetAvail(natp->nap, new_desc[i]);
2095 : }
2096 0 : new_desc[i] = NULL;
2097 : }
2098 :
2099 0 : kern_nanimh.desc_length = num_user_desc;
2100 0 : *kern_nanimhp = kern_nanimh;
2101 : /* copy out updated desc count, flags */
2102 0 : cleanup:
2103 0 : if (retval < 0) {
2104 0 : for (i = 0; i < NACL_ARRAY_SIZE(new_desc); ++i) {
2105 0 : if (NULL != new_desc[i]) {
2106 0 : NaClDescUnref(new_desc[i]);
2107 0 : new_desc[i] = NULL;
2108 : }
2109 : }
2110 : }
2111 0 : NaClDescUnref(ndp);
2112 0 : NaClDescSafeUnref(invalid_desc);
2113 0 : NaClLog(3, "NaClCommonSysImc_RecvMsg: returning %d\n", retval);
2114 0 : cleanup_leave:
2115 0 : NaClSysCommonThreadSyscallLeave(natp);
2116 0 : return retval;
2117 : }
2118 :
2119 : int32_t NaClCommonSysImc_Mem_Obj_Create(struct NaClAppThread *natp,
2120 0 : size_t size) {
2121 0 : int32_t retval = -NACL_ABI_EINVAL;
2122 : struct NaClDescImcShm *shmp;
2123 : off_t size_as_off;
2124 :
2125 0 : NaClLog(3,
2126 : ("Entered NaClCommonSysImc_Mem_Obj_Create(0x%08"NACL_PRIxPTR
2127 : " 0x%08"NACL_PRIxS")\n"),
2128 : (uintptr_t) natp, size);
2129 :
2130 0 : if (0 != (size & (NACL_MAP_PAGESIZE - 1))) {
2131 0 : return -NACL_ABI_EINVAL;
2132 : }
2133 : /*
2134 : * TODO(bsy): policy about maximum shm object size should be
2135 : * enforced here.
2136 : */
2137 0 : size_as_off = (off_t) size;
2138 0 : if (size_as_off < 0) {
2139 0 : return -NACL_ABI_EINVAL;
2140 : }
2141 :
2142 0 : shmp = NULL;
2143 :
2144 0 : NaClSysCommonThreadSyscallEnter(natp);
2145 :
2146 0 : shmp = malloc(sizeof *shmp);
2147 0 : if (NULL == shmp) {
2148 0 : retval = -NACL_ABI_ENOMEM;
2149 0 : goto cleanup;
2150 : }
2151 :
2152 0 : if (!NaClDescImcShmAllocCtor(shmp, size_as_off, /* executable= */ 0)) {
2153 0 : retval = -NACL_ABI_ENOMEM; /* is this reasonable? */
2154 0 : goto cleanup;
2155 : }
2156 :
2157 0 : retval = NaClSetAvail(natp->nap, (struct NaClDesc *) shmp);
2158 0 : shmp = NULL;
2159 :
2160 0 : cleanup:
2161 0 : free(shmp);
2162 :
2163 0 : NaClSysCommonThreadSyscallLeave(natp);
2164 :
2165 0 : return retval;
2166 : }
2167 :
2168 : int32_t NaClCommonSysImc_SocketPair(struct NaClAppThread *natp,
2169 0 : uint32_t descs_out) {
2170 : uintptr_t sysaddr;
2171 : volatile int32_t *descs_out_trusted;
2172 : struct NaClDesc *pair[2];
2173 : int32_t retval;
2174 :
2175 0 : NaClLog(3,
2176 : ("Entered NaClCommonSysImc_SocketPair(0x%08"NACL_PRIxPTR
2177 : " 0x%08"NACL_PRIx32")\n"),
2178 : (uintptr_t) natp, descs_out);
2179 :
2180 0 : NaClSysCommonThreadSyscallEnter(natp);
2181 :
2182 0 : sysaddr = NaClUserToSysAddrRange(natp->nap, descs_out,
2183 : 2 * sizeof(*descs_out_trusted));
2184 0 : if (kNaClBadAddress == sysaddr) {
2185 0 : NaClLog(1,
2186 : ("NaClCommonSysImc_Socket_Pair: bad output descriptor array "
2187 : " (0x%08"NACL_PRIx32")\n"),
2188 : descs_out);
2189 0 : retval = -NACL_ABI_EFAULT;
2190 0 : goto cleanup;
2191 : }
2192 0 : descs_out_trusted = (volatile int32_t *) sysaddr;
2193 :
2194 0 : retval = NaClCommonDescSocketPair(pair);
2195 0 : if (0 != retval) {
2196 0 : goto cleanup;
2197 : }
2198 :
2199 0 : descs_out_trusted[0] = NaClSetAvail(natp->nap, pair[0]);
2200 0 : descs_out_trusted[1] = NaClSetAvail(natp->nap, pair[1]);
2201 :
2202 0 : retval = 0;
2203 0 : cleanup:
2204 0 : NaClSysCommonThreadSyscallLeave(natp);
2205 0 : return retval;
2206 : }
2207 :
2208 : int32_t NaClCommonSysTls_Init(struct NaClAppThread *natp,
2209 3 : void *thread_ptr) {
2210 3 : int32_t retval = -NACL_ABI_EINVAL;
2211 : uintptr_t sys_tls;
2212 :
2213 3 : NaClLog(3,
2214 : ("Entered NaClCommonSysTls_Init(0x%08"NACL_PRIxPTR
2215 : ", 0x%08"NACL_PRIxPTR")\n"),
2216 : (uintptr_t) natp, (uintptr_t) thread_ptr);
2217 :
2218 3 : NaClSysCommonThreadSyscallEnter(natp);
2219 :
2220 : /* Verify that the address in the app's range and translated from
2221 : * nacl module address to service runtime address - a nop on ARM
2222 : */
2223 3 : sys_tls = NaClUserToSysAddrRange(natp->nap, (uintptr_t) thread_ptr, 4);
2224 3 : NaClLog(4,
2225 : "NaClCommonSysTls_Init: thread_ptr 0x%p, sys_tls 0x%"NACL_PRIxPTR"\n",
2226 : thread_ptr, sys_tls);
2227 3 : if (kNaClBadAddress == sys_tls) {
2228 0 : retval = -NACL_ABI_EFAULT;
2229 0 : goto cleanup;
2230 : }
2231 :
2232 3 : if (0 == NaClTlsChange(natp, (void *) sys_tls)) {
2233 0 : retval = -NACL_ABI_EINVAL;
2234 0 : goto cleanup;
2235 : }
2236 3 : natp->sys_tls = sys_tls;
2237 3 : *natp->usr_tlsp = (uint32_t) (uintptr_t) thread_ptr;
2238 3 : retval = 0;
2239 3 : cleanup:
2240 3 : NaClSysCommonThreadSyscallLeave(natp);
2241 3 : return retval;
2242 : }
2243 :
2244 : int32_t NaClCommonSysThread_Create(struct NaClAppThread *natp,
2245 : void *prog_ctr,
2246 : void *stack_ptr,
2247 : void *thread_ptr,
2248 0 : void *second_thread_ptr) {
2249 0 : int32_t retval = -NACL_ABI_EINVAL;
2250 : uintptr_t sys_tls;
2251 : uintptr_t sys_stack;
2252 :
2253 0 : NaClLog(3,
2254 : ("Entered NaClCommonSysThread_Create(0x%08"NACL_PRIxPTR
2255 : " pc=0x%08"NACL_PRIxPTR", sp=0x%08"NACL_PRIxPTR", thread_ptr=0x%08"
2256 : NACL_PRIxPTR")\n"),
2257 : (uintptr_t) natp, (uintptr_t) prog_ctr, (uintptr_t) stack_ptr,
2258 : (uintptr_t) thread_ptr);
2259 :
2260 0 : NaClSysCommonThreadSyscallEnter(natp);
2261 :
2262 : /* make sure that the thread start function is in the text region */
2263 0 : if ((uintptr_t) prog_ctr >= natp->nap->dynamic_text_end) {
2264 0 : NaClLog(LOG_ERROR, "bad pc start\n");
2265 0 : retval = -NACL_ABI_EFAULT;
2266 0 : goto cleanup;
2267 : }
2268 : /* make sure that the thread start function is aligned */
2269 : /* TODO(robertm): there should be a function for this test */
2270 :
2271 : #if 0 == NACL_DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX
2272 0 : if (0 != ((natp->nap->bundle_size - 1) & (uintptr_t) prog_ctr)) {
2273 0 : NaClLog(LOG_ERROR, "bad pc alignment\n");
2274 0 : retval = -NACL_ABI_EINVAL;
2275 0 : goto cleanup;
2276 : }
2277 : #endif
2278 : /* we do not enforce stack alignment, just check for validity */
2279 0 : sys_stack = NaClUserToSysAddr(natp->nap, (uintptr_t) stack_ptr);
2280 0 : if (kNaClBadAddress == sys_stack) {
2281 0 : NaClLog(LOG_ERROR, "bad stack\n");
2282 0 : retval = -NACL_ABI_EFAULT;
2283 0 : goto cleanup;
2284 : }
2285 0 : sys_tls = NaClUserToSysAddrRange(natp->nap, (uintptr_t) thread_ptr, 4);
2286 0 : if (kNaClBadAddress == sys_tls) {
2287 0 : NaClLog(LOG_ERROR, "bad TLS pointer\n");
2288 0 : retval = -NACL_ABI_EFAULT;
2289 0 : goto cleanup;
2290 : }
2291 :
2292 0 : NaClVmHoleWaitToStartThread(natp->nap);
2293 :
2294 0 : retval = NaClCreateAdditionalThread(natp->nap,
2295 : (uintptr_t) prog_ctr,
2296 : sys_stack,
2297 : sys_tls,
2298 : (uint32_t) (uintptr_t) second_thread_ptr);
2299 :
2300 0 : cleanup:
2301 0 : NaClSysCommonThreadSyscallLeave(natp);
2302 0 : return retval;
2303 : }
2304 :
2305 : /*
2306 : * This is not used on x86-64 and its functionality is replaced by
2307 : * NaClGetTlsFastPath (see nacl_syscall_64.S).
2308 : */
2309 310 : int32_t NaClCommonSysTlsGet(struct NaClAppThread *natp) {
2310 : uint32_t user_tls;
2311 :
2312 : /* too frequently used, and syscall-number level logging suffices */
2313 310 : user_tls = (int32_t) NaClSysToUser(natp->nap, natp->sys_tls);
2314 310 : return user_tls;
2315 : }
2316 :
2317 : int32_t NaClSysSecond_Tls_Set(struct NaClAppThread *natp,
2318 0 : uint32_t new_value) {
2319 0 : natp->tls2 = new_value;
2320 0 : return 0;
2321 : }
2322 :
2323 0 : int32_t NaClSysSecond_Tls_Get(struct NaClAppThread *natp) {
2324 0 : return natp->tls2;
2325 : }
2326 :
2327 : int NaClCommonSysThread_Nice(struct NaClAppThread *natp,
2328 0 : const int nice) {
2329 : /* Note: implementation of nacl_thread_nice is OS dependent. */
2330 : UNREFERENCED_PARAMETER(natp);
2331 0 : return nacl_thread_nice(nice);
2332 : }
2333 :
2334 0 : int32_t NaClCommonSysMutex_Create(struct NaClAppThread *natp) {
2335 0 : int32_t retval = -NACL_ABI_EINVAL;
2336 : struct NaClDescMutex *desc;
2337 :
2338 0 : NaClLog(3,
2339 : ("Entered NaClCommonSysMutex_Create(0x%08"NACL_PRIxPTR")\n"),
2340 : (uintptr_t) natp);
2341 :
2342 0 : NaClSysCommonThreadSyscallEnter(natp);
2343 :
2344 0 : desc = malloc(sizeof(*desc));
2345 :
2346 0 : if (!desc || !NaClDescMutexCtor(desc)) {
2347 0 : retval = -NACL_ABI_ENOMEM;
2348 0 : goto cleanup;
2349 : }
2350 :
2351 0 : retval = NaClSetAvail(natp->nap, (struct NaClDesc *) desc);
2352 0 : desc = NULL;
2353 0 : cleanup:
2354 0 : free(desc);
2355 0 : NaClSysCommonThreadSyscallLeave(natp);
2356 0 : NaClLog(3,
2357 : ("NaClCommonSysMutex_Create(0x%08"NACL_PRIxPTR") = %d\n"),
2358 : (uintptr_t) natp, retval);
2359 0 : return retval;
2360 : }
2361 :
2362 : int32_t NaClCommonSysMutex_Lock(struct NaClAppThread *natp,
2363 0 : int32_t mutex_handle) {
2364 0 : int32_t retval = -NACL_ABI_EINVAL;
2365 : struct NaClDesc *desc;
2366 :
2367 0 : NaClLog(3,
2368 : ("Entered NaClCommonSysMutex_Lock(0x%08"NACL_PRIxPTR", %d)\n"),
2369 : (uintptr_t) natp, mutex_handle);
2370 :
2371 0 : NaClSysCommonThreadSyscallEnter(natp);
2372 :
2373 0 : desc = NaClGetDesc(natp->nap, mutex_handle);
2374 :
2375 0 : if (NULL == desc) {
2376 0 : retval = -NACL_ABI_EBADF;
2377 0 : goto cleanup;
2378 : }
2379 :
2380 0 : retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Lock)(desc);
2381 0 : NaClDescUnref(desc);
2382 :
2383 0 : cleanup:
2384 0 : NaClSysCommonThreadSyscallLeave(natp);
2385 0 : return retval;
2386 : }
2387 :
2388 : int32_t NaClCommonSysMutex_Unlock(struct NaClAppThread *natp,
2389 0 : int32_t mutex_handle) {
2390 0 : int32_t retval = -NACL_ABI_EINVAL;
2391 : struct NaClDesc *desc;
2392 :
2393 0 : NaClLog(3,
2394 : ("Entered NaClCommonSysMutex_Unlock(0x%08"NACL_PRIxPTR", %d)\n"),
2395 : (uintptr_t) natp, mutex_handle);
2396 :
2397 0 : NaClSysCommonThreadSyscallEnter(natp);
2398 :
2399 0 : desc = NaClGetDesc(natp->nap, mutex_handle);
2400 :
2401 0 : if (NULL == desc) {
2402 0 : retval = -NACL_ABI_EBADF;
2403 0 : goto cleanup;
2404 : }
2405 :
2406 0 : retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Unlock)(desc);
2407 0 : NaClDescUnref(desc);
2408 :
2409 0 : cleanup:
2410 0 : NaClSysCommonThreadSyscallLeave(natp);
2411 0 : return retval;
2412 : }
2413 :
2414 : int32_t NaClCommonSysMutex_Trylock(struct NaClAppThread *natp,
2415 0 : int32_t mutex_handle) {
2416 0 : int32_t retval = -NACL_ABI_EINVAL;
2417 : struct NaClDesc *desc;
2418 :
2419 0 : NaClLog(3,
2420 : ("Entered NaClCommonSysMutex_Trylock(0x%08"NACL_PRIxPTR", %d)\n"),
2421 : (uintptr_t) natp, mutex_handle);
2422 :
2423 0 : NaClSysCommonThreadSyscallEnter(natp);
2424 :
2425 0 : desc = NaClGetDesc(natp->nap, mutex_handle);
2426 :
2427 0 : if (NULL == desc) {
2428 0 : retval = -NACL_ABI_EBADF;
2429 0 : goto cleanup;
2430 : }
2431 :
2432 0 : retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->TryLock)(desc);
2433 0 : NaClDescUnref(desc);
2434 :
2435 0 : cleanup:
2436 0 : NaClSysCommonThreadSyscallLeave(natp);
2437 0 : return retval;
2438 : }
2439 :
2440 0 : int32_t NaClCommonSysCond_Create(struct NaClAppThread *natp) {
2441 0 : int32_t retval = -NACL_ABI_EINVAL;
2442 : struct NaClDescCondVar *desc;
2443 :
2444 0 : NaClLog(3,
2445 : ("Entered NaClCommonSysCond_Create(0x%08"NACL_PRIxPTR")\n"),
2446 : (uintptr_t) natp);
2447 :
2448 0 : NaClSysCommonThreadSyscallEnter(natp);
2449 :
2450 0 : desc = malloc(sizeof(*desc));
2451 :
2452 0 : if (!desc || !NaClDescCondVarCtor(desc)) {
2453 0 : retval = -NACL_ABI_ENOMEM;
2454 0 : goto cleanup;
2455 : }
2456 :
2457 0 : retval = NaClSetAvail(natp->nap, (struct NaClDesc *)desc);
2458 0 : desc = NULL;
2459 0 : cleanup:
2460 0 : free(desc);
2461 0 : NaClSysCommonThreadSyscallLeave(natp);
2462 0 : NaClLog(3,
2463 : ("NaClCommonSysCond_Create(0x%08"NACL_PRIxPTR") = %d\n"),
2464 : (uintptr_t) natp, retval);
2465 0 : return retval;
2466 : }
2467 :
2468 : int32_t NaClCommonSysCond_Wait(struct NaClAppThread *natp,
2469 : int32_t cond_handle,
2470 0 : int32_t mutex_handle) {
2471 0 : int32_t retval = -NACL_ABI_EINVAL;
2472 : struct NaClDesc *cv_desc;
2473 : struct NaClDesc *mutex_desc;
2474 :
2475 0 : NaClLog(3,
2476 : ("Entered NaClCommonSysCond_Wait(0x%08"NACL_PRIxPTR", %d, %d)\n"),
2477 : (uintptr_t) natp, cond_handle, mutex_handle);
2478 :
2479 0 : NaClSysCommonThreadSyscallEnter(natp);
2480 :
2481 0 : cv_desc = NaClGetDesc(natp->nap, cond_handle);
2482 :
2483 0 : if (NULL == cv_desc) {
2484 0 : retval = -NACL_ABI_EBADF;
2485 0 : goto cleanup;
2486 : }
2487 :
2488 0 : mutex_desc = NaClGetDesc(natp->nap, mutex_handle);
2489 0 : if (NULL == mutex_desc) {
2490 0 : NaClDescUnref(cv_desc);
2491 0 : retval = -NACL_ABI_EBADF;
2492 0 : goto cleanup;
2493 : }
2494 :
2495 0 : retval = (*((struct NaClDescVtbl const *) cv_desc->base.vtbl)->
2496 : Wait)(cv_desc, mutex_desc);
2497 0 : NaClDescUnref(cv_desc);
2498 0 : NaClDescUnref(mutex_desc);
2499 :
2500 0 : cleanup:
2501 0 : NaClSysCommonThreadSyscallLeave(natp);
2502 0 : return retval;
2503 : }
2504 :
2505 : int32_t NaClCommonSysCond_Signal(struct NaClAppThread *natp,
2506 0 : int32_t cond_handle) {
2507 0 : int32_t retval = -NACL_ABI_EINVAL;
2508 : struct NaClDesc *desc;
2509 :
2510 0 : NaClLog(3,
2511 : ("Entered NaClCommonSysCond_Signal(0x%08"NACL_PRIxPTR", %d)\n"),
2512 : (uintptr_t) natp, cond_handle);
2513 :
2514 0 : NaClSysCommonThreadSyscallEnter(natp);
2515 :
2516 0 : desc = NaClGetDesc(natp->nap, cond_handle);
2517 :
2518 0 : if (NULL == desc) {
2519 0 : retval = -NACL_ABI_EBADF;
2520 0 : goto cleanup;
2521 : }
2522 :
2523 0 : retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Signal)(desc);
2524 0 : NaClDescUnref(desc);
2525 0 : cleanup:
2526 0 : NaClSysCommonThreadSyscallLeave(natp);
2527 0 : return retval;
2528 : }
2529 :
2530 : int32_t NaClCommonSysCond_Broadcast(struct NaClAppThread *natp,
2531 0 : int32_t cond_handle) {
2532 : struct NaClDesc *desc;
2533 0 : int32_t retval = -NACL_ABI_EINVAL;
2534 :
2535 0 : NaClLog(3,
2536 : ("Entered NaClCommonSysCond_Broadcast(0x%08"NACL_PRIxPTR", %d)\n"),
2537 : (uintptr_t) natp, cond_handle);
2538 :
2539 0 : NaClSysCommonThreadSyscallEnter(natp);
2540 :
2541 0 : desc = NaClGetDesc(natp->nap, cond_handle);
2542 :
2543 0 : if (NULL == desc) {
2544 0 : retval = -NACL_ABI_EBADF;
2545 0 : goto cleanup;
2546 : }
2547 :
2548 0 : retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Broadcast)(desc);
2549 0 : NaClDescUnref(desc);
2550 :
2551 0 : cleanup:
2552 0 : NaClSysCommonThreadSyscallLeave(natp);
2553 0 : return retval;
2554 : }
2555 :
2556 : int32_t NaClCommonSysCond_Timed_Wait_Abs(struct NaClAppThread *natp,
2557 : int32_t cond_handle,
2558 : int32_t mutex_handle,
2559 0 : struct nacl_abi_timespec *ts) {
2560 0 : int32_t retval = -NACL_ABI_EINVAL;
2561 : struct NaClDesc *cv_desc;
2562 : struct NaClDesc *mutex_desc;
2563 : uintptr_t sys_ts;
2564 : struct nacl_abi_timespec trusted_ts;
2565 :
2566 0 : NaClLog(3,
2567 : ("Entered NaClCommonSysCond_Timed_Wait_Abs(0x%08"NACL_PRIxPTR
2568 : ", %d, %d, 0x%08"NACL_PRIxPTR")\n"),
2569 : (uintptr_t) natp, cond_handle, mutex_handle, (uintptr_t) ts);
2570 :
2571 0 : NaClSysCommonThreadSyscallEnter(natp);
2572 :
2573 0 : sys_ts = NaClUserToSysAddrRange(natp->nap,
2574 : (uintptr_t) ts,
2575 : sizeof(*ts));
2576 0 : if (kNaClBadAddress == sys_ts) {
2577 0 : retval = -NACL_ABI_EFAULT;
2578 0 : goto cleanup;
2579 : }
2580 : /* TODO(gregoryd): validate ts - do we have a limit for time to wait? */
2581 0 : memcpy(&trusted_ts, (void *) sys_ts, sizeof(trusted_ts));
2582 :
2583 0 : cv_desc = NaClGetDesc(natp->nap, cond_handle);
2584 0 : if (NULL == cv_desc) {
2585 0 : retval = -NACL_ABI_EBADF;
2586 0 : goto cleanup;
2587 : }
2588 :
2589 0 : mutex_desc = NaClGetDesc(natp->nap, mutex_handle);
2590 0 : if (NULL == mutex_desc) {
2591 0 : NaClDescUnref(cv_desc);
2592 0 : retval = -NACL_ABI_EBADF;
2593 0 : goto cleanup;
2594 : }
2595 :
2596 0 : retval = (*((struct NaClDescVtbl const *) cv_desc->base.vtbl)->
2597 : TimedWaitAbs)(cv_desc,
2598 : mutex_desc,
2599 : &trusted_ts);
2600 0 : NaClDescUnref(cv_desc);
2601 0 : NaClDescUnref(mutex_desc);
2602 0 : cleanup:
2603 0 : NaClSysCommonThreadSyscallLeave(natp);
2604 0 : return retval;
2605 : }
2606 :
2607 : int32_t NaClCommonSysSem_Create(struct NaClAppThread *natp,
2608 0 : int32_t init_value) {
2609 0 : int32_t retval = -NACL_ABI_EINVAL;
2610 : struct NaClDescSemaphore *desc;
2611 :
2612 0 : NaClLog(3,
2613 : ("Entered NaClCommonSysSem_Create(0x%08"NACL_PRIxPTR
2614 : ", %d)\n"),
2615 : (uintptr_t) natp, init_value);
2616 :
2617 0 : NaClSysCommonThreadSyscallEnter(natp);
2618 :
2619 0 : desc = malloc(sizeof(*desc));
2620 :
2621 0 : if (!desc || !NaClDescSemaphoreCtor(desc, init_value)) {
2622 0 : retval = -NACL_ABI_ENOMEM;
2623 0 : goto cleanup;
2624 : }
2625 :
2626 0 : retval = NaClSetAvail(natp->nap, (struct NaClDesc *) desc);
2627 0 : desc = NULL;
2628 0 : cleanup:
2629 0 : free(desc);
2630 0 : NaClSysCommonThreadSyscallLeave(natp);
2631 0 : return retval;
2632 : }
2633 :
2634 :
2635 : int32_t NaClCommonSysSem_Wait(struct NaClAppThread *natp,
2636 0 : int32_t sem_handle) {
2637 0 : int32_t retval = -NACL_ABI_EINVAL;
2638 : struct NaClDesc *desc;
2639 :
2640 0 : NaClLog(3,
2641 : ("Entered NaClCommonSysSem_Wait(0x%08"NACL_PRIxPTR
2642 : ", %d)\n"),
2643 : (uintptr_t) natp, sem_handle);
2644 :
2645 0 : NaClSysCommonThreadSyscallEnter(natp);
2646 :
2647 0 : desc = NaClGetDesc(natp->nap, sem_handle);
2648 :
2649 0 : if (NULL == desc) {
2650 0 : retval = -NACL_ABI_EBADF;
2651 0 : goto cleanup;
2652 : }
2653 :
2654 : /*
2655 : * TODO(gregoryd): we have to decide on the syscall API: do we
2656 : * switch to read/write/ioctl API or do we stay with the more
2657 : * detailed API. Anyway, using a single syscall for waiting on all
2658 : * synchronization objects makes sense.
2659 : */
2660 0 : retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->SemWait)(desc);
2661 0 : NaClDescUnref(desc);
2662 0 : cleanup:
2663 0 : NaClSysCommonThreadSyscallLeave(natp);
2664 0 : return retval;
2665 : }
2666 :
2667 : int32_t NaClCommonSysSem_Post(struct NaClAppThread *natp,
2668 0 : int32_t sem_handle) {
2669 0 : int32_t retval = -NACL_ABI_EINVAL;
2670 : struct NaClDesc *desc;
2671 :
2672 0 : NaClLog(3,
2673 : ("Entered NaClCommonSysSem_Post(0x%08"NACL_PRIxPTR
2674 : ", %d)\n"),
2675 : (uintptr_t) natp, sem_handle);
2676 :
2677 0 : NaClSysCommonThreadSyscallEnter(natp);
2678 :
2679 0 : desc = NaClGetDesc(natp->nap, sem_handle);
2680 :
2681 0 : if (NULL == desc) {
2682 0 : retval = -NACL_ABI_EBADF;
2683 0 : goto cleanup;
2684 : }
2685 :
2686 0 : retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Post)(desc);
2687 0 : NaClDescUnref(desc);
2688 0 : cleanup:
2689 0 : NaClSysCommonThreadSyscallLeave(natp);
2690 0 : return retval;
2691 : }
2692 :
2693 : int32_t NaClCommonSysSem_Get_Value(struct NaClAppThread *natp,
2694 0 : int32_t sem_handle) {
2695 0 : int32_t retval = -NACL_ABI_EINVAL;
2696 : struct NaClDesc *desc;
2697 :
2698 0 : NaClLog(3,
2699 : ("Entered NaClCommonSysSem_Get_Value(0x%08"NACL_PRIxPTR
2700 : ", %d)\n"),
2701 : (uintptr_t) natp, sem_handle);
2702 :
2703 0 : NaClSysCommonThreadSyscallEnter(natp);
2704 :
2705 0 : desc = NaClGetDesc(natp->nap, sem_handle);
2706 :
2707 0 : if (NULL == desc) {
2708 0 : retval = -NACL_ABI_EBADF;
2709 0 : goto cleanup;
2710 : }
2711 :
2712 0 : retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->GetValue)(desc);
2713 0 : NaClDescUnref(desc);
2714 0 : cleanup:
2715 0 : NaClSysCommonThreadSyscallLeave(natp);
2716 0 : return retval;
2717 : }
2718 :
2719 :
2720 : int32_t NaClCommonSysException_Handler(struct NaClAppThread *natp,
2721 : uint32_t handler_addr,
2722 0 : uint32_t old_handler) {
2723 : uintptr_t safe_old_handler;
2724 0 : if (!natp->nap->enable_exception_handling) {
2725 0 : return -NACL_ABI_ENOSYS;
2726 : }
2727 0 : if (!NaClIsValidJumpTarget(natp->nap, handler_addr)) {
2728 0 : return -NACL_ABI_EFAULT;
2729 : }
2730 0 : safe_old_handler = NaClUserToSysAddrNullOkay(natp->nap, old_handler);
2731 0 : if (kNaClBadAddress == safe_old_handler) {
2732 0 : return -NACL_ABI_EINVAL;
2733 : }
2734 0 : NaClXMutexLock(&natp->nap->exception_mu);
2735 0 : if (old_handler) {
2736 0 : *(volatile uint32_t *) safe_old_handler = natp->nap->exception_handler;
2737 : }
2738 0 : natp->nap->exception_handler = handler_addr;
2739 0 : NaClXMutexUnlock(&natp->nap->exception_mu);
2740 0 : return 0;
2741 : }
2742 :
2743 : int32_t NaClCommonSysException_Stack(struct NaClAppThread *natp,
2744 : uint32_t stack_addr,
2745 0 : uint32_t stack_size) {
2746 0 : if (!natp->nap->enable_exception_handling) {
2747 0 : return -NACL_ABI_ENOSYS;
2748 : }
2749 0 : if (kNaClBadAddress == NaClUserToSysAddrNullOkay(natp->nap,
2750 : stack_addr + stack_size)) {
2751 0 : return -NACL_ABI_EINVAL;
2752 : }
2753 0 : natp->user.exception_stack = stack_addr + stack_size;
2754 0 : return 0;
2755 : }
2756 :
2757 0 : int32_t NaClCommonSysException_Clear_Flag(struct NaClAppThread *natp) {
2758 0 : if (!natp->nap->enable_exception_handling) {
2759 0 : return -NACL_ABI_ENOSYS;
2760 : }
2761 0 : natp->user.exception_flag = 0;
2762 0 : return 0;
2763 : }
2764 :
2765 :
2766 0 : int32_t NaClCommonSysTest_InfoLeak(struct NaClAppThread *natp) {
2767 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
2768 : /*
2769 : * Put some interesting bits into the x87 and SSE registers.
2770 : */
2771 : union fxsave {
2772 : char buf[512];
2773 : struct {
2774 : uint16_t fcw;
2775 : uint16_t fsw;
2776 : uint16_t ftw;
2777 : uint16_t fop;
2778 : union {
2779 : struct {
2780 : uint64_t rip;
2781 : uint64_t rdp;
2782 : } x64;
2783 : struct {
2784 : uint32_t fpu_ip;
2785 : uint32_t cs;
2786 : uint32_t fpu_dp;
2787 : uint32_t ds;
2788 : } ia32;
2789 : } bitness;
2790 : uint32_t mxcsr;
2791 : uint32_t mxcsr_mask;
2792 : struct {
2793 : uint8_t st[10];
2794 : uint8_t reserved[6];
2795 : } st_space[8];
2796 : uint32_t xmm_space[64];
2797 : } fxsave;
2798 : };
2799 :
2800 : static const char tenbytes[10] = "SecretBits";
2801 : static const char manybytes[256] =
2802 : "Highly sensitive information must not be leaked to untrusted code!\n"
2803 : "xyzzy\nplugh\nYou are likely to be eaten by a grue.\n"
2804 : "When in the Course of human events it becomes necessary for one people"
2805 : " to dissolve the political bands which have connected them with ...\n";
2806 :
2807 : # ifdef __GNUC__
2808 : union fxsave u __attribute__((aligned(16)));
2809 : # elif NACL_WINDOWS
2810 : __declspec(align(16)) union fxsave u;
2811 : # else
2812 : # error Unsupported platform
2813 : # endif
2814 :
2815 : int i;
2816 :
2817 : # ifdef __GNUC__
2818 0 : __asm__("fxsave %0" : "=m" (u));
2819 : # elif NACL_WINDOWS
2820 : # if NACL_BUILD_SUBARCH == 64
2821 : {
2822 : void DoFxsave(union fxsave *);
2823 : DoFxsave(&u);
2824 : }
2825 : # else
2826 : __asm {
2827 : fxsave u
2828 : };
2829 : # endif
2830 : # else
2831 : # error Unsupported platform
2832 : # endif
2833 :
2834 0 : for (i = 0; i < 8; ++i)
2835 0 : memcpy(&u.fxsave.st_space[i], tenbytes, sizeof(tenbytes));
2836 :
2837 0 : memcpy(u.fxsave.xmm_space, manybytes, sizeof(u.fxsave.xmm_space));
2838 :
2839 : # ifdef __GNUC__
2840 0 : __asm__ volatile("fxrstor %0" :: "m" (u));
2841 : # elif NACL_WINDOWS
2842 : # if NACL_BUILD_SUBARCH == 64
2843 : {
2844 : void DoFxrstor(union fxsave *);
2845 : DoFxrstor(&u);
2846 : }
2847 : # else
2848 : __asm {
2849 : fxrstor u
2850 : };
2851 : # endif
2852 : # else
2853 : # error Unsupported platform
2854 : # endif
2855 :
2856 : #endif
2857 :
2858 : UNREFERENCED_PARAMETER(natp);
2859 :
2860 0 : return -NACL_ABI_ENOSYS;
2861 : }
2862 :
2863 0 : static int NaClIsValidClockId(int clk_id) {
2864 0 : switch (clk_id) {
2865 : case NACL_ABI_CLOCK_REALTIME:
2866 : case NACL_ABI_CLOCK_MONOTONIC:
2867 : case NACL_ABI_CLOCK_PROCESS_CPUTIME_ID:
2868 : case NACL_ABI_CLOCK_THREAD_CPUTIME_ID:
2869 0 : return 1;
2870 : }
2871 0 : return 0;
2872 : }
2873 :
2874 : int32_t NaClCommonSysClockGetCommon(struct NaClAppThread *natp,
2875 : int clk_id,
2876 : uint32_t ts_addr,
2877 : int (*timefunc)(
2878 : nacl_clockid_t clk_id,
2879 0 : struct nacl_abi_timespec *tp)) {
2880 0 : int retval = -NACL_ABI_EINVAL;
2881 : uintptr_t sysaddr;
2882 : struct nacl_abi_timespec out_buf;
2883 :
2884 0 : NaClSysCommonThreadSyscallEnter(natp);
2885 0 : if (!NaClIsValidClockId(clk_id)) {
2886 0 : goto done;
2887 : }
2888 0 : sysaddr = NaClUserToSysAddrRange(natp->nap,
2889 : (uintptr_t) ts_addr, sizeof(out_buf));
2890 0 : if (kNaClBadAddress == sysaddr) {
2891 0 : NaClLog(1,
2892 : ("NaClSysCommonSysClockGetCommon: bad timespec address "
2893 : " (0x%08"NACL_PRIx32")\n"),
2894 : ts_addr);
2895 0 : retval = -NACL_ABI_EFAULT;
2896 0 : goto done;
2897 : }
2898 0 : retval = (*timefunc)((nacl_clockid_t) clk_id, &out_buf);
2899 0 : if (0 == retval) {
2900 0 : *(struct nacl_abi_timespec volatile *) sysaddr = out_buf;
2901 : }
2902 0 : done:
2903 0 : return retval;
2904 : }
2905 :
2906 : int32_t NaClCommonSysClockGetRes(struct NaClAppThread *natp,
2907 : int clk_id,
2908 0 : uint32_t tsp) {
2909 0 : return NaClCommonSysClockGetCommon(natp, clk_id, (uintptr_t) tsp,
2910 : NaClClockGetRes);
2911 : }
2912 :
2913 : int32_t NaClCommonSysClockGetTime(struct NaClAppThread *natp,
2914 : int clk_id,
2915 0 : uint32_t tsp) {
2916 0 : return NaClCommonSysClockGetCommon(natp, clk_id, (uintptr_t) tsp,
2917 : NaClClockGetTime);
2918 : }
|