diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-06-08 11:59:00 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-06-08 11:59:00 +0000 |
commit | 23d3f11debde1922bcf0ee2ddb76dbc44f94fa84 (patch) | |
tree | 57509bf1825555f47bc0e77bcd816e3aa06fe043 /libexec/ld.so | |
parent | ca23d60df1120a1060e97f92930c0dcffc7632c6 (diff) |
Some ELF ABIs still require a PLT that is both writable and executable. To
avoid W^X violations, initially map such segments as writable and
non-executable, and change the mapping to non-writable and executable
after initial relocation processing. As a side-benefit this means we no
longer depend on the __plt_start and __plt_end to make the PLT read-only
after relocation processing.
This will break binaries linked with ld -Z, most notably emacs, on some
of our architectures.
ok deraadt@, guenther@
Diffstat (limited to 'libexec/ld.so')
-rw-r--r-- | libexec/ld.so/library.c | 20 | ||||
-rw-r--r-- | libexec/ld.so/loader.c | 13 |
2 files changed, 27 insertions, 6 deletions
diff --git a/libexec/ld.so/library.c b/libexec/ld.so/library.c index 5318af38592..455b95f18a9 100644 --- a/libexec/ld.so/library.c +++ b/libexec/ld.so/library.c @@ -1,4 +1,4 @@ -/* $OpenBSD: library.c,v 1.75 2016/05/07 19:05:23 guenther Exp $ */ +/* $OpenBSD: library.c,v 1.76 2016/06/08 11:58:59 kettenis Exp $ */ /* * Copyright (c) 2002 Dale Rahn @@ -215,11 +215,22 @@ _dl_tryload_shlib(const char *libname, int type, int flags) char *start = (char *)(TRUNC_PG(phdp->p_vaddr)) + loff; Elf_Addr off = (phdp->p_vaddr & align); Elf_Addr size = off + phdp->p_filesz; + int flags = PFLAGS(phdp->p_flags); void *res; + /* + * Initially map W|X segments without X + * permission. After we're done with the + * initial relocation processing, we will make + * these segments read-only and add back the X + * permission. This way we maintain W^X at + * all times. + */ + if ((flags & PROT_WRITE) && (flags & PROT_EXEC)) + flags &= ~PROT_EXEC; + if (size != 0) { - res = _dl_mmap(start, ROUND_PG(size), - PFLAGS(phdp->p_flags), + res = _dl_mmap(start, ROUND_PG(size), flags, MAP_FIXED|MAP_PRIVATE, libfile, TRUNC_PG(phdp->p_offset)); } else @@ -252,8 +263,7 @@ _dl_tryload_shlib(const char *libname, int type, int flags) start = start + ROUND_PG(size); size = ROUND_PG(off + phdp->p_memsz) - ROUND_PG(size); - res = _dl_mmap(start, size, - PFLAGS(phdp->p_flags), + res = _dl_mmap(start, size, flags, MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); if (_dl_mmap_error(res)) { _dl_printf("%s: rtld mmap failed mapping %s.\n", diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c index b0c316fbc17..e9aaa592873 100644 --- a/libexec/ld.so/loader.c +++ b/libexec/ld.so/loader.c @@ -1,4 +1,4 @@ -/* $OpenBSD: loader.c,v 1.160 2016/06/05 19:43:58 kettenis Exp $ */ +/* $OpenBSD: loader.c,v 1.161 2016/06/08 11:58:59 kettenis Exp $ */ /* * Copyright (c) 1998 Per Fogelstrom, Opsycon AB @@ -637,6 +637,7 @@ int _dl_rtld(elf_object_t *object) { size_t sz; + struct load_list *llist; int fails = 0; if (object->next) @@ -675,6 +676,16 @@ _dl_rtld(elf_object_t *object) fails += _dl_md_reloc_got(object, !(_dl_bindnow || object->obj_flags & DF_1_NOW)); + /* + * Look for W|X segments and make them read-only. + */ + for (llist = object->load_list; llist != NULL; llist = llist->next) { + if ((llist->prot & PROT_WRITE) && (llist->prot & PROT_EXEC)) { + _dl_mprotect(llist->start, llist->size, + llist->prot & ~PROT_WRITE); + } + } + if (_dl_symcache != NULL) { if (sz != 0) _dl_munmap( _dl_symcache, sz); |