Load 57 into trunk.
[nativeclient.git] / service_runtime / sel_ldr_standard.c
blob32a5b932502c7cb4886edaffbd23271b2cca2f5f
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl Simple/secure ELF loader (NaCl SEL).
36 #include "native_client/include/portability.h"
38 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
43 #include "native_client/include/nacl_elf.h"
44 #include "native_client/service_runtime/sel_memory.h"
45 #include "native_client/service_runtime/sel_ldr.h"
46 #include "native_client/service_runtime/sel_util.h"
47 #include "native_client/service_runtime/sel_addrspace.h"
48 #include "native_client/service_runtime/nacl_app_thread.h"
49 #include "native_client/service_runtime/nacl_check.h"
50 #include "native_client/service_runtime/nacl_closure.h"
51 #include "native_client/service_runtime/nacl_sync_checked.h"
52 #include "native_client/service_runtime/nacl_sync_queue.h"
53 #include "native_client/service_runtime/nacl_time.h"
55 #include "native_client/service_runtime/tramp.h"
57 #define PTR_ALIGN_MASK ((sizeof(void *))-1)
60 * Other than empty segments, these are the only ones that are allowed.
62 struct NaClPhdrChecks nacl_phdr_check_data[] = {
63 /* phdr */
64 { PT_PHDR, PF_R, PCA_IGNORE, 0, 0, },
65 /* text */
66 { PT_LOAD, PF_R|PF_X, PCA_TEXT_CHECK, 1, NACL_TRAMPOLINE_SIZE, },
67 /* rodata */
68 { PT_LOAD, PF_R, PCA_NONE, 0, 0, },
69 /* data/bss */
70 { PT_LOAD, PF_R|PF_W, PCA_NONE, 0, 0, },
71 /* tdata/tbss, part of data */
72 { PT_TLS, PF_R, PCA_SAVE_TLS_INFO, 0, 0, },
74 * allow optional GNU stack permission marker, but require that the
75 * stack is non-executable.
77 { PT_GNU_STACK, PF_R|PF_W, PCA_NONE, 0, 0, },
80 NaClErrorCode NaClProcessPhdrs(struct NaClApp *nap)
82 /* Scan phdrs and do sanity checks in-line. Verify that the load
83 * address is NACL_TRAMPOLINE_SIZE, that we have a single text
84 * segment. Data and TLS segments are not required, though it is
85 * hard to avoid with standard tools, but in any case there should
86 * be at most one each. Ensure that no segment's vaddr is outside
87 * of the address space. Ensure that PT_GNU_STACK is present, and
88 * that x is off.
90 int seen_seg[(sizeof nacl_phdr_check_data
91 / sizeof nacl_phdr_check_data[0])];
92 int segnum;
93 Elf32_Phdr *php;
94 size_t j;
95 uintptr_t max_vaddr;
97 memset(seen_seg, 0, sizeof seen_seg);
98 max_vaddr = NACL_TRAMPOLINE_SIZE;
100 * nacl_phdr_check_data is small, so O(|check_data| * nap->elf_hdr.e_phum)
101 * is okay.
103 for (segnum = 0; segnum < nap->elf_hdr.e_phnum; ++segnum) {
104 php = &nap->phdrs[segnum];
105 NaClLog(3, "Looking at segment %d, type 0x%x, p_flags 0x%x\n",
106 segnum, php->p_type, php->p_flags);
107 php->p_flags &= ~PF_MASKOS;
108 for (j = 0;
109 j < sizeof nacl_phdr_check_data/sizeof nacl_phdr_check_data[0];
110 ++j) {
111 if (php->p_type == nacl_phdr_check_data[j].p_type
112 && php->p_flags == nacl_phdr_check_data[j].p_flags) {
113 NaClLog(2, "Matched nacl_phdr_check_data[%"PRIdS"]\n", j);
114 if (seen_seg[j]) {
115 NaClLog(2, "Segment %d is a type that has been seen\n", segnum);
116 return LOAD_DUP_SEGMENT;
118 ++seen_seg[j];
120 if (PCA_IGNORE == nacl_phdr_check_data[j].action) {
121 NaClLog(3, "Ignoring\n");
122 goto next_seg;
125 if (0 != php->p_memsz) {
127 * We will load this segment later. Do the sanity checks.
129 if (0 != nacl_phdr_check_data[j].p_vaddr
130 && (nacl_phdr_check_data[j].p_vaddr != php->p_vaddr)) {
131 NaClLog(2,
132 ("Segment %d: bad virtual address: 0x%08x,"
133 " expected 0x%08x\n"),
134 segnum,
135 php->p_vaddr,
136 nacl_phdr_check_data[j].p_vaddr);
137 return LOAD_SEGMENT_BAD_LOC;
139 if (php->p_vaddr < NACL_TRAMPOLINE_SIZE) {
140 NaClLog(2, "Segment %d: virtual address (0x%08x) too low\n",
141 segnum,
142 php->p_vaddr);
143 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
146 * integer overflow? Elf32_Addr and Elf32_Word are uint32_t,
147 * so the addition/comparison is well defined.
149 if (php->p_vaddr + php->p_memsz < php->p_vaddr) {
150 NaClLog(2,
151 "Segment %d: p_memsz caused integer overflow\n",
152 segnum);
153 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
155 if (php->p_vaddr + php->p_memsz >= (1U << nap->addr_bits)) {
156 NaClLog(2,
157 "Segment %d: too large, ends at 0x%08x\n",
158 segnum,
159 php->p_vaddr + php->p_memsz);
160 return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
162 if (php->p_filesz > php->p_memsz) {
163 NaClLog(2,
164 ("Segment %d: file size 0x%08x larger"
165 " than memory size 0x%08x\n"),
166 segnum,
167 php->p_filesz,
168 php->p_memsz);
169 return LOAD_SEGMENT_BAD_PARAM;
172 php->p_flags |= PF_OS_WILL_LOAD;
173 /* record our decision that we will load this segment */
176 * NACL_TRAMPOLINE_SIZE <= p_vaddr
177 * <= p_vaddr + p_memsz
178 * < (1U << nap->addr_bits)
180 if (max_vaddr < php->p_vaddr + php->p_memsz) {
181 max_vaddr = php->p_vaddr + php->p_memsz;
185 switch (nacl_phdr_check_data[j].action) {
186 case PCA_NONE:
187 break;
188 case PCA_TEXT_CHECK:
189 if (0 == php->p_memsz) {
190 return LOAD_BAD_ELF_TEXT;
192 nap->text_region_bytes = php->p_filesz;
193 break;
194 case PCA_SAVE_TLS_INFO:
195 nap->tls_start = php->p_vaddr;
196 nap->tls_size = php->p_memsz;
197 break;
198 case PCA_IGNORE:
199 break;
201 goto next_seg;
204 /* segment not in nacl_phdr_check_data */
205 if (0 == php->p_memsz) {
206 NaClLog(3, "Segment %d zero size: ignored\n", segnum);
207 continue;
209 NaClLog(2,
210 "Segment %d is of unexpected type 0x%x, flag 0x%x\n",
211 segnum,
212 php->p_type,
213 php->p_flags);
214 return LOAD_BAD_SEGMENT;
215 next_seg:
218 for (j = 0;
219 j < sizeof nacl_phdr_check_data/sizeof nacl_phdr_check_data[0];
220 ++j) {
221 if (nacl_phdr_check_data[j].required && !seen_seg[j]) {
222 return LOAD_REQUIRED_SEG_MISSING;
225 nap->data_end = nap->break_addr = max_vaddr;
227 * Memory allocation will use NaClRoundPage(nap->break_addr), but
228 * the system notion of break is always an exact address. Even
229 * though we must allocate and make accessible multiples of pages,
230 * the linux-style brk system call (which returns current break on
231 * failure) permits an arbitrarily aligned address as argument.
234 return LOAD_OK;
237 NaClErrorCode NaClAppLoadFile(struct Gio *gp,
238 struct NaClApp *nap)
240 NaClErrorCode ret = LOAD_INTERNAL;
241 NaClErrorCode subret;
243 int cur_ph;
245 /* NACL_MAX_ADDR_BITS < 32 */
246 if (nap->addr_bits > NACL_MAX_ADDR_BITS) {
247 ret = LOAD_ADDR_SPACE_TOO_BIG;
248 goto done;
251 nap->stack_size = NaClRoundAllocPage(nap->stack_size);
253 /* nap->addr_bits <= NACL_MAX_ADDR_BITS < 32 */
254 if ((*gp->vtbl->Read)(gp,
255 &nap->elf_hdr,
256 sizeof nap->elf_hdr)
257 != sizeof nap->elf_hdr) {
258 ret = LOAD_READ_ERROR;
259 goto done;
262 #define DUMP(m,f) do { NaClLog(2, \
263 #m " = %" f "\n", \
264 nap->elf_hdr.m); } while (0)
265 DUMP(e_ident+1, ".3s");
266 DUMP(e_type, "#x");
267 DUMP(e_machine, "#x");
268 DUMP(e_version, "#x");
269 DUMP(e_entry, "#x");
270 DUMP(e_phoff, "#x");
271 DUMP(e_shoff, "#x");
272 DUMP(e_flags, "#x");
273 DUMP(e_ehsize, "#x");
274 DUMP(e_phentsize, "#x");
275 DUMP(e_phnum, "#x");
276 DUMP(e_shentsize, "#x");
277 DUMP(e_shnum, "#x");
278 DUMP(e_shstrndx, "#x");
279 #undef DUMP
280 NaClLog(2, "sizeof(Elf32_Ehdr) = %x\n", (int) sizeof nap->elf_hdr);
282 if (memcmp(nap->elf_hdr.e_ident, ELFMAG, SELFMAG)) {
283 ret = LOAD_BAD_ELF_MAGIC;
284 goto done;
286 if (ELFCLASS32 != nap->elf_hdr.e_ident[EI_CLASS]) {
287 ret = LOAD_NOT_32_BIT;
288 goto done;
290 if (ELFOSABI_NACL != nap->elf_hdr.e_ident[EI_OSABI]) {
291 NaClLog(LOG_ERROR, "Expected OSABI %d, got %d\n",
292 ELFOSABI_NACL,
293 nap->elf_hdr.e_ident[EI_OSABI]);
294 ret = LOAD_BAD_ABI;
295 goto done;
297 if (EF_NACL_ABIVERSION != nap->elf_hdr.e_ident[EI_ABIVERSION]) {
298 NaClLog(LOG_ERROR, "Expected ABIVERSION %d, got %d\n",
299 EF_NACL_ABIVERSION,
300 nap->elf_hdr.e_ident[EI_ABIVERSION]);
301 ret = LOAD_BAD_ABI;
302 goto done;
304 if (ET_EXEC != nap->elf_hdr.e_type) {
305 ret = LOAD_NOT_EXEC;
306 goto done;
308 if (EM_386 != nap->elf_hdr.e_machine) {
309 ret = LOAD_BAD_MACHINE;
310 goto done;
312 if (EV_CURRENT != nap->elf_hdr.e_version) {
313 ret = LOAD_BAD_ELF_VERS;
314 goto done;
316 nap->entry_pt = nap->elf_hdr.e_entry;
318 if (nap->elf_hdr.e_flags & EF_NACL_ALIGN_MASK) {
319 unsigned long eflags = nap->elf_hdr.e_flags & EF_NACL_ALIGN_MASK;
320 if (eflags == EF_NACL_ALIGN_16) {
321 nap->align_boundary = 16;
322 } else if (eflags == EF_NACL_ALIGN_32) {
323 nap->align_boundary = 32;
324 } else {
325 ret = LOAD_BAD_ABI;
326 goto done;
328 } else {
329 nap->align_boundary = 32;
332 /* read program headers */
333 if (nap->elf_hdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) {
334 ret = LOAD_TOO_MANY_SECT; /* overloaded */
335 goto done;
337 free(nap->phdrs);
338 nap->phdrs = malloc(nap->elf_hdr.e_phnum * sizeof nap->phdrs[0]);
339 if (!nap->phdrs) {
340 ret = LOAD_NO_MEMORY;
341 goto done;
343 if (nap->elf_hdr.e_phentsize < sizeof nap->phdrs[0]) {
344 ret = LOAD_BAD_SECT;
345 goto done;
347 for (cur_ph = 0; cur_ph < nap->elf_hdr.e_phnum; ++cur_ph) {
348 if ((*gp->vtbl->Seek)(gp,
349 nap->elf_hdr.e_phoff
350 + cur_ph * nap->elf_hdr.e_phentsize,
351 SEEK_SET) == -1) {
352 ret = LOAD_BAD_SECT;
353 goto done;
355 if ((*gp->vtbl->Read)(gp,
356 &nap->phdrs[cur_ph],
357 sizeof nap->phdrs[0])
358 != sizeof nap->phdrs[0]) {
359 ret = LOAD_BAD_SECT;
360 goto done;
362 #define DUMP(mem) do {\
363 NaClLog(2, "%s: %x\n", #mem, nap->phdrs[cur_ph].mem); \
364 } while (0)
365 DUMP(p_type);
366 DUMP(p_offset);
367 DUMP(p_vaddr);
368 DUMP(p_paddr);
369 DUMP(p_filesz);
370 DUMP(p_memsz);
371 DUMP(p_flags);
372 NaClLog(2, " (%s %s %s)\n",
373 (nap->phdrs[cur_ph].p_flags & PF_R) ? "PF_R" : "",
374 (nap->phdrs[cur_ph].p_flags & PF_W) ? "PF_W" : "",
375 (nap->phdrs[cur_ph].p_flags & PF_X) ? "PF_X" : "");
376 DUMP(p_align);
377 #undef DUMP
378 NaClLog(2, "\n");
382 * We need to determine the size of the CS region. (The DS and SS
383 * region sizes are obvious -- the entire application address
384 * space.) NaClProcessPhdrs will figure out nap->text_region_bytes.
387 subret = NaClProcessPhdrs(nap);
388 if (subret != LOAD_OK) {
389 ret = subret;
390 goto done;
393 if (!NaClAddrIsValidEntryPt(nap, nap->entry_pt)) {
394 ret = LOAD_BAD_ENTRY;
395 goto done;
398 NaClLog(2, "Allocating address space\n");
399 subret = NaClAllocAddrSpace(nap);
400 if (subret != LOAD_OK) {
401 ret = subret;
402 goto done;
405 NaClLog(2, "Loading into memory\n");
406 subret = NaClLoadImage(gp, nap);
407 if (subret != LOAD_OK) {
408 ret = subret;
409 goto done;
412 NaClLog(2, "Validating image\n");
413 subret = NaClValidateImage(nap);
414 if (subret != LOAD_OK) {
415 ret = subret;
416 goto done;
419 NaClLog(2, "Installing trampoline\n");
421 NaClLoadTrampoline(nap);
423 NaClLog(2, "Installing springboard\n");
425 NaClLoadSpringboard(nap);
427 NaClLog(2, "Applying memory protection\n");
429 subret = NaClMemoryProtection(nap);
430 if (subret != LOAD_OK) {
431 ret = subret;
432 goto done;
435 ret = LOAD_OK;
436 done:
437 return ret;
440 int NaClAddrIsValidEntryPt(struct NaClApp *nap,
441 uintptr_t addr)
443 if (0 != (addr & (nap->align_boundary - 1))) {
444 return 0;
447 return addr < NACL_TRAMPOLINE_SIZE + nap->text_region_bytes;
451 * preconditions:
452 * argc > 0, argc and argv table is consistent
453 * envv may be NULL (this happens on MacOS/Cocoa
454 * if envv is non-NULL it is 'consistent', null terminated etc.
456 int NaClCreateMainThread(struct NaClApp *nap,
457 int argc,
458 char **argv,
459 char **envv)
462 * Compute size of string tables for argv and envv
464 int retval;
465 int envc;
466 char **pp;
467 size_t size;
468 int i;
469 char *p;
470 char *strp;
471 int *argv_len;
472 int *envv_len;
473 struct NaClAppThread *natp;
474 uintptr_t esp;
476 retval = 0; /* fail */
477 CHECK(argc > 0);
478 CHECK(NULL != argv);
480 if (envv == NULL) {
481 envc = 0;
482 } else {
483 for (pp = envv, envc = 0; NULL != *pp; ++pp, ++envc)
486 envv_len = 0;
487 argv_len = malloc(argc * sizeof argv_len[0]);
488 envv_len = malloc(envc * sizeof envv_len[0]);
489 if (NULL == argv_len) {
490 goto cleanup;
492 if (NULL == envv_len && 0 != envc) {
493 goto cleanup;
496 size = 0;
498 for (i = 0; i < argc; ++i) {
499 argv_len[i] = strlen(argv[i]) + 1;
500 size += argv_len[i];
502 for (i = 0; i < envc; ++i) {
503 envv_len[i] = strlen(envv[i]) + 1;
504 size += envv_len[i];
507 size += (argc + envc + 4) * sizeof(char *) + sizeof(int);
509 size = (size + PTR_ALIGN_MASK) & ~PTR_ALIGN_MASK;
511 if (size > nap->stack_size) {
512 retval = 0;
513 goto cleanup;
516 /* write strings and char * arrays to stack */
518 esp = (nap->mem_start + (1 << nap->addr_bits) - size);
519 VCHECK(0 == (esp & PTR_ALIGN_MASK), ("esp not aligned: %08x\n", esp));
521 p = (char *) esp;
522 strp = p + (argc + envc + 4) * sizeof(char *) + sizeof(int);
524 #define BLAT(t, v) do { \
525 *(t *) p = (t) v; p += sizeof(t); \
526 } while (0);
528 BLAT(int, argc);
530 for (i = 0; i < argc; ++i) {
531 BLAT(char *, NaClSysToUser(nap, (uintptr_t) strp));
532 strcpy(strp, argv[i]);
533 strp += argv_len[i];
535 BLAT(char *, 0);
537 for (i = 0; i < envc; ++i) {
538 BLAT(char *, NaClSysToUser(nap, (uintptr_t) strp));
539 strcpy(strp, envv[i]);
540 strp += envv_len[i];
542 BLAT(char *, 0);
543 /* Push an empty auxv for glibc support */
544 BLAT(char *, 0);
545 BLAT(char *, 0);
546 #undef BLAT
548 /* now actually spawn the thread */
549 natp = malloc(sizeof *natp);
550 if (!natp) {
551 goto cleanup;
554 nap->running = 1;
556 /* e_entry is user addr */
557 if (!NaClAppThreadAllocSegCtor(natp,
558 nap,
560 nap->elf_hdr.e_entry,
561 NaClSysToUser(nap, esp),
562 NaClUserToSys(nap, nap->break_addr),
563 1)) {
564 retval = 0;
565 goto cleanup;
569 * NB: Hereafter locking is required to access nap.
571 retval = 1;
572 cleanup:
573 free(argv_len);
574 free(envv_len);
576 return retval;
579 int NaClWaitForMainThreadToExit(struct NaClApp *nap)
581 struct NaClClosure *work;
583 while (NULL != (work = NaClSyncQueueDequeue(&nap->work_queue))) {
584 NaClLog(3, "NaClWaitForMainThreadToExit: got work %08"PRIxPTR"\n",
585 (uintptr_t) work);
586 NaClLog(3, " invoking Run fn %08"PRIxPTR"\n",
587 (uintptr_t) work->vtbl->Run);
589 (*work->vtbl->Run)(work);
590 NaClLog(3, "... done\n");
593 NaClLog(3, " taking NaClApp lock\n");
594 NaClXMutexLock(&nap->mu);
595 NaClLog(3, " waiting for exit status\n");
596 while (nap->running) {
597 NaClCondVarWait(&nap->cv, &nap->mu);
600 * Some thread invoked the exit (exit_group) syscall.
603 return (nap->exit_status);
606 int32_t NaClCreateAdditionalThread(struct NaClApp *nap,
607 uintptr_t eip,
608 uintptr_t esp,
609 uintptr_t sys_tdb,
610 size_t tdb_size)
612 struct NaClAppThread *natp;
614 natp = malloc(sizeof *natp);
615 if (NULL == natp) {
616 return -NACL_ABI_ENOMEM;
618 if (!NaClAppThreadAllocSegCtor(natp, nap, 0, eip, esp, sys_tdb, tdb_size)) {
619 return -NACL_ABI_ENOMEM;
621 return 0;