Look for a PT_GNU_RELRO section and, if present, mprotect that range
authorguenther <guenther@openbsd.org>
Mon, 8 Aug 2016 22:05:26 +0000 (22:05 +0000)
committerguenther <guenther@openbsd.org>
Mon, 8 Aug 2016 22:05:26 +0000 (22:05 +0000)
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@

lib/csu/boot.h

index c0a541f..1e9fae0 100644 (file)
@@ -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)