summaryrefslogtreecommitdiff
path: root/libexec/ld.so
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-06-08 11:59:00 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-06-08 11:59:00 +0000
commit23d3f11debde1922bcf0ee2ddb76dbc44f94fa84 (patch)
tree57509bf1825555f47bc0e77bcd816e3aa06fe043 /libexec/ld.so
parentca23d60df1120a1060e97f92930c0dcffc7632c6 (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.c20
-rw-r--r--libexec/ld.so/loader.c13
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);