diff options
| author | Nick Kralevich <nnk@google.com> | 2012-11-16 08:45:51 -0800 |
|---|---|---|
| committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2012-11-16 08:45:52 -0800 |
| commit | fe07ca04e4af6c43d068df0e23dc83431053fc22 (patch) | |
| tree | 86641f34bf889da7a8040adc7429c11cbf8f5157 | |
| parent | 170168cdf37111b45b15817fab9e3df54cbc27b7 (diff) | |
| parent | ac3de8d080745e62c77fdf03e3923726d0a6b50d (diff) | |
| download | bionic-fe07ca04e4af6c43d068df0e23dc83431053fc22.zip bionic-fe07ca04e4af6c43d068df0e23dc83431053fc22.tar.gz bionic-fe07ca04e4af6c43d068df0e23dc83431053fc22.tar.bz2 | |
Merge "Support GNU_RELRO for static executables."
| -rw-r--r-- | libc/bionic/libc_init_static.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/libc/bionic/libc_init_static.c b/libc/bionic/libc_init_static.c index a73bb71..ba7f008 100644 --- a/libc/bionic/libc_init_static.c +++ b/libc/bionic/libc_init_static.c @@ -48,6 +48,14 @@ #include <bionic_tls.h> #include <errno.h> +#include <sys/mman.h> + +// Returns the address of the page containing address 'x'. +#define PAGE_START(x) ((x) & PAGE_MASK) + +// Returns the address of the next page after address 'x', unless 'x' is +// itself at the start of a page. +#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1)) static void call_array(void(**list)()) { @@ -57,6 +65,42 @@ static void call_array(void(**list)()) } } +/* + * Find the value of the AT_* variable passed to us by the kernel. + */ +static unsigned find_aux(unsigned *vecs, unsigned type) { + while (vecs[0]) { + if (vecs[0] == type) { + return vecs[1]; + } + vecs += 2; + } + + return 0; // should never happen +} + +static void apply_gnu_relro(unsigned *vecs) { + Elf32_Phdr *phdr_start; + unsigned phdr_ct; + Elf32_Phdr *phdr; + + phdr_start = (Elf32_Phdr *) find_aux(vecs, AT_PHDR); + phdr_ct = find_aux(vecs, AT_PHNUM); + + for (phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) { + if (phdr->p_type != PT_GNU_RELRO) + continue; + + Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr); + Elf32_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz); + + // Check return value here? What do we do if we fail? + mprotect((void *) seg_page_start, + seg_page_end - seg_page_start, + PROT_READ); + } +} + __noreturn void __libc_init(uintptr_t *elfdata, void (*onexit)(void), int (*slingshot)(int, char**, char**), @@ -64,6 +108,7 @@ __noreturn void __libc_init(uintptr_t *elfdata, { int argc; char **argv, **envp; + unsigned *vecs; __libc_init_tls(NULL); @@ -84,6 +129,14 @@ __noreturn void __libc_init(uintptr_t *elfdata, argv = (char**)(elfdata + 1); envp = argv + argc + 1; + // The auxiliary vector is at the end of the environment block + vecs = (unsigned *) envp; + while (vecs[0] != 0) { + vecs++; + } + /* The end of the environment block is marked by two NULL pointers */ + vecs++; + /* The executable may have its own destructors listed in its .fini_array * so we need to ensure that these are called when the program exits * normally. @@ -91,5 +144,6 @@ __noreturn void __libc_init(uintptr_t *elfdata, if (structors->fini_array) __cxa_atexit(__libc_fini,structors->fini_array,NULL); + apply_gnu_relro(vecs); exit(slingshot(argc, argv, envp)); } |
