diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-31 01:46:38 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-31 01:46:38 +0000 |
commit | 4451feeb191113651cb1a82862d2bece91290b8d (patch) | |
tree | bac56ba575c66e240b9cd2c0959a7f25d902b1a9 /chrome/nacl | |
parent | 12274721df2f935cc1147964492ab87edbb3acee (diff) | |
download | chromium_src-4451feeb191113651cb1a82862d2bece91290b8d.zip chromium_src-4451feeb191113651cb1a82862d2bece91290b8d.tar.gz chromium_src-4451feeb191113651cb1a82862d2bece91290b8d.tar.bz2 |
Revert 98909 - Use chain-loading for Linux nacl_helper
This replaces the nacl_helper_bootstrap program, dynamically-linked against
nacl_helper.so, with a standalone, statically-linked nacl_helper_bootstrap
program that loads the dynamic linker, instructing it in turn to load the
nacl_helper program (now a PIE rather than a DSO).
This avoids two problems with the old scheme:
1. The nacl_helper_bootstrap program remained in the dynamic linker's
list of loaded objects, as the main executable, even though the
memory where its .dynamic section had been was overwritten with
the NaCl untrusted address space. Code that traverses the list of
all loaded objects could thus attempt to look at pointers into this
part of memory, and be led astray.
2. nacl_helper_bootstrap's large (~1G) bss segment could cause the kernel
to refuse to load the program because it didn't think there was enough
free memory in the system for so large an allocation of anonymous memory.
The bootstrap program is kept very small by avoiding all use of libc
(except for memset and integer division routines needed on ARM). It has
its own custom start-up code hand-written in assembly and its own custom
system call stubs done with hand-written GCC inline asm statements.
To avoid the second problem, the bootstrap program no longer has a large
bss. Instead, it has a special ELF segment (i.e. PT_LOAD header) that
specifies no memory access, and a large (~1G) mapping size from the file.
This mapping is way off the end of the file, but the kernel doesn't mind
that, and since it's all a file mapping, the kernel does not do its normal
memory accounting for consuming a large amount of anonymous memory.
Unfortunately, it's impossible to get the linker to produce exactly the
right PT_LOAD header by itself. Using a custom linker script, we get the
layout exactly how we want it and a PT_LOAD header that is almost right.
We then use a build-time helper program to munge one field of the PT_LOAD
to make it exactly what we need.
BUG= http://code.google.com/p/chromium/issues/detail?id=94147
TEST= hand-tested chromium build, invoked with --nacl-linux-helper
R=bradchen@google.com,mseaborn@chromium.org
Review URL: http://codereview.chromium.org/7795010
TBR=mcgrathr@chromium.org
Review URL: http://codereview.chromium.org/7811013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98910 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/nacl')
-rw-r--r-- | chrome/nacl/nacl_fork_delegate_linux.cc | 18 | ||||
-rw-r--r-- | chrome/nacl/nacl_helper_bootstrap_linux.c | 433 | ||||
-rw-r--r-- | chrome/nacl/nacl_helper_bootstrap_linux.x | 93 | ||||
-rw-r--r-- | chrome/nacl/nacl_helper_bootstrap_munge_phdr.c | 66 | ||||
-rwxr-xr-x | chrome/nacl/nacl_helper_bootstrap_munge_phdr.py | 36 | ||||
-rw-r--r-- | chrome/nacl/nacl_helper_exports.txt | 10 | ||||
-rw-r--r-- | chrome/nacl/nacl_helper_linux.cc | 26 |
7 files changed, 51 insertions, 631 deletions
diff --git a/chrome/nacl/nacl_fork_delegate_linux.cc b/chrome/nacl/nacl_fork_delegate_linux.cc index 26fae53..e5ee01a 100644 --- a/chrome/nacl/nacl_fork_delegate_linux.cc +++ b/chrome/nacl/nacl_fork_delegate_linux.cc @@ -26,8 +26,6 @@ NaClForkDelegate::NaClForkDelegate() sandboxed_(false), fd_(-1) {} -const char kNaClHelperAtZero[] = "--at-zero"; - void NaClForkDelegate::Init(const bool sandboxed, const int browserdesc, const int sandboxdesc) { @@ -50,18 +48,18 @@ void NaClForkDelegate::Init(const bool sandboxed, const bool use_helper = CommandLine::ForCurrentProcess()->HasSwitch( switches::kNaClLinuxHelper); FilePath helper_exe; - FilePath helper_bootstrap_exe; - if (use_helper && - PathService::Get(chrome::FILE_NACL_HELPER, &helper_exe) && - PathService::Get(chrome::FILE_NACL_HELPER_BOOTSTRAP, - &helper_bootstrap_exe)) { + if (use_helper && PathService::Get(chrome::FILE_NACL_HELPER, &helper_exe)) { CommandLine::StringVector argv = CommandLine::ForCurrentProcess()->argv(); - argv[0] = helper_bootstrap_exe.value(); - argv[1] = helper_exe.value(); - argv[2] = kNaClHelperAtZero; + argv[0] = helper_exe.value(); base::LaunchOptions options; options.fds_to_remap = &fds_to_map; options.clone_flags = CLONE_FS | SIGCHLD; + // LD_BIND_NOW forces non-lazy binding in the dynamic linker, to + // prevent the linker from trying to look at the text of the nacl_helper + // program after it has been replaced by the nacl module. + base::environment_vector env; + env.push_back(std::make_pair("LD_BIND_NOW", "1")); + options.environ = &env; ready_ = base::LaunchProcess(argv, options, NULL); // parent and error cases are handled below } diff --git a/chrome/nacl/nacl_helper_bootstrap_linux.c b/chrome/nacl/nacl_helper_bootstrap_linux.c index c534c39..7a0ace7 100644 --- a/chrome/nacl/nacl_helper_bootstrap_linux.c +++ b/chrome/nacl/nacl_helper_bootstrap_linux.c @@ -2,428 +2,23 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * - * This is a standalone program that loads and runs the dynamic linker. - * This program itself must be linked statically. To keep it small, it's - * written to avoid all dependencies on libc and standard startup code. - * Hence, this should be linked using -nostartfiles. It must be compiled - * with -fno-stack-protector to ensure the compiler won't emit code that - * presumes some special setup has been done. - * - * On ARM, the compiler will emit calls to some libc functions, so we - * cannot link with -nostdlib. The functions it does use (memset and - * __aeabi_* functions for integer division) are sufficiently small and - * self-contained in ARM's libc.a that we don't have any problem using - * the libc definitions though we aren't using the rest of libc or doing - * any of the setup it might expect. - */ - -#include <elf.h> -#include <fcntl.h> -#include <link.h> -#include <stddef.h> -#include <stdint.h> -#include <sys/mman.h> - -#define MAX_PHNUM 12 - -#if defined(__i386__) -# define DYNAMIC_LINKER "/lib/ld-linux.so.2" -#elif defined(__x86_64__) -# define DYNAMIC_LINKER "/lib64/ld-linux-x86-64.so.2" -#elif defined(__ARM_EABI__) -# define DYNAMIC_LINKER "/lib/ld-linux.so.3" -#else -# error "Don't know the dynamic linker file name for this architecture!" -#endif - - -/* - * We're not using <string.h> functions here, to avoid dependencies. - * In the x86 libc, even "simple" functions like memset and strlen can - * depend on complex startup code, because in newer libc - * implementations they are defined using STT_GNU_IFUNC. - */ - -static void my_bzero(void *buf, size_t n) { - char *p = buf; - while (n-- > 0) - *p++ = 0; -} - -static size_t my_strlen(const char *s) { - size_t n = 0; - while (*s++ != '\0') - ++n; - return n; -} - - -/* - * Get inline functions for system calls. - */ -static int my_errno; -#define SYS_ERRNO my_errno -#include "third_party/lss/linux_syscall_support.h" - - -/* - * We're avoiding libc, so no printf. The only nontrivial thing we need - * is rendering numbers, which is, in fact, pretty trivial. - */ -static void iov_int_string(int value, struct kernel_iovec *iov, - char *buf, size_t bufsz) { - char *p = &buf[bufsz]; - do { - --p; - *p = "0123456789"[value % 10]; - value /= 10; - } while (value != 0); - iov->iov_base = p; - iov->iov_len = &buf[bufsz] - p; -} - -#define STRING_IOV(string_constant, cond) \ - { (void *) string_constant, cond ? (sizeof(string_constant) - 1) : 0 } - -__attribute__((noreturn)) static void fail(const char *message, - const char *item1, int value1, - const char *item2, int value2) { - char valbuf1[32]; - char valbuf2[32]; - struct kernel_iovec iov[] = { - STRING_IOV("bootstrap_helper", 1), - STRING_IOV(DYNAMIC_LINKER, 1), - STRING_IOV(": ", 1), - { (void *) message, my_strlen(message) }, - { (void *) item1, item1 == NULL ? 0 : my_strlen(item1) }, - STRING_IOV("=", item1 != NULL), - {}, - STRING_IOV(", ", item1 != NULL && item2 != NULL), - { (void *) item2, item2 == NULL ? 0 : my_strlen(item2) }, - STRING_IOV("=", item2 != NULL), - {}, - { "\n", 1 }, - }; - const int niov = sizeof(iov) / sizeof(iov[0]); - - if (item1 != NULL) - iov_int_string(value1, &iov[6], valbuf1, sizeof(valbuf1)); - if (item2 != NULL) - iov_int_string(value1, &iov[10], valbuf2, sizeof(valbuf2)); - - sys_writev(2, iov, niov); - sys_exit_group(2); - while (1) *(volatile int *) 0 = 0; /* Crash. */ -} - - -static int my_open(const char *file, int oflag) { - int result = sys_open(file, oflag, 0); - if (result < 0) - fail("Cannot open dynamic linker! ", "errno", my_errno, NULL, 0); - return result; -} - -static void my_pread(const char *fail_message, - int fd, void *buf, size_t bufsz, uintptr_t pos) { - ssize_t result = sys_pread64(fd, buf, bufsz, pos); - if (result < 0) - fail(fail_message, "errno", my_errno, NULL, 0); - if ((size_t) result != bufsz) - fail(fail_message, "read count", result, NULL, 0); -} - -static uintptr_t my_mmap(const char *segment_type, unsigned int segnum, - uintptr_t address, size_t size, - int prot, int flags, int fd, uintptr_t pos) { -#if defined(__NR_mmap2) - void *result = sys_mmap2((void *) address, size, prot, flags, fd, pos >> 12); -#else - void *result = sys_mmap((void *) address, size, prot, flags, fd, pos); -#endif - if (result == MAP_FAILED) - fail("Failed to map from dynamic linker! ", - segment_type, segnum, "errno", my_errno); - return (uintptr_t) result; -} - -static void my_mprotect(unsigned int segnum, - uintptr_t address, size_t size, int prot) { - if (sys_mprotect((void *) address, size, prot) < 0) - fail("Failed to mprotect hole in dynamic linker! ", - "segment", segnum, "errno", my_errno); -} - - -static int prot_from_phdr(const ElfW(Phdr) *phdr) { - int prot = 0; - if (phdr->p_flags & PF_R) - prot |= PROT_READ; - if (phdr->p_flags & PF_W) - prot |= PROT_WRITE; - if (phdr->p_flags & PF_X) - prot |= PROT_EXEC; - return prot; -} - -static uintptr_t round_up(uintptr_t value, uintptr_t size) { - return (value + size - 1) & -size; -} - -static uintptr_t round_down(uintptr_t value, uintptr_t size) { - return value & -size; -} - -/* - * Handle the "bss" portion of a segment, where the memory size - * exceeds the file size and we zero-fill the difference. For any - * whole pages in this region, we over-map anonymous pages. For the - * sub-page remainder, we zero-fill bytes directly. + * Bootstraping the nacl_helper. This executable reserves the bottom 1G + * of the address space, then invokes nacl_helper_init. Note that, + * as the text of this executable will eventually be overwritten by the + * native_client module, nacl_helper_init must not attempt to return. */ -static void handle_bss(unsigned int segnum, const ElfW(Phdr) *ph, - ElfW(Addr) load_bias, size_t pagesize) { - if (ph->p_memsz > ph->p_filesz) { - ElfW(Addr) file_end = ph->p_vaddr + load_bias + ph->p_filesz; - ElfW(Addr) file_page_end = round_up(file_end, pagesize); - ElfW(Addr) page_end = round_up(ph->p_vaddr + load_bias + - ph->p_memsz, pagesize); - if (page_end > file_page_end) - my_mmap("bss segment", segnum, - file_page_end, page_end - file_page_end, - prot_from_phdr(ph), MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); - if (file_page_end > file_end && (ph->p_flags & PF_W)) - my_bzero((void *) file_end, file_page_end - file_end); - } -} - -/* - * This is the main loading code. It's called with the address of the - * auxiliary vector on the stack, which we need to examine and modify. - * It returns the dynamic linker's runtime entry point address, where - * we should jump to. This is called by the machine-dependent _start - * code (below). On return, it restores the original stack pointer - * and jumps to this entry point. - */ -ElfW(Addr) do_load(ElfW(auxv_t) *auxv) { - /* - * Record the auxv entries that are specific to the file loaded. - * The incoming entries point to our own static executable. - */ - ElfW(auxv_t) *av_entry = NULL; - ElfW(auxv_t) *av_phdr = NULL; - ElfW(auxv_t) *av_phnum = NULL; - size_t pagesize = 0; - - ElfW(auxv_t) *av; - for (av = auxv; - av_entry == NULL || av_phdr == NULL || av_phnum == NULL || pagesize == 0; - ++av) { - switch (av->a_type) { - case AT_NULL: - fail("Failed to find AT_ENTRY, AT_PHDR, AT_PHNUM, or AT_PAGESZ!", - NULL, 0, NULL, 0); - /*NOTREACHED*/ - break; - case AT_ENTRY: - av_entry = av; - break; - case AT_PAGESZ: - pagesize = av->a_un.a_val; - break; - case AT_PHDR: - av_phdr = av; - break; - case AT_PHNUM: - av_phnum = av; - break; - } - } - - int fd = my_open(DYNAMIC_LINKER, O_RDONLY); - - ElfW(Ehdr) ehdr; - my_pread("Failed to read ELF header from dynamic linker! ", - fd, &ehdr, sizeof(ehdr), 0); - - if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || - ehdr.e_ident[EI_MAG1] != ELFMAG1 || - ehdr.e_ident[EI_MAG2] != ELFMAG2 || - ehdr.e_ident[EI_MAG3] != ELFMAG3 || - ehdr.e_version != EV_CURRENT || - ehdr.e_ehsize != sizeof(ehdr) || - ehdr.e_phentsize != sizeof(ElfW(Phdr))) - fail("Dynamic linker has no valid ELF header!", NULL, 0, NULL, 0); - - switch (ehdr.e_machine) { -#if defined(__i386__) - case EM_386: -#elif defined(__x86_64__) - case EM_X86_64: -#elif defined(__arm__) - case EM_ARM: -#else -# error "Don't know the e_machine value for this architecture!" -#endif - break; - default: - fail("Dynamic linker has wrong architecture! ", - "e_machine", ehdr.e_machine, NULL, 0); - break; - } - - ElfW(Phdr) phdr[MAX_PHNUM]; - if (ehdr.e_phnum > sizeof(phdr) / sizeof(phdr[0]) || ehdr.e_phnum < 1) - fail("Dynamic linker has unreasonable ", - "e_phnum", ehdr.e_phnum, NULL, 0); - if (ehdr.e_type != ET_DYN) - fail("Dynamic linker not ET_DYN! ", - "e_type", ehdr.e_type, NULL, 0); +#include <stdlib.h> - my_pread("Failed to read program headers from dynamic linker! ", - fd, phdr, sizeof(phdr[0]) * ehdr.e_phnum, ehdr.e_phoff); +/* reserve 1GB of space */ +#define ONEGIG (1 << 30) +char nacl_reserved_space[ONEGIG]; - size_t i = 0; - while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD) - ++i; - if (i == ehdr.e_phnum) - fail("Dynamic linker has no PT_LOAD header!", - NULL, 0, NULL, 0); +void nacl_helper_init(int argc, char *argv[], + const char *nacl_reserved_space); - /* - * ELF requires that PT_LOAD segments be in ascending order of p_vaddr. - * Find the last one to calculate the whole address span of the image. - */ - const ElfW(Phdr) *first_load = &phdr[i]; - const ElfW(Phdr) *last_load = &phdr[ehdr.e_phnum - 1]; - while (last_load > first_load && last_load->p_type != PT_LOAD) - --last_load; - - size_t span = last_load->p_vaddr + last_load->p_memsz - first_load->p_vaddr; - - /* - * Map the first segment and reserve the space used for the rest and - * for holes between segments. - */ - const uintptr_t mapping = my_mmap("segment", first_load - phdr, - round_down(first_load->p_vaddr, pagesize), - span, prot_from_phdr(first_load), - MAP_PRIVATE, fd, - round_down(first_load->p_offset, pagesize)); - - const ElfW(Addr) load_bias = mapping - round_down(first_load->p_vaddr, - pagesize); - - if (first_load->p_offset > ehdr.e_phoff || - first_load->p_filesz < ehdr.e_phoff + (ehdr.e_phnum * sizeof(ElfW(Phdr)))) - fail("First load segment of dynamic linker does not contain phdrs!", - NULL, 0, NULL, 0); - - /* Point the auxv elements at the dynamic linker's phdrs and entry. */ - av_phdr->a_un.a_val = (ehdr.e_phoff - first_load->p_offset + - first_load->p_vaddr + load_bias); - av_phnum->a_un.a_val = ehdr.e_phnum; - av_entry->a_un.a_val = ehdr.e_entry + load_bias; - - handle_bss(first_load - phdr, first_load, load_bias, pagesize); - - ElfW(Addr) last_end = first_load->p_vaddr + load_bias + first_load->p_memsz; - - /* - * Map the remaining segments, and protect any holes between them. - */ - const ElfW(Phdr) *ph; - for (ph = first_load + 1; ph <= last_load; ++ph) { - if (ph->p_type == PT_LOAD) { - ElfW(Addr) last_page_end = round_up(last_end, pagesize); - - last_end = ph->p_vaddr + load_bias + ph->p_memsz; - ElfW(Addr) start = round_down(ph->p_vaddr + load_bias, pagesize); - ElfW(Addr) end = round_up(last_end, pagesize); - - if (start > last_page_end) - my_mprotect(ph - phdr, last_page_end, start - last_page_end, PROT_NONE); - - my_mmap("segment", ph - phdr, - start, end - start, - prot_from_phdr(ph), MAP_PRIVATE | MAP_FIXED, fd, - round_down(ph->p_offset, pagesize)); - - handle_bss(ph - phdr, ph, load_bias, pagesize); - } - } - - sys_close(fd); - - return ehdr.e_entry + load_bias; +int main(int argc, char *argv[]) { + nacl_helper_init(argc, argv, nacl_reserved_space); + abort(); + return 0; // convince the tools I'm sane. } - -/* - * We have to define the actual entry point code (_start) in assembly - * for each machine. The kernel startup protocol is not compatible - * with the normal C function calling convention. Here, we calculate - * the address of the auxiliary vector on the stack; call do_load - * (above) using the normal C convention as per the ABI; restore the - * original starting stack; and finally, jump to the dynamic linker's - * entry point address. - */ -#if defined(__i386__) -asm(".globl _start\n" - ".type _start,@function\n" - "_start:\n" - "xorl %ebp, %ebp\n" - "movl %esp, %ebx\n" /* Save starting SP in %ebx. */ - "andl $-16, %esp\n" /* Align the stack as per ABI. */ - "movl (%ebx), %eax\n" /* argc */ - "leal 8(%ebx,%eax,4), %ecx\n" /* envp */ - /* Find the envp element that is NULL, and auxv is past there. */ - "0: addl $4, %ecx\n" - "cmpl $0, -4(%ecx)\n" - "jne 0b\n" - "pushl %ecx\n" /* Argument: auxv. */ - "call do_load\n" - "movl %ebx, %esp\n" /* Restore the saved SP. */ - "jmp *%eax\n" /* Jump to the entry point. */ - ); -#elif defined(__x86_64__) -asm(".globl _start\n" - ".type _start,@function\n" - "_start:\n" - "xorq %rbp, %rbp\n" - "movq %rsp, %rbx\n" /* Save starting SP in %rbx. */ - "andq $-16, %rsp\n" /* Align the stack as per ABI. */ - "movq (%rbx), %rax\n" /* argc */ - "leaq 16(%rbx,%rax,8), %rdi\n" /* envp */ - /* Find the envp element that is NULL, and auxv is past there. */ - "0: addq $8, %rdi\n" - "cmpq $0, -8(%rdi)\n" - "jne 0b\n" - "call do_load\n" /* Argument already in %rdi: auxv */ - "movq %rbx, %rsp\n" /* Restore the saved SP. */ - "jmp *%rax\n" /* Jump to the entry point. */ - ); -#elif defined(__arm__) -asm(".globl _start\n" - ".type _start,#function\n" - "_start:\n" -#if defined(__thumb2__) - ".thumb\n" - ".syntax unified\n" -#endif - "mov fp, #0\n" - "mov lr, #0\n" - "mov r4, sp\n" /* Save starting SP in r4. */ - "ldr r1, [r4]\n" /* argc */ - "add r1, r1, #2\n" - "add r0, r4, r1, asl #2\n" /* envp */ - /* Find the envp element that is NULL, and auxv is past there. */ - "0: ldr r1, [r0], #4\n" - "cmp r1, #0\n" - "bne 0b\n" - "bl do_load\n" - "mov sp, r4\n" /* Restore the saved SP. */ - "blx r0\n" /* Jump to the entry point. */ - ); -#else -# error "Need stack-preserving _start code for this architecture!" -#endif diff --git a/chrome/nacl/nacl_helper_bootstrap_linux.x b/chrome/nacl/nacl_helper_bootstrap_linux.x deleted file mode 100644 index 5eae077..0000000 --- a/chrome/nacl/nacl_helper_bootstrap_linux.x +++ /dev/null @@ -1,93 +0,0 @@ -/* Copyright (c) 2011 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * This is a custom linker script used to build nacl_helper_bootstrap. - * It has a very special layout. This script will only work with input - * that is kept extremely minimal. If there are unexpected input sections - * not named here, the result will not be correct. - * - * We need to use a standalone loader program rather than just using a - * dynamically-linked program here because its entire address space will be - * taken over for the NaCl untrusted address space. A normal program would - * cause dynamic linker data structures to point to its .dynamic section, - * which is no longer available after startup. - * - * We need this special layout (and the nacl_helper_bootstrap_munge_phdr - * step) because simply having bss space large enough to reserve the - * address space would cause the kernel loader to think we're using that - * much anonymous memory and refuse to execute the program on a machine - * with not much memory available. - */ - -/* - * Set the entry point to the symbol called _start, which we define in assembly. - */ -ENTRY(_start) - -/* - * This is the address where the program text starts. - * We set this as low as we think we can get away with. - * The common settings for sysctl vm.mmap_min_addr range from 4k to 64k. - */ -TEXT_START = 0x10000; - -/* - * This is the top of the range we are trying to reserve, which is 1G - * for x86-32 and ARM. For an x86-64 zero-based sandbox, this really - * needs to be 36G. - */ -RESERVE_TOP = 1 << 30; - -/* - * We specify the program headers we want explicitly, to get the layout - * exactly right and to give the "reserve" segment p_flags of zero, so - * that it gets mapped as PROT_NONE. - */ -PHDRS { - text PT_LOAD FILEHDR PHDRS; - reserve PT_LOAD FLAGS(0); - stack PT_GNU_STACK FLAGS(6); /* RW, no E */ -} - -/* - * Now we lay out the sections across those segments. - */ -SECTIONS { - /* - * Here is the program itself. - */ - .text TEXT_START + SIZEOF_HEADERS : { - *(.note.gnu.build-id) - *(.text*) - *(.rodata*) - *(.eh_frame*) - } :text - etext = .; - - /* - * Now we move up to the next p_align increment, and place the dummy - * segment there. The linker emits this segment with the p_vaddr and - * p_memsz we want, which reserves the address space. But the linker - * gives it a p_filesz of zero. We have to edit the phdr after link - * time to give it a p_filesz matching its p_memsz. That way, the - * kernel doesn't think we are preallocating a huge amount of memory. - * It just maps it from the file, i.e. way off the end of the file, - * which is perfect for reserving the address space. - */ - . = ALIGN(CONSTANT(COMMONPAGESIZE)); - RESERVE_START = .; - .reserve : { - . = RESERVE_TOP - RESERVE_START; - } :reserve - - /* - * These are empty input sections the linker generates. - * If we don't discard them, they pollute the flags in the output segment. - */ - /DISCARD/ : { - *(.iplt) - *(.rel*) - *(.igot.plt) - } -} diff --git a/chrome/nacl/nacl_helper_bootstrap_munge_phdr.c b/chrome/nacl/nacl_helper_bootstrap_munge_phdr.c deleted file mode 100644 index 87fe73f..0000000 --- a/chrome/nacl/nacl_helper_bootstrap_munge_phdr.c +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (c) 2011 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * This is a trivial program to edit an ELF file in place, making - * one crucial modification to a program header. It's invoked: - * bootstrap_phdr_hacker FILENAME SEGMENT_NUMBER - * where SEGMENT_NUMBER is the zero-origin index of the program header - * we'll touch. This is a PT_LOAD with p_filesz of zero. We change its - * p_filesz to match its p_memsz value. - */ - -#include <errno.h> -#include <error.h> -#include <fcntl.h> -#include <gelf.h> -#include <libelf.h> -#include <stdlib.h> -#include <unistd.h> - -int main(int argc, char **argv) { - if (argc != 3) - error(1, 0, "Usage: %s FILENAME SEGMENT_NUMBER", argv[0]); - - const char *const file = argv[1]; - const int segment = atoi(argv[2]); - - int fd = open(file, O_RDWR); - if (fd < 0) - error(2, errno, "Cannot open %s for read/write", file); - - if (elf_version(EV_CURRENT) == EV_NONE) - error(2, 0, "elf_version: %s", elf_errmsg(-1)); - - Elf *elf = elf_begin(fd, ELF_C_RDWR, NULL); - if (elf == NULL) - error(2, 0, "elf_begin: %s", elf_errmsg(-1)); - - if (elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT) == 0) - error(2, 0, "elf_flagelf: %s", elf_errmsg(-1)); - - GElf_Phdr phdr; - GElf_Phdr *ph = gelf_getphdr(elf, segment, &phdr); - if (ph == NULL) - error(2, 0, "gelf_getphdr: %s", elf_errmsg(-1)); - - if (ph->p_type != PT_LOAD) - error(3, 0, "Program header %d is %u, not PT_LOAD", - segment, (unsigned int) ph->p_type); - if (ph->p_filesz != 0) - error(3, 0, "Program header %d has nonzero p_filesz", segment); - - ph->p_filesz = ph->p_memsz; - if (gelf_update_phdr(elf, segment, ph) == 0) - error(2, 0, "gelf_update_phdr: %s", elf_errmsg(-1)); - - if (elf_flagphdr(elf, ELF_C_SET, ELF_F_DIRTY) == 0) - error(2, 0, "elf_flagphdr: %s", elf_errmsg(-1)); - - if (elf_update(elf, ELF_C_WRITE) < 0) - error(2, 0, "elf_update: %s", elf_errmsg(-1)); - - close(fd); - - return 0; -} diff --git a/chrome/nacl/nacl_helper_bootstrap_munge_phdr.py b/chrome/nacl/nacl_helper_bootstrap_munge_phdr.py deleted file mode 100755 index c3a3931..0000000 --- a/chrome/nacl/nacl_helper_bootstrap_munge_phdr.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2011 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# This takes three command-line arguments: -# MUNGE-PHDR-PROGRAM file name of program built from -# nacl_helper_bootstrap_munge_phdr.c -# INFILE raw linked ELF file name -# OUTFILE output file name -# -# We just run the MUNGE-PHDR-PROGRAM on a copy of INFILE. -# That modifies the file in place. Then we move it to OUTFILE. -# -# We only have this wrapper script because nacl_helper_bootstrap_munge_phdr.c -# wants to modify a file in place (and it would be a much longer and more -# fragile program if it created a fresh ELF output file instead). - -import shutil -import subprocess -import sys - - -def Main(argv): - if len(argv) != 4: - print 'Usage: %s MUNGE-PHDR-PROGRAM INFILE OUTFILE' % argv[0] - sys.exit(1) - [prog, munger, infile, outfile] = argv - tmpfile = outfile + '.tmp' - shutil.copy(infile, tmpfile) - segment_num = '1' - subprocess.check_call([munger, tmpfile, segment_num]) - shutil.move(tmpfile, outfile) - -if __name__ == '__main__': - Main(sys.argv) diff --git a/chrome/nacl/nacl_helper_exports.txt b/chrome/nacl/nacl_helper_exports.txt new file mode 100644 index 0000000..af930c1 --- /dev/null +++ b/chrome/nacl/nacl_helper_exports.txt @@ -0,0 +1,10 @@ +# gnu-ld version script for exporting desired symbols from nacl_helper +# + +NACL_HELPER_1_0 { + global: + nacl_helper_init; + nacl_helper_get_1G_address; + local: + *; +}; diff --git a/chrome/nacl/nacl_helper_linux.cc b/chrome/nacl/nacl_helper_linux.cc index 7ffeadb..b53cf8d 100644 --- a/chrome/nacl/nacl_helper_linux.cc +++ b/chrome/nacl/nacl_helper_linux.cc @@ -23,7 +23,6 @@ #include "content/common/main_function_params.h" #include "content/common/unix_domain_socket_posix.h" #include "ipc/ipc_switches.h" -#include "native_client/src/trusted/service_runtime/sel_memory.h" namespace { @@ -117,20 +116,33 @@ void HandleForkRequest(const std::vector<int>& child_fds) { } // namespace -static const char kNaClHelperAtZero[] = "at-zero"; +static const void* g_nacl_reserved_space = NULL; +extern "C" __attribute__((visibility("default"))) +const void* nacl_helper_get_1G_address() { + return g_nacl_reserved_space; +} -int main(int argc, char *argv[]) { +// nacl_helper_init does the real work of this module. It is invoked as +// a static constructor and never returns, preventing main() from the +// nacl_helper_bootstrap program from being called. +// +// NOTE This routine must not return. +extern "C" __attribute__((visibility("default"))) +void nacl_helper_init(int argc, char *argv[], + const char *nacl_reserved_space) { CommandLine::Init(argc, argv); base::AtExitManager exit_manager; base::RandUint64(); // acquire /dev/urandom fd before sandbox is raised std::vector<int> empty; // for SendMsg() calls g_suid_sandbox_active = (NULL != getenv("SBX_D")); - - if (CommandLine::ForCurrentProcess()->HasSwitch(kNaClHelperAtZero)) { - g_nacl_prereserved_sandbox_addr = (void *) (uintptr_t) 0x10000; + g_nacl_reserved_space = nacl_reserved_space; + if (!nacl_reserved_space) { + VLOG(1) << "nacl_reserved_space is NULL"; + } else { + VLOG(1) << "nacl_reserved_space is at " + << (void *)nacl_reserved_space; } - // Send the zygote a message to let it know we are ready to help if (!UnixDomainSocket::SendMsg(kNaClZygoteDescriptor, kNaClHelperStartupAck, |