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

Side by Side Diff: sysdeps/nacl/receive_args.c

Issue 7282019: Adjust for new NaCl startup ABI (Closed) Base URL: http://git.chromium.org/native_client/nacl-glibc.git@master
Patch Set: Created 9 years, 5 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
OLDNEW
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
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
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
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
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 }
OLDNEW
« make_sysd_rules.py ('K') | « sysdeps/nacl/receive_args.h ('k') | sysdeps/nacl/start.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698