diff options
author | Philip Guenther <guenther@cvs.openbsd.org> | 2016-08-08 22:05:27 +0000 |
---|---|---|
committer | Philip Guenther <guenther@cvs.openbsd.org> | 2016-08-08 22:05:27 +0000 |
commit | a1a0cc4825570dd02b2ebae1476f0113978d647e (patch) | |
tree | 684832bb56d3a56bef65554621e4dfe7d9355e44 /lib/csu/boot.h | |
parent | cad4d8a2aaa04165e4354ba73bd1ed482eab3167 (diff) |
Look for a PT_GNU_RELRO section and, if present, mprotect that range
instead of the [__got_start, __got_end) range.
Also, instead of mprotecting the [__plt_start, __plt_end) range,
just scan for sections which are both writable and executable and
mprotect them to read-only. (This part was stolen from kettenis@)
ok kettenis@
Diffstat (limited to 'lib/csu/boot.h')
-rw-r--r-- | lib/csu/boot.h | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/lib/csu/boot.h b/lib/csu/boot.h index c0a541f76e6..1e9fae0684e 100644 --- a/lib/csu/boot.h +++ b/lib/csu/boot.h @@ -1,4 +1,4 @@ -/* $OpenBSD: boot.h,v 1.21 2016/08/07 02:44:00 guenther Exp $ */ +/* $OpenBSD: boot.h,v 1.22 2016/08/08 22:05:26 guenther Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -86,8 +86,6 @@ struct boot_dyn { */ void _dl_boot_bind(const long, long *, Elf_Dyn *); -extern char __plt_start[]; -extern char __plt_end[]; extern char __got_start[]; extern char __got_end[]; @@ -106,6 +104,7 @@ _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp) long loff; int prot_exec = 0; RELOC_TYPE *rp; + Elf_Phdr *phdp; Elf_Addr i; /* @@ -220,12 +219,29 @@ _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp) else pagesize = 4096; -#if defined(__alpha__) || defined(__powerpc__) || defined(__sparc__) || \ - defined(__sparc64__) - start = ELF_TRUNC((Elf_Addr)__plt_start, pagesize); - size = ELF_ROUND((Elf_Addr)__plt_end - start, pagesize); - mprotect((void *)start, size, PROT_READ); + /* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */ + phdp = (Elf_Phdr *)dl_data[AUX_phdr]; + for (i = 0; i < dl_data[AUX_phnum]; i++, phdp++) { + switch (phdp->p_type) { +#if defined(__alpha__) || defined(__hppa__) || defined(__powerpc__) || \ + defined(__sparc__) || defined(__sparc64__) + case PT_LOAD: + if ((phdp->p_flags & (PF_X | PF_W)) != (PF_X | PF_W)) + break; + mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz, + PROT_READ); + break; #endif + case PT_GNU_RELRO: + mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz, + PROT_READ); + /* + * GNU_RELRO (a) covers the GOT, and (b) comes after + * all LOAD sections, so if we found it then we're done + */ + return; + } + } #if defined(__powerpc__) if (dynld.dt_proc[DT_PROC(DT_PPC_GOT)] == 0) |