From 660c432f5961aa4240ca88f573df7bfbf65eda27 Mon Sep 17 00:00:00 2001 From: guenther Date: Mon, 8 Aug 2016 21:59:20 +0000 Subject: [PATCH] Look for a PT_GNU_RELRO section per object and, if present, mprotect that 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 | 10 ++++- libexec/ld.so/library_mquery.c | 12 +++++- libexec/ld.so/loader.c | 72 +++++++++++++++++++--------------- libexec/ld.so/resolve.c | 50 ++++++++++++++++------- libexec/ld.so/resolve.h | 6 ++- 5 files changed, 100 insertions(+), 50 deletions(-) diff --git a/libexec/ld.so/library.c b/libexec/ld.so/library.c index ff80119a6dd..7adf2bc81cf 100644 --- a/libexec/ld.so/library.c +++ b/libexec/ld.so/library.c @@ -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); diff --git a/libexec/ld.so/library_mquery.c b/libexec/ld.so/library_mquery.c index 7a214da55b5..2192d6f691d 100644 --- a/libexec/ld.so/library_mquery.c +++ b/libexec/ld.so/library_mquery.c @@ -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, diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c index 691bbbf4d77..bd7c82e95ab 100644 --- a/libexec/ld.so/loader.c +++ b/libexec/ld.so/loader.c @@ -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(); /* diff --git a/libexec/ld.so/resolve.c b/libexec/ld.so/resolve.c index d6c2e525c6e..dc384c7bed0 100644 --- a/libexec/ld.so/resolve.c +++ b/libexec/ld.so/resolve.c @@ -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); } diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h index ace0e960b1a..df0469c9fc0 100644 --- a/libexec/ld.so/resolve.h +++ b/libexec/ld.so/resolve.h @@ -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; -- 2.20.1