| Index: sysdeps/nacl/receive_args.c
|
| diff --git a/sysdeps/nacl/receive_args.c b/sysdeps/nacl/receive_args.c
|
| index bf67f3f76f3d7a386713fab8a0da1c58be865d7f..995eea2f1b43bc16d3204921420be3185e25aaed 100644
|
| --- a/sysdeps/nacl/receive_args.c
|
| +++ b/sysdeps/nacl/receive_args.c
|
| @@ -3,11 +3,14 @@
|
|
|
| #include <assert.h>
|
| #include <errno.h>
|
| +#include <elf.h>
|
| #include <string.h>
|
| #include <sys/mman.h>
|
| #include <unistd.h>
|
| +#include <ldsodefs.h>
|
|
|
| #include <nacl_rpc.h>
|
| +#include <nacl_syscalls.h>
|
|
|
|
|
| /* We expect to receive an IMC message with the following format:
|
| @@ -41,21 +44,9 @@ struct args_message
|
| char string_data[];
|
| };
|
|
|
| -struct process_args
|
| -{
|
| - int received_size;
|
| - struct args_message message;
|
| -};
|
| -
|
| #define MESSAGE_SIZE_MAX 0x10000
|
|
|
|
|
| -static void fail (const char *message)
|
| -{
|
| - __write (2, message, strlen (message));
|
| - _exit (127);
|
| -}
|
| -
|
| /* The NaCl plugin blocks waiting for us to accept an SRPC connection.
|
| If we reject the connection, the "onload" Javascript hook is not run.
|
| See http://code.google.com/p/nativeclient/issues/detail?id=1501
|
| @@ -111,7 +102,7 @@ static int keep_plugin_happy (int socket_fd)
|
|
|
| /* Send reply, listing no SRPC methods. */
|
| struct NaClImcMsgIoVec send_iov = {
|
| - srpc_reply_message,
|
| + (void *) srpc_reply_message,
|
| sizeof (srpc_reply_message)
|
| };
|
| struct NaClImcMsgHdr send_message = { &send_iov, 1, NULL, 0, 0 };
|
| @@ -158,7 +149,7 @@ static void decode_hex (unsigned char *dest, int *dest_size,
|
| *dest_size = src_size / 2;
|
| }
|
|
|
| -struct process_args *argmsg_fetch ()
|
| +uint32_t *argmsg_fetch (uint32_t *info)
|
| {
|
| /* The NaCl browser plugin does not give us a good way to detect
|
| that we are running under it. We detect that we are running
|
| @@ -192,129 +183,110 @@ struct process_args *argmsg_fetch ()
|
| {
|
| /* We are not running under the NaCl browser plugin or in a
|
| similar environment. */
|
| - return NULL;
|
| + return info;
|
| }
|
| keep_plugin_happy (socket_fd);
|
| - struct process_args *args =
|
| - mmap (NULL, MESSAGE_SIZE_MAX, PROT_READ | PROT_WRITE,
|
| - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
| - if (args == MAP_FAILED)
|
| - fail ("Failed to allocate memory to receive startup message\n");
|
| - struct NaClImcMsgIoVec iov;
|
| - struct NaClImcMsgHdr message;
|
| - iov.base = (void *) &args->message;
|
| - iov.length = MESSAGE_SIZE_MAX - offsetof (struct process_args, message);
|
| - message.iov = &iov;
|
| - message.iov_length = 1;
|
| - message.descv = NULL;
|
| - message.desc_length = 0;
|
| - message.flags = 0;
|
| - args->received_size = imc_recvmsg (NACL_PLUGIN_ASYNC_TO_CHILD_FD,
|
| - &message, 0);
|
| +
|
| + union
|
| + {
|
| + unsigned char buffer[MESSAGE_SIZE_MAX];
|
| + struct args_message message;
|
| + } msgbuf;
|
| +
|
| + struct NaClImcMsgIoVec iov = { .base = &msgbuf, .length = sizeof(msgbuf) };
|
| + struct NaClImcMsgHdr message = { .iov = &iov, .iov_length = 1 };
|
| +
|
| + int received_size = imc_recvmsg (NACL_PLUGIN_ASYNC_TO_CHILD_FD,
|
| + &message, 0);
|
|
|
| /* As a workaround for a limitation in the NaCl plugin, allow the
|
| message to be hex-encoded. This is because __sendAsyncMessage*()
|
| does not support null bytes in messages.
|
| See http://code.google.com/p/nativeclient/issues/detail?id=1535
|
| TODO(mseaborn): Fix this limitation. */
|
| - if (args->received_size >= 4 &&
|
| - memcmp (args->message.tag, "HEXD", 4) == 0)
|
| - decode_hex ((unsigned char *) &args->message, &args->received_size,
|
| - (unsigned char *) &args->message + 4, args->received_size - 4);
|
| -
|
| - if (args->received_size < 0)
|
| - fail ("Error receiving startup message\n");
|
| - if (args->received_size < 4 ||
|
| - memcmp (args->message.tag, "ARGS", 4) != 0)
|
| - fail ("Startup message does not have the expected tag\n");
|
| - if (args->received_size < offsetof (struct args_message, string_data))
|
| - fail ("Startup message too small\n");
|
| - /* Check for an attempt to allocate too much space on the stack. */
|
| - if (args->message.argc > MESSAGE_SIZE_MAX ||
|
| - args->message.envc > MESSAGE_SIZE_MAX ||
|
| - args->message.argc + args->message.envc > MESSAGE_SIZE_MAX)
|
| - fail ("argv/env too large\n");
|
| - return args;
|
| -}
|
| -
|
| -static size_t arrays_size (struct process_args *args)
|
| -{
|
| - return (sizeof(argc_type) +
|
| - sizeof(char *) * (args->message.argc + 1 +
|
| - args->message.envc + 1 +
|
| - 2 /* for empty auxv */));
|
| -}
|
| -
|
| -static size_t strings_size (struct process_args *args)
|
| -{
|
| - return args->received_size - offsetof (struct args_message, string_data);
|
| -}
|
| -
|
| -size_t argmsg_get_size_on_stack (struct process_args *args)
|
| -{
|
| - return arrays_size (args) + strings_size (args);
|
| -}
|
| -
|
| -void argmsg_move_to_stack (struct process_args *args,
|
| - void *buf, size_t buf_size)
|
| -{
|
| - char *buf_end = (char *) buf + buf_size;
|
| - char *strings = (char *) buf + arrays_size (args);
|
| - memcpy (strings, args->message.string_data, strings_size (args));
|
| -
|
| - *(argc_type *) buf = args->message.argc;
|
| - char **dest = (char **) ((char *) buf + sizeof(argc_type));
|
| - char *next_str = strings;
|
| - int i;
|
| - /* Set up argv array */
|
| - for (i = 0; i < args->message.argc; i++)
|
| + if (received_size >= 4 &&
|
| + memcmp (msgbuf.message.tag, "HEXD", 4) == 0)
|
| + decode_hex (msgbuf.buffer, &received_size,
|
| + &msgbuf.buffer[4], received_size - 4);
|
| +
|
| + if (received_size < 0)
|
| + _dl_fatal_printf ("Error receiving startup message (%u)\n", errno);
|
| + if (received_size < 4 ||
|
| + memcmp (msgbuf.message.tag, "ARGS", 4) != 0)
|
| + _dl_fatal_printf ("Startup message (%u bytes) lacks the expected tag\n",
|
| + received_size);
|
| + if (received_size < offsetof (struct args_message, string_data))
|
| + _dl_fatal_printf ("Startup message too small (%u bytes)\n", received_size);
|
| +
|
| + /* Count the original auxv size so we know how big to make the new buffer. */
|
| + size_t nauxv = 0;
|
| + Elf32_auxv_t *const auxv = (void *) &info[3 + info[2] + 1 + info[1] + 1];
|
| + Elf32_auxv_t *av = auxv;
|
| + do
|
| + ++nauxv;
|
| + while (av++->a_type != AT_NULL);
|
| +
|
| + /* Allocate a new information block in the heap.
|
| + We will pass this pointer to the user program rather than
|
| + the original argument (which was a pointer onto our stack). */
|
| + size_t infosize = ((3 + msgbuf.message.argc + 1 +
|
| + msgbuf.message.envc + 1) * sizeof(uint32_t) +
|
| + nauxv * sizeof(Elf32_auxv_t) +
|
| + (received_size -
|
| + offsetof (struct args_message, string_data)));
|
| + uint32_t *newinfo = __mmap (NULL, infosize, PROT_READ|PROT_WRITE,
|
| + MAP_PRIVATE|MAP_ANON, -1, 0);
|
| + if (newinfo == NULL)
|
| + _dl_fatal_printf ("Cannot allocate %u bytes for startup information\n",
|
| + infosize);
|
| +
|
| + /* Fill in the new information block.
|
| + We replace the arguments and environment with what we got from IPC,
|
| + and copy the rest from the original block. */
|
| + newinfo[0] = info[0];
|
| + newinfo[1] = msgbuf.message.envc;
|
| + newinfo[2] = msgbuf.message.argc;
|
| +
|
| + /* Copy the auxiliary vector, which sits after the string vectors. */
|
| + char **argv = (char **) &newinfo[3];
|
| + char **envp = &argv[msgbuf.message.argc + 1];
|
| + char *copy = __mempcpy (&envp[msgbuf.message.envc + 1],
|
| + auxv, nauxv * sizeof(auxv[0]));
|
| +
|
| + /* Now copy the strings into place and fill in the string vectors. */
|
| + const char *p = msgbuf.message.string_data;
|
| + const char *endp = (char *) &msgbuf.buffer[received_size];
|
| +
|
| + /* First, the argument vector. */
|
| + for (int i = 0; i < msgbuf.message.argc; ++i)
|
| {
|
| - *dest++ = next_str;
|
| - next_str = (char *) memchr (next_str, 0, buf_end - next_str);
|
| - if (next_str == NULL)
|
| - fail ("Missing null terminator in argv list\n");
|
| - next_str++;
|
| + const char *elt_end = memchr (p, '\0', endp - p);
|
| + if (elt_end == NULL)
|
| + _dl_fatal_printf ("Unterminated argument string in startup message\n");
|
| + ++elt_end;
|
| + argv[i] = copy;
|
| + copy = __mempcpy (copy, p, elt_end - p);
|
| + p = elt_end;
|
| }
|
| - *dest++ = NULL;
|
| - /* Set up environment array */
|
| - for (i = 0; i < args->message.envc; i++)
|
| + argv[msgbuf.message.argc] = NULL;
|
| +
|
| + /* Finally, the environment vector. */
|
| + for (int i = 0; i < msgbuf.message.envc; ++i)
|
| {
|
| - *dest++ = next_str;
|
| - next_str = (char *) memchr (next_str, 0, buf_end - next_str);
|
| - if (next_str == NULL)
|
| - fail ("Missing null terminator in env list\n");
|
| - next_str++;
|
| + const char *elt_end = memchr (p, '\0', endp - p);
|
| + if (elt_end == NULL)
|
| + _dl_fatal_printf ("\
|
| +Unterminated environment string in startup message\n");
|
| + ++elt_end;
|
| + envp[i] = copy;
|
| + copy = __mempcpy (copy, p, elt_end - p);
|
| + p = elt_end;
|
| }
|
| - *dest++ = NULL;
|
| - /* Set up an empty auxv */
|
| - *dest++ = NULL;
|
| - *dest++ = NULL;
|
| - if ((char *) dest != strings)
|
| - fail ("Internal error: mismatch in array size\n");
|
| - if (next_str != buf_end)
|
| - fail ("Excess data in message body\n");
|
| -
|
| - if (munmap (args, MESSAGE_SIZE_MAX) != 0)
|
| - fail ("Failed to munmap() startup message\n");
|
| -}
|
| + envp[msgbuf.message.envc] = NULL;
|
|
|
| -void jump_to_elf_start (void *buf, uintptr_t entry_func, uintptr_t atexit_func)
|
| -{
|
| - /* The ELF entry point ABI is such that assembly code is required to
|
| - call the entry point.
|
| - See http://code.google.com/p/nativeclient/issues/detail?id=1131
|
| - TODO(mseaborn): Switch to using the normal function call ABI. */
|
| -#if defined(__i386__)
|
| - __asm__ ("mov %0, %%esp\n"
|
| - "nacljmp %1\n"
|
| - : : "m" (buf), "r" (entry_func),
|
| - "d" (atexit_func) /* %edx */);
|
| -#elif defined(__x86_64__)
|
| - __asm__ ("naclrestsp %0, %%r15\n"
|
| - "nacljmp %1, %%r15\n"
|
| - : : "m" (buf), "r" (entry_func),
|
| - "d" (atexit_func) /* %rdx */);
|
| -#else
|
| -# error Unsupported architecture
|
| -#endif
|
| + if (p != endp)
|
| + _dl_fatal_printf ("Excess data (%u bytes) in startup message body\n",
|
| + endp - p);
|
| +
|
| + return newinfo;
|
| }
|
|
|