summaryrefslogtreecommitdiff
path: root/lib/csu/boot.h
diff options
context:
space:
mode:
authorPhilip Guenther <guenther@cvs.openbsd.org>2016-08-08 22:05:27 +0000
committerPhilip Guenther <guenther@cvs.openbsd.org>2016-08-08 22:05:27 +0000
commita1a0cc4825570dd02b2ebae1476f0113978d647e (patch)
tree684832bb56d3a56bef65554621e4dfe7d9355e44 /lib/csu/boot.h
parentcad4d8a2aaa04165e4354ba73bd1ed482eab3167 (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.h32
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)