Look for a PT_GNU_RELRO section per object and, if present, mprotect that
authorguenther <guenther@openbsd.org>
Mon, 8 Aug 2016 21:59:20 +0000 (21:59 +0000)
committerguenther <guenther@openbsd.org>
Mon, 8 Aug 2016 21:59:20 +0000 (21:59 +0000)
range instead of the [__got_start, __got_end) range.
On many archs this will cover _DYNAMIC too, so move up the DT_DEBUG handling
to before relocations and the mprotect are done.

ok kettenis@

libexec/ld.so/library.c
libexec/ld.so/library_mquery.c
libexec/ld.so/loader.c
libexec/ld.so/resolve.c
libexec/ld.so/resolve.h

index ff80119..7adf2bc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: library.c,v 1.77 2016/07/04 21:15:06 guenther Exp $ */
+/*     $OpenBSD: library.c,v 1.78 2016/08/08 21:59:20 guenther Exp $ */
 
 /*
  * Copyright (c) 2002 Dale Rahn
@@ -98,6 +98,7 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
        struct load_list *next_load, *load_list = NULL;
        Elf_Addr maxva = 0, minva = ELFDEFNNAME(NO_ADDR);
        Elf_Addr libaddr, loff, align = _dl_pagesz - 1;
+       Elf_Addr relro_addr = 0, relro_size = 0;
        elf_object_t *object;
        char    hbuf[4096];
        Elf_Dyn *dynp = NULL;
@@ -281,6 +282,11 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
                            phdp->p_memsz);
                        break;
 
+               case PT_GNU_RELRO:
+                       relro_addr = phdp->p_vaddr + loff;
+                       relro_size = phdp->p_memsz;
+                       break;
+
                default:
                        break;
                }
@@ -299,6 +305,8 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
                object->dev = sb.st_dev;
                object->inode = sb.st_ino;
                object->obj_flags |= flags;
+               object->relro_addr = relro_addr;
+               object->relro_size = relro_size;
                _dl_set_sod(object->load_name, &object->sod);
                if (ptls != NULL && ptls->p_memsz)
                        _dl_set_tls(object, ptls, libaddr, libname);
index 7a214da..2192d6f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: library_mquery.c,v 1.54 2016/07/04 21:15:06 guenther Exp $ */
+/*     $OpenBSD: library_mquery.c,v 1.55 2016/08/08 21:59:20 guenther Exp $ */
 
 /*
  * Copyright (c) 2002 Dale Rahn
@@ -108,6 +108,7 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
        Elf_Addr load_end = 0;
        Elf_Addr align = _dl_pagesz - 1, off, size;
        Elf_Phdr *ptls = NULL;
+       Elf_Addr relro_addr = 0, relro_size = 0;
        struct stat sb;
        char hbuf[4096];
 
@@ -297,10 +298,15 @@ retry:
        }
 
        phdp = (Elf_Phdr *)(hbuf + ehdr->e_phoff);
-       for (i = 0; i < ehdr->e_phnum; i++, phdp++)
+       for (i = 0; i < ehdr->e_phnum; i++, phdp++) {
                if (phdp->p_type == PT_OPENBSD_RANDOMIZE)
                        _dl_randombuf((char *)(phdp->p_vaddr + LOFF),
                            phdp->p_memsz);
+               else if (phdp->p_type == PT_GNU_RELRO) {
+                       relro_addr = phdp->p_vaddr + LOFF;
+                       relro_size = phdp->p_memsz;
+               }
+       }
 
        _dl_close(libfile);
 
@@ -315,6 +321,8 @@ retry:
                object->dev = sb.st_dev;
                object->inode = sb.st_ino;
                object->obj_flags |= flags;
+               object->relro_addr = relro_addr;
+               object->relro_size = relro_size;
                _dl_set_sod(object->load_name, &object->sod);
                if (ptls != NULL && ptls->p_memsz)
                        _dl_set_tls(object, ptls, (Elf_Addr)lowld->start,
index 691bbbf..bd7c82e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: loader.c,v 1.162 2016/07/04 21:15:06 guenther Exp $ */
+/*     $OpenBSD: loader.c,v 1.163 2016/08/08 21:59:20 guenther Exp $ */
 
 /*
  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -478,6 +478,10 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
                        }
                        ptls = phdp;
                        break;
+               case PT_GNU_RELRO:
+                       exe_obj->relro_addr = phdp->p_vaddr + exe_loff;
+                       exe_obj->relro_size = phdp->p_memsz;
+                       break;
                }
                phdp++;
        }
@@ -524,37 +528,9 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
        _dl_allocate_tls_offsets();
 
        /*
-        * Everything should be in place now for doing the relocation
-        * and binding. Call _dl_rtld to do the job. Fingers crossed.
-        */
-       failed = 0;
-       if (_dl_traceld == NULL)
-               failed = _dl_rtld(_dl_objects);
-
-       if (_dl_debug || _dl_traceld) {
-               if (_dl_traceld)
-                       _dl_pledge("stdio rpath", NULL);
-               _dl_show_objects();
-       }
-
-       DL_DEB(("dynamic loading done, %s.\n",
-           (failed == 0) ? "success":"failed"));
-
-       if (failed != 0)
-               _dl_exit(1);
-
-       if (_dl_traceld)
-               _dl_exit(0);
-
-       _dl_loading_object = NULL;
-
-       /* set up the TIB for the initial thread */
-       _dl_allocate_first_tib();
-
-       _dl_fixup_user_env();
-
-       /*
-        * Finally make something to help gdb when poking around in the code.
+        * Make something to help gdb when poking around in the code.
+        * Do this poking at the .dynamic section now, before relocation
+        * renders it read-only
         */
        map_link = NULL;
 #ifdef __mips__
@@ -594,6 +570,38 @@ _dl_boot(const char **argv, char **envp, const long dyn_loff, long *dl_data)
 #endif
        }
 
+
+       /*
+        * Everything should be in place now for doing the relocation
+        * and binding. Call _dl_rtld to do the job. Fingers crossed.
+        */
+
+       failed = 0;
+       if (_dl_traceld == NULL)
+               failed = _dl_rtld(_dl_objects);
+
+       if (_dl_debug || _dl_traceld) {
+               if (_dl_traceld)
+                       _dl_pledge("stdio rpath", NULL);
+               _dl_show_objects();
+       }
+
+       DL_DEB(("dynamic loading done, %s.\n",
+           (failed == 0) ? "success":"failed"));
+
+       if (failed != 0)
+               _dl_exit(1);
+
+       if (_dl_traceld)
+               _dl_exit(0);
+
+       _dl_loading_object = NULL;
+
+       /* set up the TIB for the initial thread */
+       _dl_allocate_first_tib();
+
+       _dl_fixup_user_env();
+
        _dl_debug_state();
 
        /*
index d6c2e52..dc384c7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: resolve.c,v 1.73 2016/07/04 21:15:06 guenther Exp $ */
+/*     $OpenBSD: resolve.c,v 1.74 2016/08/08 21:59:20 guenther Exp $ */
 
 /*
  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -442,31 +442,53 @@ _dl_protect_segment(elf_object_t *object, Elf_Addr addr,
        const Elf_Sym *this;
        Elf_Addr ooff, start, end;
 
-       if (addr == 0) {
+       if (addr == 0 && start_sym[2] == 'g' &&
+           (addr = object->relro_addr) != 0) {
+               DL_DEB(("protect start RELRO = 0x%lx in %s\n",
+                   addr, object->load_name));
+       }
+       else if (addr == 0) {
                this = NULL;
                ooff = _dl_find_symbol(start_sym, &this,
                    SYM_SEARCH_OBJ | SYM_NOWARNNOTFOUND | SYM_PLT, NULL,
                    object, NULL);
                /* If not found, nothing to do */
-               if (this == NULL)
+               if (this == NULL) {
+                       DL_DEB(("protect start \"%s\" not found in %s\n",
+                           start_sym, object->load_name));
                        return (NULL);
+               }
                addr = ooff + this->st_value;
+               DL_DEB(("protect start \"%s\" to %x = 0x%lx in %s\n",
+                   start_sym, prot, addr, object->load_name));
        }
 
-       this = NULL;
-       ooff = _dl_find_symbol(end_sym, &this,
-           SYM_SEARCH_OBJ | SYM_NOWARNNOTFOUND | SYM_PLT, NULL, object, NULL);
-       if (this == NULL)
-               addr = 0;
-       else {
-               end = ooff + this->st_value;
-               if (addr < end) {
-                       start = ELF_TRUNC(addr, _dl_pagesz);
-                       end = ELF_ROUND(end, _dl_pagesz);
-                       _dl_mprotect((void *)start, end - start, prot);
+       if (object->relro_addr != 0 && start_sym[2] == 'g') {
+               end = object->relro_addr + object->relro_size;
+               DL_DEB(("protect end RELRO = 0x%lx in %s\n",
+                   end, object->load_name));
+       } else {
+               this = NULL;
+               ooff = _dl_find_symbol(end_sym, &this,
+                   SYM_SEARCH_OBJ | SYM_NOWARNNOTFOUND | SYM_PLT, NULL,
+                   object, NULL);
+               if (this == NULL) {
+                       DL_DEB(("protect end \"%s\" not found in %s\n",
+                           end_sym, object->load_name));
+                       addr = 0;
+               } else {
+                       end = ooff + this->st_value;
+                       DL_DEB(("protect end \"%s\" = 0x%lx in %s\n",
+                           end_sym, end, object->load_name));
                }
        }
 
+       if (addr != 0 && addr < end) {
+               start = ELF_TRUNC(addr, _dl_pagesz);
+               end = ELF_ROUND(end, _dl_pagesz);
+               _dl_mprotect((void *)start, end - start, prot);
+       }
+
        return ((void *)addr);
 }
 
index ace0e96..df0469c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: resolve.h,v 1.78 2016/07/04 21:15:06 guenther Exp $ */
+/*     $OpenBSD: resolve.h,v 1.79 2016/08/08 21:59:20 guenther Exp $ */
 
 /*
  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -148,6 +148,10 @@ struct elf_object {
        const void      *tls_static_data;
        int             tls_offset;
 
+       /* relro bits */
+       Elf_Addr        relro_addr;
+       Elf_Addr        relro_size;
+
        /* generation number of last grpsym insert on this object */
        unsigned int grpsym_gen;