Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(723)

Side by Side Diff: pnacl/support/unsandboxed_irt.c

Issue 269703002: Non-SFI Mode: Add nonsfi_loader and plumbing to test it (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Review Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2013 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 #include <assert.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <limits.h>
11 #include <pthread.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 #include <sys/syscall.h>
18 #include <unistd.h>
19
20 #if defined(__linux__)
21 # include <linux/futex.h>
22 #endif
23
24 #include "native_client/src/include/elf32.h"
25 #include "native_client/src/include/elf_auxv.h"
26 #include "native_client/src/include/nacl_macros.h"
27 #include "native_client/src/trusted/service_runtime/include/machine/_types.h"
28 #include "native_client/src/trusted/service_runtime/include/sys/mman.h"
29 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
30 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
31 #include "native_client/src/trusted/service_runtime/include/sys/unistd.h"
32 #include "native_client/src/untrusted/irt/irt.h"
33 #include "native_client/src/untrusted/irt/irt_dev.h"
34
35 /*
36 * This is an implementation of NaCl's IRT interfaces that runs
37 * outside of the NaCl sandbox.
38 *
39 * This allows PNaCl to be used as a portability layer without the
40 * SFI-based sandboxing. PNaCl pexes can be translated to
41 * non-SFI-sandboxed native code and linked against this IRT
42 * implementation.
43 */
44
45
46 #if defined(__ANDROID__) && !defined(FUTEX_PRIVATE_FLAG)
47 /* Android's Linux headers currently don't define this flag. */
48 # define FUTEX_PRIVATE_FLAG 128
49 #endif
50
51 #if defined(__GLIBC__)
52 /*
53 * glibc's headers will define st_atimensec etc. fields, but only if
54 * _POSIX_SOURCE is defined, which disables many other declarations,
55 * such as nanosleep(), getpagesize(), MAP_ANON and clock_gettime().
56 */
57 # define st_atimensec st_atim.tv_nsec
58 # define st_mtimensec st_mtim.tv_nsec
59 # define st_ctimensec st_ctim.tv_nsec
60 #elif defined(__APPLE__)
61 /*
62 * Similarly, Mac OS X's headers will define st_atimensec etc. fields,
63 * but only if _POSIX_SOURCE is defined, which disables declarations
64 * such as _SC_NPROCESSORS_ONLN.
65 */
66 # define st_atimensec st_atimespec.tv_nsec
67 # define st_mtimensec st_mtimespec.tv_nsec
68 # define st_ctimensec st_ctimespec.tv_nsec
69 #endif
70
71 void _user_start(void *info);
72 void _start(void *info);
73
74 /* TODO(mseaborn): Make threads work on Mac OS X. */
75 #if defined(__APPLE__)
76 # define __thread /* nothing */
77 #endif
78 static __thread void *g_tls_value;
79
80
81 /*
82 * The IRT functions in irt.h are declared as taking "struct timespec"
83 * and "struct timeval" pointers, but these are really "struct
84 * nacl_abi_timespec" and "struct nacl_abi_timeval" pointers in this
85 * unsandboxed context.
86 *
87 * To avoid changing irt.h for now and also avoid casting function
88 * pointers, we use the same type signatures as in irt.h and do the
89 * casting here.
90 */
91 static void convert_from_nacl_timespec(struct timespec *dest,
92 const struct timespec *src_nacl) {
93 const struct nacl_abi_timespec *src =
94 (const struct nacl_abi_timespec *) src_nacl;
95 dest->tv_sec = src->tv_sec;
96 dest->tv_nsec = src->tv_nsec;
97 }
98
99 static void convert_to_nacl_timespec(struct timespec *dest_nacl,
100 const struct timespec *src) {
101 struct nacl_abi_timespec *dest = (struct nacl_abi_timespec *) dest_nacl;
102 dest->tv_sec = src->tv_sec;
103 dest->tv_nsec = src->tv_nsec;
104 }
105
106 static void convert_to_nacl_timeval(struct timeval *dest_nacl,
107 const struct timeval *src) {
108 struct nacl_abi_timeval *dest = (struct nacl_abi_timeval *) dest_nacl;
109 dest->nacl_abi_tv_sec = src->tv_sec;
110 dest->nacl_abi_tv_usec = src->tv_usec;
111 }
112
113 static void convert_to_nacl_stat(struct stat *dest_nacl,
114 const struct stat *src) {
115 struct nacl_abi_stat *dest = (struct nacl_abi_stat *) dest_nacl;
116 dest->nacl_abi_st_dev = src->st_dev;
117 dest->nacl_abi_st_ino = src->st_ino;
118 dest->nacl_abi_st_mode = src->st_mode;
119 dest->nacl_abi_st_nlink = src->st_nlink;
120 dest->nacl_abi_st_uid = src->st_uid;
121 dest->nacl_abi_st_gid = src->st_gid;
122 dest->nacl_abi_st_rdev = src->st_rdev;
123 dest->nacl_abi_st_size = src->st_size;
124 dest->nacl_abi_st_blksize = src->st_blksize;
125 dest->nacl_abi_st_blocks = src->st_blocks;
126 dest->nacl_abi_st_atime = src->st_atime;
127 dest->nacl_abi_st_atimensec = src->st_atimensec;
128 dest->nacl_abi_st_mtime = src->st_mtime;
129 dest->nacl_abi_st_mtimensec = src->st_mtimensec;
130 dest->nacl_abi_st_ctime = src->st_ctime;
131 dest->nacl_abi_st_ctimensec = src->st_ctimensec;
132 }
133
134 static void copy_flag(int *dest, int src, int new_flag, int old_flag) {
135 if ((src & old_flag) != 0)
136 *dest |= new_flag;
137 }
138
139 /* Returns whether the conversion was successful. */
140 static int convert_from_nacl_mmap_prot(int *prot, int prot_nacl) {
141 if ((prot_nacl & ~NACL_ABI_PROT_MASK) != 0)
142 return 0;
143 *prot = 0;
144 copy_flag(prot, prot_nacl, PROT_READ, NACL_ABI_PROT_READ);
145 copy_flag(prot, prot_nacl, PROT_WRITE, NACL_ABI_PROT_WRITE);
146 copy_flag(prot, prot_nacl, PROT_EXEC, NACL_ABI_PROT_EXEC);
147 return 1;
148 }
149
150 /* Returns whether the conversion was successful. */
151 static int convert_from_nacl_mmap_flags(int *flags, int flags_nacl) {
152 int allowed = NACL_ABI_MAP_SHARED |
153 NACL_ABI_MAP_PRIVATE |
154 NACL_ABI_MAP_FIXED |
155 NACL_ABI_MAP_ANON;
156 if ((flags_nacl & ~allowed) != 0)
157 return 0;
158 *flags = 0;
159 copy_flag(flags, flags_nacl, MAP_SHARED, NACL_ABI_MAP_SHARED);
160 copy_flag(flags, flags_nacl, MAP_PRIVATE, NACL_ABI_MAP_PRIVATE);
161 copy_flag(flags, flags_nacl, MAP_FIXED, NACL_ABI_MAP_FIXED);
162 copy_flag(flags, flags_nacl, MAP_ANON, NACL_ABI_MAP_ANON);
163 return 1;
164 }
165
166 static int check_error(int result) {
167 if (result != 0) {
168 /*
169 * Check that we really have an error and don't indicate success
170 * mistakenly.
171 */
172 assert(errno != 0);
173 return errno;
174 }
175 return 0;
176 }
177
178 static int irt_close(int fd) {
179 return check_error(close(fd));
180 }
181
182 static int irt_dup(int fd, int *new_fd) {
183 int result = dup(fd);
184 if (result < 0)
185 return errno;
186 *new_fd = result;
187 return 0;
188 }
189
190 static int irt_dup2(int fd, int new_fd) {
191 int result = dup2(fd, new_fd);
192 if (result < 0)
193 return errno;
194 assert(result == new_fd);
195 return 0;
196 }
197
198 static int irt_read(int fd, void *buf, size_t count, size_t *nread) {
199 int result = read(fd, buf, count);
200 if (result < 0)
201 return errno;
202 *nread = result;
203 return 0;
204 }
205
206 static int irt_write(int fd, const void *buf, size_t count, size_t *nwrote) {
207 int result = write(fd, buf, count);
208 if (result < 0)
209 return errno;
210 *nwrote = result;
211 return 0;
212 }
213
214 static int irt_seek(int fd, nacl_abi_off_t offset, int whence,
215 nacl_abi_off_t *new_offset) {
216 off_t result = lseek(fd, offset, whence);
217 if (result < 0)
218 return errno;
219 *new_offset = result;
220 return 0;
221 }
222
223 static int irt_fstat(int fd, struct stat *st) {
224 /* TODO(mseaborn): Implement this and convert "struct stat". */
225 return ENOSYS;
226 }
227
228 static void irt_exit(int status) {
229 _exit(status);
230 }
231
232 static int irt_clock_func(clock_t *ticks) {
233 clock_t result = clock();
234 if (result == (clock_t) -1)
235 return errno;
236 *ticks = result;
237 return 0;
238 }
239
240 static int irt_gettod(struct timeval *time_nacl) {
241 struct timeval time;
242 int result = check_error(gettimeofday(&time, NULL));
243 convert_to_nacl_timeval(time_nacl, &time);
244 return result;
245 }
246
247 static int irt_sched_yield(void) {
248 return check_error(sched_yield());
249 }
250
251 static int irt_nanosleep(const struct timespec *requested_nacl,
252 struct timespec *remaining_nacl) {
253 struct timespec requested;
254 struct timespec remaining;
255 convert_from_nacl_timespec(&requested, requested_nacl);
256 int result = check_error(nanosleep(&requested, &remaining));
257 if (remaining_nacl != NULL)
258 convert_to_nacl_timespec(remaining_nacl, &remaining);
259 return result;
260 }
261
262 static int irt_sysconf(int name, int *value) {
263 switch (name) {
264 case NACL_ABI__SC_PAGESIZE:
265 /*
266 * For now, return the host's page size (typically 4k) rather
267 * than 64k (NaCl's usual page size), which pexes will usually
268 * be tested with. We could change this to 64k, but then the
269 * mmap() we define here should round up requested sizes to
270 * multiples of 64k.
271 */
272 *value = getpagesize();
273 return 0;
274 case NACL_ABI__SC_NPROCESSORS_ONLN: {
275 int result = sysconf(_SC_NPROCESSORS_ONLN);
276 if (result == 0)
277 return errno;
278 *value = result;
279 return 0;
280 }
281 default:
282 return EINVAL;
283 }
284 }
285
286 static int irt_mmap(void **addr, size_t len, int prot, int flags,
287 int fd, nacl_irt_off_t off) {
288 int host_prot;
289 int host_flags;
290 if (!convert_from_nacl_mmap_prot(&host_prot, prot) ||
291 !convert_from_nacl_mmap_flags(&host_flags, flags)) {
292 return EINVAL;
293 }
294 void *result = mmap(*addr, len, host_prot, host_flags, fd, off);
295 if (result == MAP_FAILED)
296 return errno;
297 *addr = result;
298 return 0;
299 }
300
301 static int irt_munmap(void *addr, size_t len) {
302 return check_error(munmap(addr, len));
303 }
304
305 static int tls_init(void *ptr) {
306 g_tls_value = ptr;
307 return 0;
308 }
309
310 static void *tls_get(void) {
311 return g_tls_value;
312 }
313
314 void *__nacl_read_tp(void) {
315 return g_tls_value;
316 }
317
318 struct thread_args {
319 void (*start_func)(void);
320 void *thread_ptr;
321 };
322
323 static void *start_thread(void *arg) {
324 struct thread_args args = *(struct thread_args *) arg;
325 free(arg);
326 g_tls_value = args.thread_ptr;
327 args.start_func();
328 abort();
329 }
330
331 static int thread_create(void (*start_func)(void), void *stack,
332 void *thread_ptr) {
333 /*
334 * For now, we ignore the stack that user code provides and just use
335 * the stack that the host libpthread allocates.
336 */
337 pthread_attr_t attr;
338 int error = pthread_attr_init(&attr);
339 if (error != 0)
340 return error;
341 error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
342 if (error != 0)
343 return error;
344 struct thread_args *args = malloc(sizeof(struct thread_args));
345 if (args == NULL) {
346 error = ENOMEM;
347 goto cleanup;
348 }
349 args->start_func = start_func;
350 args->thread_ptr = thread_ptr;
351 pthread_t tid;
352 error = pthread_create(&tid, &attr, start_thread, args);
353 if (error != 0)
354 free(args);
355 cleanup:
356 pthread_attr_destroy(&attr);
357 return error;
358 }
359
360 static void thread_exit(int32_t *stack_flag) {
361 *stack_flag = 0; /* Indicate that the user code's stack can be freed. */
362 pthread_exit(NULL);
363 }
364
365 static int thread_nice(const int nice) {
366 return 0;
367 }
368
369 /*
370 * Mac OS X does not provide futexes or clock_gettime()/getres() natively.
371 * TODO(mseaborn): Make threads and clock_gettime() work on Mac OS X.
372 */
373 #if defined(__linux__)
374 static int futex_wait_abs(volatile int *addr, int value,
375 const struct timespec *abstime_nacl) {
376 struct timespec reltime;
377 struct timespec *reltime_ptr = NULL;
378 if (abstime_nacl != NULL) {
379 struct timespec time_now;
380 if (clock_gettime(CLOCK_REALTIME, &time_now) != 0)
381 return errno;
382
383 /* Convert the absolute time to a relative time. */
384 const struct nacl_abi_timespec *abstime =
385 (const struct nacl_abi_timespec *) abstime_nacl;
386 reltime.tv_sec = abstime->tv_sec - time_now.tv_sec;
387 reltime.tv_nsec = abstime->tv_nsec - time_now.tv_nsec;
388 if (reltime.tv_nsec < 0) {
389 reltime.tv_sec -= 1;
390 reltime.tv_nsec += 1000000000;
391 }
392 /*
393 * Linux's FUTEX_WAIT returns EINVAL if given a negative relative
394 * time. But an absolute time that's in the past is a valid
395 * argument, for which we need to return ETIMEDOUT instead.
396 */
397 if (reltime.tv_sec < 0)
398 return ETIMEDOUT;
399 reltime_ptr = &reltime;
400 }
401 return check_error(syscall(__NR_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG,
402 value, reltime_ptr, 0, 0));
403 }
404
405 static int futex_wake(volatile int *addr, int nwake, int *count) {
406 int result = syscall(__NR_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
407 nwake, 0, 0, 0);
408 if (result < 0)
409 return errno;
410 *count = result;
411 return 0;
412 }
413
414 static int irt_clock_getres(nacl_irt_clockid_t clk_id,
415 struct timespec *time_nacl) {
416 struct timespec time;
417 int result = check_error(clock_getres(clk_id, &time));
418 convert_to_nacl_timespec(time_nacl, &time);
419 return result;
420 }
421
422 static int irt_clock_gettime(nacl_irt_clockid_t clk_id,
423 struct timespec *time_nacl) {
424 struct timespec time;
425 int result = check_error(clock_gettime(clk_id, &time));
426 convert_to_nacl_timespec(time_nacl, &time);
427 return result;
428 }
429 #endif
430
431 static int irt_open(const char *pathname, int flags, mode_t mode, int *new_fd) {
432 int fd = open(pathname, flags, mode);
433 if (fd < 0)
434 return errno;
435 *new_fd = fd;
436 return 0;
437 }
438
439 static int irt_stat(const char *pathname, struct stat *stat_info_nacl) {
440 struct stat stat_info;
441 if (stat(pathname, &stat_info) != 0)
442 return errno;
443 convert_to_nacl_stat(stat_info_nacl, &stat_info);
444 return 0;
445 }
446
447 static int irt_mkdir(const char *pathname, mode_t mode) {
448 return check_error(mkdir(pathname, mode));
449 }
450
451 static int irt_rmdir(const char *pathname) {
452 return check_error(rmdir(pathname));
453 }
454
455 static int irt_chdir(const char *pathname) {
456 return check_error(chdir(pathname));
457 }
458
459 static int irt_getcwd(char *pathname, size_t len) {
460 if (getcwd(pathname, len) == NULL)
461 return errno;
462 return 0;
463 }
464
465 static int irt_unlink(const char *pathname) {
466 return check_error(unlink(pathname));
467 }
468
469 static int irt_getpid(int *pid) {
470 *pid = getpid();
471 return 0;
472 }
473
474 static void irt_stub_func(const char *name) {
475 fprintf(stderr, "Error: Unimplemented IRT function: %s\n", name);
476 abort();
477 }
478
479 #define DEFINE_STUB(name) \
480 static void irt_stub_##name() { irt_stub_func(#name); }
481 #define USE_STUB(s, name) (typeof(s.name)) irt_stub_##name
482
483 static const struct nacl_irt_basic irt_basic = {
484 irt_exit,
485 irt_gettod,
486 irt_clock_func,
487 irt_nanosleep,
488 irt_sched_yield,
489 irt_sysconf,
490 };
491
492 DEFINE_STUB(getdents)
493 static const struct nacl_irt_fdio irt_fdio = {
494 irt_close,
495 irt_dup,
496 irt_dup2,
497 irt_read,
498 irt_write,
499 irt_seek,
500 irt_fstat,
501 USE_STUB(irt_fdio, getdents),
502 };
503
504 DEFINE_STUB(mprotect)
505 static const struct nacl_irt_memory irt_memory = {
506 irt_mmap,
507 irt_munmap,
508 USE_STUB(irt_memory, mprotect),
509 };
510
511 static const struct nacl_irt_tls irt_tls = {
512 tls_init,
513 tls_get,
514 };
515
516 static const struct nacl_irt_thread irt_thread = {
517 thread_create,
518 thread_exit,
519 thread_nice,
520 };
521
522 #if defined(__linux__)
523 static const struct nacl_irt_futex irt_futex = {
524 futex_wait_abs,
525 futex_wake,
526 };
527
528 static const struct nacl_irt_clock irt_clock = {
529 irt_clock_getres,
530 irt_clock_gettime,
531 };
532 #else
533 DEFINE_STUB(futex_wait_abs)
534 DEFINE_STUB(futex_wake)
535 static const struct nacl_irt_futex irt_futex = {
536 USE_STUB(irt_futex, futex_wait_abs),
537 USE_STUB(irt_futex, futex_wake),
538 };
539 #endif
540
541 DEFINE_STUB(truncate)
542 DEFINE_STUB(lstat)
543 DEFINE_STUB(link)
544 DEFINE_STUB(rename)
545 DEFINE_STUB(symlink)
546 DEFINE_STUB(chmod)
547 DEFINE_STUB(access)
548 DEFINE_STUB(readlink)
549 DEFINE_STUB(utimes)
550 static const struct nacl_irt_dev_filename irt_dev_filename = {
551 irt_open,
552 irt_stat,
553 irt_mkdir,
554 irt_rmdir,
555 irt_chdir,
556 irt_getcwd,
557 irt_unlink,
558 USE_STUB(irt_dev_filename, truncate),
559 USE_STUB(irt_dev_filename, lstat),
560 USE_STUB(irt_dev_filename, link),
561 USE_STUB(irt_dev_filename, rename),
562 USE_STUB(irt_dev_filename, symlink),
563 USE_STUB(irt_dev_filename, chmod),
564 USE_STUB(irt_dev_filename, access),
565 USE_STUB(irt_dev_filename, readlink),
566 USE_STUB(irt_dev_filename, utimes),
567 };
568
569 static const struct nacl_irt_dev_getpid irt_dev_getpid = {
570 irt_getpid,
571 };
572
573 struct nacl_interface_table {
574 const char *name;
575 const void *table;
576 size_t size;
577 };
578
579 static const struct nacl_interface_table irt_interfaces[] = {
580 { NACL_IRT_BASIC_v0_1, &irt_basic, sizeof(irt_basic) },
581 { NACL_IRT_FDIO_v0_1, &irt_fdio, sizeof(irt_fdio) },
582 { NACL_IRT_MEMORY_v0_3, &irt_memory, sizeof(irt_memory) },
583 { NACL_IRT_TLS_v0_1, &irt_tls, sizeof(irt_tls) },
584 { NACL_IRT_THREAD_v0_1, &irt_thread, sizeof(irt_thread) },
585 { NACL_IRT_FUTEX_v0_1, &irt_futex, sizeof(irt_futex) },
586 #if defined(__linux__)
587 { NACL_IRT_CLOCK_v0_1, &irt_clock, sizeof(irt_clock) },
588 #endif
589 { NACL_IRT_DEV_FILENAME_v0_3, &irt_dev_filename, sizeof(irt_dev_filename) },
590 { NACL_IRT_DEV_GETPID_v0_1, &irt_dev_getpid, sizeof(irt_dev_getpid) },
591 };
592
593 static size_t irt_interface_query(const char *interface_ident,
594 void *table, size_t tablesize) {
595 unsigned i;
596 for (i = 0; i < NACL_ARRAY_SIZE(irt_interfaces); ++i) {
597 if (0 == strcmp(interface_ident, irt_interfaces[i].name)) {
598 const size_t size = irt_interfaces[i].size;
599 if (size <= tablesize) {
600 memcpy(table, irt_interfaces[i].table, size);
601 return size;
602 }
603 break;
604 }
605 }
606 fprintf(stderr, "Warning: unavailable IRT interface queried: %s\n",
607 interface_ident);
608 return 0;
609 }
610
611 int main(int argc, char **argv, char **environ) {
612 /* Find size of environ array. */
613 size_t env_count = 0;
614 while (environ[env_count] != NULL)
615 env_count++;
616
617 size_t count =
618 1 /* cleanup_func pointer */
619 + 2 /* envc and argc counts */
620 + argc + 1 /* argv array, with terminator */
621 + env_count + 1 /* environ array, with terminator */
622 + 4; /* auxv: 2 entries, one of them the terminator */
623 uintptr_t *data = malloc(count * sizeof(uintptr_t));
624 if (data == NULL) {
625 fprintf(stderr, "Failed to allocate argv/env/auxv array\n");
626 return 1;
627 }
628 size_t pos = 0;
629 data[pos++] = 0; /* cleanup_func pointer */
630 data[pos++] = env_count;
631 data[pos++] = argc;
632 /* Copy arrays, with terminators. */
633 size_t i;
634 for (i = 0; i < (size_t) argc; i++)
635 data[pos++] = (uintptr_t) argv[i];
636 data[pos++] = 0;
637 for (i = 0; i < env_count; i++)
638 data[pos++] = (uintptr_t) environ[i];
639 data[pos++] = 0;
640 /* auxv[0] */
641 data[pos++] = AT_SYSINFO;
642 data[pos++] = (uintptr_t) irt_interface_query;
643 /* auxv[1] */
644 data[pos++] = 0;
645 data[pos++] = 0;
646 assert(pos == count);
647
648 /*
649 * On Linux, we rename _start() to _user_start() to avoid a clash
650 * with the "_start" routine in the host toolchain. On Mac OS X,
651 * lacking objcopy, doing the symbol renaming is trickier, but also
652 * unnecessary, because the host toolchain doesn't have a "_start"
653 * routine.
654 */
655 #if defined(__APPLE__)
656 _start(data);
657 #else
658 _user_start(data);
659 #endif
660 return 1;
661 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698