OLD | NEW |
(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 <stdio.h> |
| 10 #include <stdlib.h> |
| 11 #include <string.h> |
| 12 #include <sys/mman.h> |
| 13 #include <unistd.h> |
| 14 |
| 15 #include "native_client/src/include/elf32.h" |
| 16 #include "native_client/src/include/elf_auxv.h" |
| 17 #include "native_client/src/include/nacl_macros.h" |
| 18 #include "native_client/src/trusted/service_runtime/include/sys/unistd.h" |
| 19 #include "native_client/src/untrusted/irt/irt.h" |
| 20 |
| 21 /* |
| 22 * This is an implementation of NaCl's IRT interfaces that runs |
| 23 * outside of the NaCl sandbox. |
| 24 * |
| 25 * This allows PNaCl to be used as a portability layer without the |
| 26 * SFI-based sandboxing. PNaCl pexes can be translated to |
| 27 * non-SFI-sandboxed native code and linked against this IRT |
| 28 * implementation. |
| 29 */ |
| 30 |
| 31 |
| 32 void _user_start(void *info); |
| 33 |
| 34 static __thread void *g_tls_value; |
| 35 |
| 36 |
| 37 static int irt_close(int fd) { |
| 38 if (close(fd) != 0) |
| 39 return errno; |
| 40 return 0; |
| 41 } |
| 42 |
| 43 static int irt_write(int fd, const void *buf, size_t count, size_t *nwrote) { |
| 44 int result = write(fd, buf, count); |
| 45 if (result < 0) |
| 46 return errno; |
| 47 *nwrote = result; |
| 48 return 0; |
| 49 } |
| 50 |
| 51 static int irt_fstat(int fd, struct stat *st) { |
| 52 /* TODO(mseaborn): Implement this and convert "struct stat". */ |
| 53 return ENOSYS; |
| 54 } |
| 55 |
| 56 static void irt_exit(int status) { |
| 57 _exit(status); |
| 58 } |
| 59 |
| 60 static int irt_sysconf(int name, int *value) { |
| 61 switch (name) { |
| 62 case NACL_ABI__SC_PAGESIZE: |
| 63 /* |
| 64 * For now, return the host's page size (typically 4k) rather |
| 65 * than 64k (NaCl's usual page size), which pexes will usually |
| 66 * be tested with. We could change this to 64k, but then the |
| 67 * mmap() we define here should round up requested sizes to |
| 68 * multiples of 64k. |
| 69 */ |
| 70 *value = getpagesize(); |
| 71 return 0; |
| 72 default: |
| 73 return EINVAL; |
| 74 } |
| 75 } |
| 76 |
| 77 static int irt_mmap(void **addr, size_t len, int prot, int flags, |
| 78 int fd, off_t off) { |
| 79 void *result = mmap(*addr, len, prot, flags, fd, off); |
| 80 if (result == MAP_FAILED) |
| 81 return errno; |
| 82 *addr = result; |
| 83 return 0; |
| 84 } |
| 85 |
| 86 static int tls_init(void *ptr) { |
| 87 g_tls_value = ptr; |
| 88 return 0; |
| 89 } |
| 90 |
| 91 static void *tls_get(void) { |
| 92 return g_tls_value; |
| 93 } |
| 94 |
| 95 void *__nacl_read_tp(void) { |
| 96 return g_tls_value; |
| 97 } |
| 98 |
| 99 static void irt_stub_func(const char *name) { |
| 100 fprintf(stderr, "Error: Unimplemented IRT function: %s\n", name); |
| 101 abort(); |
| 102 } |
| 103 |
| 104 #define DEFINE_STUB(name) \ |
| 105 static void irt_stub_##name() { irt_stub_func(#name); } |
| 106 #define USE_STUB(s, name) (typeof(s.name)) irt_stub_##name |
| 107 |
| 108 DEFINE_STUB(gettod) |
| 109 DEFINE_STUB(clock) |
| 110 DEFINE_STUB(nanosleep) |
| 111 DEFINE_STUB(sched_yield) |
| 112 static struct nacl_irt_basic irt_basic = { |
| 113 irt_exit, |
| 114 USE_STUB(irt_basic, gettod), |
| 115 USE_STUB(irt_basic, clock), |
| 116 USE_STUB(irt_basic, nanosleep), |
| 117 USE_STUB(irt_basic, sched_yield), |
| 118 irt_sysconf, |
| 119 }; |
| 120 |
| 121 DEFINE_STUB(dup) |
| 122 DEFINE_STUB(dup2) |
| 123 DEFINE_STUB(read) |
| 124 DEFINE_STUB(seek) |
| 125 DEFINE_STUB(getdents) |
| 126 static struct nacl_irt_fdio irt_fdio = { |
| 127 irt_close, |
| 128 USE_STUB(irt_fdio, dup), |
| 129 USE_STUB(irt_fdio, dup2), |
| 130 USE_STUB(irt_fdio, read), |
| 131 irt_write, |
| 132 USE_STUB(irt_fdio, seek), |
| 133 irt_fstat, |
| 134 USE_STUB(irt_fdio, getdents), |
| 135 }; |
| 136 |
| 137 DEFINE_STUB(munmap) |
| 138 DEFINE_STUB(mprotect) |
| 139 static struct nacl_irt_memory irt_memory = { |
| 140 irt_mmap, |
| 141 USE_STUB(irt_memory, munmap), |
| 142 USE_STUB(irt_memory, mprotect), |
| 143 }; |
| 144 |
| 145 static struct nacl_irt_tls irt_tls = { |
| 146 tls_init, |
| 147 tls_get, |
| 148 }; |
| 149 |
| 150 struct nacl_interface_table { |
| 151 const char *name; |
| 152 const void *table; |
| 153 size_t size; |
| 154 }; |
| 155 |
| 156 static const struct nacl_interface_table irt_interfaces[] = { |
| 157 { NACL_IRT_BASIC_v0_1, &irt_basic, sizeof(irt_basic) }, |
| 158 { NACL_IRT_FDIO_v0_1, &irt_fdio, sizeof(irt_fdio) }, |
| 159 { NACL_IRT_MEMORY_v0_3, &irt_memory, sizeof(irt_memory) }, |
| 160 { NACL_IRT_TLS_v0_1, &irt_tls, sizeof(irt_tls) }, |
| 161 }; |
| 162 |
| 163 static size_t irt_interface_query(const char *interface_ident, |
| 164 void *table, size_t tablesize) { |
| 165 unsigned i; |
| 166 for (i = 0; i < NACL_ARRAY_SIZE(irt_interfaces); ++i) { |
| 167 if (0 == strcmp(interface_ident, irt_interfaces[i].name)) { |
| 168 const size_t size = irt_interfaces[i].size; |
| 169 if (size <= tablesize) { |
| 170 memcpy(table, irt_interfaces[i].table, size); |
| 171 return size; |
| 172 } |
| 173 break; |
| 174 } |
| 175 } |
| 176 fprintf(stderr, "Warning: unavailable IRT interface queried: %s\n", |
| 177 interface_ident); |
| 178 return 0; |
| 179 } |
| 180 |
| 181 /* Layout for empty argv/env arrays. */ |
| 182 struct startup_info { |
| 183 void (*cleanup_func)(); |
| 184 int envc; |
| 185 int argc; |
| 186 char *argv0; |
| 187 char *envp0; |
| 188 Elf32_auxv_t auxv[2]; |
| 189 }; |
| 190 |
| 191 int main(int argc, char **argv) { |
| 192 /* TODO(mseaborn): Copy across argv and environment arrays. */ |
| 193 struct startup_info info; |
| 194 info.cleanup_func = NULL; |
| 195 info.envc = 0; |
| 196 info.argc = 0; |
| 197 info.argv0 = NULL; |
| 198 info.envp0 = NULL; |
| 199 info.auxv[0].a_type = AT_SYSINFO; |
| 200 info.auxv[0].a_un.a_val = (uintptr_t) irt_interface_query; |
| 201 info.auxv[1].a_type = 0; |
| 202 info.auxv[1].a_un.a_val = 0; |
| 203 |
| 204 _user_start(&info); |
| 205 return 1; |
| 206 } |
OLD | NEW |