| OLD | NEW |
| 1 | 1 |
| 2 #include "receive_args.h" | 2 #include "receive_args.h" |
| 3 | 3 |
| 4 #include <assert.h> | 4 #include <assert.h> |
| 5 #include <errno.h> | 5 #include <errno.h> |
| 6 #include <elf.h> |
| 6 #include <string.h> | 7 #include <string.h> |
| 7 #include <sys/mman.h> | 8 #include <sys/mman.h> |
| 8 #include <unistd.h> | 9 #include <unistd.h> |
| 10 #include <ldsodefs.h> |
| 9 | 11 |
| 10 #include <nacl_rpc.h> | 12 #include <nacl_rpc.h> |
| 13 #include <nacl_syscalls.h> |
| 11 | 14 |
| 12 | 15 |
| 13 /* We expect to receive an IMC message with the following format: | 16 /* We expect to receive an IMC message with the following format: |
| 14 | 17 |
| 15 Fixed-size header: | 18 Fixed-size header: |
| 16 | 19 |
| 17 "ARGS" (4 bytes) - message type tag | 20 "ARGS" (4 bytes) - message type tag |
| 18 argc (4 bytes, uint32_t) - number of strings in argv array | 21 argc (4 bytes, uint32_t) - number of strings in argv array |
| 19 envc (4 bytes, uint32_t) - number of strings in environment array | 22 envc (4 bytes, uint32_t) - number of strings in environment array |
| 20 | 23 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 34 */ | 37 */ |
| 35 | 38 |
| 36 struct args_message | 39 struct args_message |
| 37 { | 40 { |
| 38 char tag[4]; | 41 char tag[4]; |
| 39 uint32_t argc; | 42 uint32_t argc; |
| 40 uint32_t envc; | 43 uint32_t envc; |
| 41 char string_data[]; | 44 char string_data[]; |
| 42 }; | 45 }; |
| 43 | 46 |
| 44 struct process_args | |
| 45 { | |
| 46 int received_size; | |
| 47 struct args_message message; | |
| 48 }; | |
| 49 | |
| 50 #define MESSAGE_SIZE_MAX 0x10000 | 47 #define MESSAGE_SIZE_MAX 0x10000 |
| 51 | 48 |
| 52 | 49 |
| 53 static void fail (const char *message) | |
| 54 { | |
| 55 __write (2, message, strlen (message)); | |
| 56 _exit (127); | |
| 57 } | |
| 58 | |
| 59 /* The NaCl plugin blocks waiting for us to accept an SRPC connection. | 50 /* The NaCl plugin blocks waiting for us to accept an SRPC connection. |
| 60 If we reject the connection, the "onload" Javascript hook is not run. | 51 If we reject the connection, the "onload" Javascript hook is not run. |
| 61 See http://code.google.com/p/nativeclient/issues/detail?id=1501 | 52 See http://code.google.com/p/nativeclient/issues/detail?id=1501 |
| 62 Since it is currently not practical to link libsrpc into the dynamic | 53 Since it is currently not practical to link libsrpc into the dynamic |
| 63 linker, we have to hard-code the response. | 54 linker, we have to hard-code the response. |
| 64 TODO(mseaborn): Fix the plugin's process startup interface so that we | 55 TODO(mseaborn): Fix the plugin's process startup interface so that we |
| 65 do not have to send it the SRPC connection acceptance message below. */ | 56 do not have to send it the SRPC connection acceptance message below. */ |
| 66 static const uint8_t srpc_reply_message[] = | 57 static const uint8_t srpc_reply_message[] = |
| 67 { | 58 { |
| 68 /* struct LengthHeader[2]: */ | 59 /* struct LengthHeader[2]: */ |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 the first message. */ | 95 the first message. */ |
| 105 char buf[20]; | 96 char buf[20]; |
| 106 struct NaClImcMsgIoVec recv_iov = { buf, sizeof (buf) }; | 97 struct NaClImcMsgIoVec recv_iov = { buf, sizeof (buf) }; |
| 107 struct NaClImcMsgHdr recv_message = { &recv_iov, 1, NULL, 0, 0 }; | 98 struct NaClImcMsgHdr recv_message = { &recv_iov, 1, NULL, 0, 0 }; |
| 108 int received = imc_recvmsg (socket_fd, &recv_message, 0); | 99 int received = imc_recvmsg (socket_fd, &recv_message, 0); |
| 109 if (received < 0) | 100 if (received < 0) |
| 110 return -1; | 101 return -1; |
| 111 | 102 |
| 112 /* Send reply, listing no SRPC methods. */ | 103 /* Send reply, listing no SRPC methods. */ |
| 113 struct NaClImcMsgIoVec send_iov = { | 104 struct NaClImcMsgIoVec send_iov = { |
| 114 srpc_reply_message, | 105 (void *) srpc_reply_message, |
| 115 sizeof (srpc_reply_message) | 106 sizeof (srpc_reply_message) |
| 116 }; | 107 }; |
| 117 struct NaClImcMsgHdr send_message = { &send_iov, 1, NULL, 0, 0 }; | 108 struct NaClImcMsgHdr send_message = { &send_iov, 1, NULL, 0, 0 }; |
| 118 int sent = imc_sendmsg (socket_fd, &send_message, 0); | 109 int sent = imc_sendmsg (socket_fd, &send_message, 0); |
| 119 if (sent < 0) | 110 if (sent < 0) |
| 120 return -1; | 111 return -1; |
| 121 | 112 |
| 122 if (__close (socket_fd) < 0) | 113 if (__close (socket_fd) < 0) |
| 123 return -1; | 114 return -1; |
| 124 | 115 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 151 | 142 |
| 152 static void decode_hex (unsigned char *dest, int *dest_size, | 143 static void decode_hex (unsigned char *dest, int *dest_size, |
| 153 unsigned char *src, int src_size) | 144 unsigned char *src, int src_size) |
| 154 { | 145 { |
| 155 int i; | 146 int i; |
| 156 for (i = 0; i < src_size / 2; i++) | 147 for (i = 0; i < src_size / 2; i++) |
| 157 dest[i] = from_hex (src[i*2]) * 0x10 + from_hex (src[i*2 + 1]); | 148 dest[i] = from_hex (src[i*2]) * 0x10 + from_hex (src[i*2 + 1]); |
| 158 *dest_size = src_size / 2; | 149 *dest_size = src_size / 2; |
| 159 } | 150 } |
| 160 | 151 |
| 161 struct process_args *argmsg_fetch () | 152 uint32_t *argmsg_fetch (uint32_t *info) |
| 162 { | 153 { |
| 163 /* The NaCl browser plugin does not give us a good way to detect | 154 /* The NaCl browser plugin does not give us a good way to detect |
| 164 that we are running under it. We detect that we are running | 155 that we are running under it. We detect that we are running |
| 165 under the plugin by the presence of the file descriptor | 156 under the plugin by the presence of the file descriptor |
| 166 NACL_PLUGIN_BOUND_SOCK. | 157 NACL_PLUGIN_BOUND_SOCK. |
| 167 See http://code.google.com/p/nativeclient/issues/detail?id=889 | 158 See http://code.google.com/p/nativeclient/issues/detail?id=889 |
| 168 | 159 |
| 169 Furthermore, the NaCl plugin blocks waiting for us to accept or | 160 Furthermore, the NaCl plugin blocks waiting for us to accept or |
| 170 reject an SRPC connection. We cannot usefully accept the | 161 reject an SRPC connection. We cannot usefully accept the |
| 171 connection at this point, but we need to unblock the plugin so | 162 connection at this point, but we need to unblock the plugin so |
| (...skipping 13 matching lines...) Expand all Loading... |
| 185 TODO(pasko): eliminate testing socket numbers as part of dynamic linker | 176 TODO(pasko): eliminate testing socket numbers as part of dynamic linker |
| 186 startup. */ | 177 startup. */ |
| 187 if (socket_fd == -1 && errno == EINVAL) | 178 if (socket_fd == -1 && errno == EINVAL) |
| 188 { | 179 { |
| 189 socket_fd = imc_accept (NACL_PLUGIN_BOUND_SOCK + 4); | 180 socket_fd = imc_accept (NACL_PLUGIN_BOUND_SOCK + 4); |
| 190 } | 181 } |
| 191 if (socket_fd == -1 && errno == EBADF) | 182 if (socket_fd == -1 && errno == EBADF) |
| 192 { | 183 { |
| 193 /* We are not running under the NaCl browser plugin or in a | 184 /* We are not running under the NaCl browser plugin or in a |
| 194 similar environment. */ | 185 similar environment. */ |
| 195 return NULL; | 186 return info; |
| 196 } | 187 } |
| 197 keep_plugin_happy (socket_fd); | 188 keep_plugin_happy (socket_fd); |
| 198 struct process_args *args = | 189 |
| 199 mmap (NULL, MESSAGE_SIZE_MAX, PROT_READ | PROT_WRITE, | 190 union |
| 200 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 191 { |
| 201 if (args == MAP_FAILED) | 192 unsigned char buffer[MESSAGE_SIZE_MAX]; |
| 202 fail ("Failed to allocate memory to receive startup message\n"); | 193 struct args_message message; |
| 203 struct NaClImcMsgIoVec iov; | 194 } msgbuf; |
| 204 struct NaClImcMsgHdr message; | 195 |
| 205 iov.base = (void *) &args->message; | 196 struct NaClImcMsgIoVec iov = { .base = &msgbuf, .length = sizeof(msgbuf) }; |
| 206 iov.length = MESSAGE_SIZE_MAX - offsetof (struct process_args, message); | 197 struct NaClImcMsgHdr message = { .iov = &iov, .iov_length = 1 }; |
| 207 message.iov = &iov; | 198 |
| 208 message.iov_length = 1; | 199 int received_size = imc_recvmsg (NACL_PLUGIN_ASYNC_TO_CHILD_FD, |
| 209 message.descv = NULL; | 200 &message, 0); |
| 210 message.desc_length = 0; | |
| 211 message.flags = 0; | |
| 212 args->received_size = imc_recvmsg (NACL_PLUGIN_ASYNC_TO_CHILD_FD, | |
| 213 &message, 0); | |
| 214 | 201 |
| 215 /* As a workaround for a limitation in the NaCl plugin, allow the | 202 /* As a workaround for a limitation in the NaCl plugin, allow the |
| 216 message to be hex-encoded. This is because __sendAsyncMessage*() | 203 message to be hex-encoded. This is because __sendAsyncMessage*() |
| 217 does not support null bytes in messages. | 204 does not support null bytes in messages. |
| 218 See http://code.google.com/p/nativeclient/issues/detail?id=1535 | 205 See http://code.google.com/p/nativeclient/issues/detail?id=1535 |
| 219 TODO(mseaborn): Fix this limitation. */ | 206 TODO(mseaborn): Fix this limitation. */ |
| 220 if (args->received_size >= 4 && | 207 if (received_size >= 4 && |
| 221 memcmp (args->message.tag, "HEXD", 4) == 0) | 208 memcmp (msgbuf.message.tag, "HEXD", 4) == 0) |
| 222 decode_hex ((unsigned char *) &args->message, &args->received_size, | 209 decode_hex (msgbuf.buffer, &received_size, |
| 223 (unsigned char *) &args->message + 4, args->received_size - 4); | 210 &msgbuf.buffer[4], received_size - 4); |
| 224 | 211 |
| 225 if (args->received_size < 0) | 212 if (received_size < 0) |
| 226 fail ("Error receiving startup message\n"); | 213 _dl_fatal_printf ("Error receiving startup message (%u)\n", errno); |
| 227 if (args->received_size < 4 || | 214 if (received_size < 4 || |
| 228 memcmp (args->message.tag, "ARGS", 4) != 0) | 215 memcmp (msgbuf.message.tag, "ARGS", 4) != 0) |
| 229 fail ("Startup message does not have the expected tag\n"); | 216 _dl_fatal_printf ("Startup message (%u bytes) lacks the expected tag\n", |
| 230 if (args->received_size < offsetof (struct args_message, string_data)) | 217 received_size); |
| 231 fail ("Startup message too small\n"); | 218 if (received_size < offsetof (struct args_message, string_data)) |
| 232 /* Check for an attempt to allocate too much space on the stack. */ | 219 _dl_fatal_printf ("Startup message too small (%u bytes)\n", received_size); |
| 233 if (args->message.argc > MESSAGE_SIZE_MAX || | 220 |
| 234 args->message.envc > MESSAGE_SIZE_MAX || | 221 /* Count the original auxv size so we know how big to make the new buffer. */ |
| 235 args->message.argc + args->message.envc > MESSAGE_SIZE_MAX) | 222 size_t nauxv = 0; |
| 236 fail ("argv/env too large\n"); | 223 Elf32_auxv_t *const auxv = (void *) &info[3 + info[2] + 1 + info[1] + 1]; |
| 237 return args; | 224 Elf32_auxv_t *av = auxv; |
| 225 do |
| 226 ++nauxv; |
| 227 while (av++->a_type != AT_NULL); |
| 228 |
| 229 /* Allocate a new information block in the heap. |
| 230 We will pass this pointer to the user program rather than |
| 231 the original argument (which was a pointer onto our stack). */ |
| 232 size_t infosize = ((3 + msgbuf.message.argc + 1 + |
| 233 msgbuf.message.envc + 1) * sizeof(uint32_t) + |
| 234 nauxv * sizeof(Elf32_auxv_t) + |
| 235 (received_size - |
| 236 offsetof (struct args_message, string_data))); |
| 237 uint32_t *newinfo = __mmap (NULL, infosize, PROT_READ|PROT_WRITE, |
| 238 MAP_PRIVATE|MAP_ANON, -1, 0); |
| 239 if (newinfo == NULL) |
| 240 _dl_fatal_printf ("Cannot allocate %u bytes for startup information\n", |
| 241 infosize); |
| 242 |
| 243 /* Fill in the new information block. |
| 244 We replace the arguments and environment with what we got from IPC, |
| 245 and copy the rest from the original block. */ |
| 246 newinfo[0] = info[0]; |
| 247 newinfo[1] = msgbuf.message.envc; |
| 248 newinfo[2] = msgbuf.message.argc; |
| 249 |
| 250 /* Copy the auxiliary vector, which sits after the string vectors. */ |
| 251 char **argv = (char **) &newinfo[3]; |
| 252 char **envp = &argv[msgbuf.message.argc + 1]; |
| 253 char *copy = __mempcpy (&envp[msgbuf.message.envc + 1], |
| 254 auxv, nauxv * sizeof(auxv[0])); |
| 255 |
| 256 /* Now copy the strings into place and fill in the string vectors. */ |
| 257 const char *p = msgbuf.message.string_data; |
| 258 const char *endp = (char *) &msgbuf.buffer[received_size]; |
| 259 |
| 260 /* First, the argument vector. */ |
| 261 for (int i = 0; i < msgbuf.message.argc; ++i) |
| 262 { |
| 263 const char *elt_end = memchr (p, '\0', endp - p); |
| 264 if (elt_end == NULL) |
| 265 _dl_fatal_printf ("Unterminated argument string in startup message\n"); |
| 266 ++elt_end; |
| 267 argv[i] = copy; |
| 268 copy = __mempcpy (copy, p, elt_end - p); |
| 269 p = elt_end; |
| 270 } |
| 271 argv[msgbuf.message.argc] = NULL; |
| 272 |
| 273 /* Finally, the environment vector. */ |
| 274 for (int i = 0; i < msgbuf.message.envc; ++i) |
| 275 { |
| 276 const char *elt_end = memchr (p, '\0', endp - p); |
| 277 if (elt_end == NULL) |
| 278 _dl_fatal_printf ("\ |
| 279 Unterminated environment string in startup message\n"); |
| 280 ++elt_end; |
| 281 envp[i] = copy; |
| 282 copy = __mempcpy (copy, p, elt_end - p); |
| 283 p = elt_end; |
| 284 } |
| 285 envp[msgbuf.message.envc] = NULL; |
| 286 |
| 287 if (p != endp) |
| 288 _dl_fatal_printf ("Excess data (%u bytes) in startup message body\n", |
| 289 endp - p); |
| 290 |
| 291 return newinfo; |
| 238 } | 292 } |
| 239 | |
| 240 static size_t arrays_size (struct process_args *args) | |
| 241 { | |
| 242 return (sizeof(argc_type) + | |
| 243 sizeof(char *) * (args->message.argc + 1 + | |
| 244 args->message.envc + 1 + | |
| 245 2 /* for empty auxv */)); | |
| 246 } | |
| 247 | |
| 248 static size_t strings_size (struct process_args *args) | |
| 249 { | |
| 250 return args->received_size - offsetof (struct args_message, string_data); | |
| 251 } | |
| 252 | |
| 253 size_t argmsg_get_size_on_stack (struct process_args *args) | |
| 254 { | |
| 255 return arrays_size (args) + strings_size (args); | |
| 256 } | |
| 257 | |
| 258 void argmsg_move_to_stack (struct process_args *args, | |
| 259 void *buf, size_t buf_size) | |
| 260 { | |
| 261 char *buf_end = (char *) buf + buf_size; | |
| 262 char *strings = (char *) buf + arrays_size (args); | |
| 263 memcpy (strings, args->message.string_data, strings_size (args)); | |
| 264 | |
| 265 *(argc_type *) buf = args->message.argc; | |
| 266 char **dest = (char **) ((char *) buf + sizeof(argc_type)); | |
| 267 char *next_str = strings; | |
| 268 int i; | |
| 269 /* Set up argv array */ | |
| 270 for (i = 0; i < args->message.argc; i++) | |
| 271 { | |
| 272 *dest++ = next_str; | |
| 273 next_str = (char *) memchr (next_str, 0, buf_end - next_str); | |
| 274 if (next_str == NULL) | |
| 275 fail ("Missing null terminator in argv list\n"); | |
| 276 next_str++; | |
| 277 } | |
| 278 *dest++ = NULL; | |
| 279 /* Set up environment array */ | |
| 280 for (i = 0; i < args->message.envc; i++) | |
| 281 { | |
| 282 *dest++ = next_str; | |
| 283 next_str = (char *) memchr (next_str, 0, buf_end - next_str); | |
| 284 if (next_str == NULL) | |
| 285 fail ("Missing null terminator in env list\n"); | |
| 286 next_str++; | |
| 287 } | |
| 288 *dest++ = NULL; | |
| 289 /* Set up an empty auxv */ | |
| 290 *dest++ = NULL; | |
| 291 *dest++ = NULL; | |
| 292 if ((char *) dest != strings) | |
| 293 fail ("Internal error: mismatch in array size\n"); | |
| 294 if (next_str != buf_end) | |
| 295 fail ("Excess data in message body\n"); | |
| 296 | |
| 297 if (munmap (args, MESSAGE_SIZE_MAX) != 0) | |
| 298 fail ("Failed to munmap() startup message\n"); | |
| 299 } | |
| 300 | |
| 301 void jump_to_elf_start (void *buf, uintptr_t entry_func, uintptr_t atexit_func) | |
| 302 { | |
| 303 /* The ELF entry point ABI is such that assembly code is required to | |
| 304 call the entry point. | |
| 305 See http://code.google.com/p/nativeclient/issues/detail?id=1131 | |
| 306 TODO(mseaborn): Switch to using the normal function call ABI. */ | |
| 307 #if defined(__i386__) | |
| 308 __asm__ ("mov %0, %%esp\n" | |
| 309 "nacljmp %1\n" | |
| 310 : : "m" (buf), "r" (entry_func), | |
| 311 "d" (atexit_func) /* %edx */); | |
| 312 #elif defined(__x86_64__) | |
| 313 __asm__ ("naclrestsp %0, %%r15\n" | |
| 314 "nacljmp %1, %%r15\n" | |
| 315 : : "m" (buf), "r" (entry_func), | |
| 316 "d" (atexit_func) /* %rdx */); | |
| 317 #else | |
| 318 # error Unsupported architecture | |
| 319 #endif | |
| 320 } | |
| OLD | NEW |