summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libexec/rtld-elf/Symbol.map1
-rw-r--r--libexec/rtld-elf/map_object.c7
-rw-r--r--libexec/rtld-elf/rtld.c42
-rw-r--r--libexec/rtld-elf/rtld.h1
-rw-r--r--sys/sys/link_elf.h1
5 files changed, 52 insertions, 0 deletions
diff --git a/libexec/rtld-elf/Symbol.map b/libexec/rtld-elf/Symbol.map
index 7a8273f..6a416a7 100644
--- a/libexec/rtld-elf/Symbol.map
+++ b/libexec/rtld-elf/Symbol.map
@@ -28,4 +28,5 @@ FBSDprivate_1.0 {
_rtld_atfork_pre;
_rtld_atfork_post;
_rtld_addr_phdr;
+ _rtld_get_stack_prot;
};
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index d231830..3f69e9b 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -83,6 +83,7 @@ map_object(int fd, const char *path, const struct stat *sb)
Elf_Addr bss_vaddr;
Elf_Addr bss_vlimit;
caddr_t bss_addr;
+ Elf_Word stack_flags;
hdr = get_elf_header(fd, path);
if (hdr == NULL)
@@ -100,6 +101,7 @@ map_object(int fd, const char *path, const struct stat *sb)
phdyn = phinterp = phtls = NULL;
phdr_vaddr = 0;
segs = alloca(sizeof(segs[0]) * hdr->e_phnum);
+ stack_flags = PF_X | PF_R | PF_W;
while (phdr < phlimit) {
switch (phdr->p_type) {
@@ -128,6 +130,10 @@ map_object(int fd, const char *path, const struct stat *sb)
case PT_TLS:
phtls = phdr;
break;
+
+ case PT_GNU_STACK:
+ stack_flags = phdr->p_flags;
+ break;
}
++phdr;
@@ -261,6 +267,7 @@ map_object(int fd, const char *path, const struct stat *sb)
obj->tlsinitsize = phtls->p_filesz;
obj->tlsinit = mapbase + phtls->p_vaddr;
}
+ obj->stack_flags = stack_flags;
return obj;
}
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index ee3985b..2e39b67 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -103,6 +103,7 @@ static void unload_filtees(Obj_Entry *);
static int load_needed_objects(Obj_Entry *, int);
static int load_preload_objects(void);
static Obj_Entry *load_object(const char *, const Obj_Entry *, int);
+static void map_stacks_exec(void);
static Obj_Entry *obj_from_addr(const void *);
static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *);
static void objlist_call_init(Objlist *, RtldLockState *);
@@ -188,6 +189,9 @@ extern Elf_Dyn _DYNAMIC;
int osreldate, pagesize;
+static int stack_prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+static int max_stack_flags;
+
/*
* Global declarations normally provided by crt1. The dynamic linker is
* not built with crt1, so we have to provide them ourselves.
@@ -382,6 +386,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
close(fd);
if (obj_main == NULL)
die();
+ max_stack_flags = obj->stack_flags;
} else { /* Main program already loaded. */
const Elf_Phdr *phdr;
int phnum;
@@ -421,6 +426,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
dbg("obj_main path %s", obj_main->path);
obj_main->mainprog = true;
+ if (aux_info[AT_STACKPROT] != NULL &&
+ aux_info[AT_STACKPROT]->a_un.a_val != 0)
+ stack_prot = aux_info[AT_STACKPROT]->a_un.a_val;
+
/*
* Get the actual dynamic linker pathname from the executable if
* possible. (It should always be possible.) That ensures that
@@ -519,6 +528,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */
+ map_stacks_exec();
+
wlock_acquire(rtld_bind_lock, &lockstate);
objlist_call_init(&initlist, &lockstate);
objlist_clear(&initlist);
@@ -1031,6 +1042,8 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
break;
}
+ obj->stack_flags = PF_X | PF_R | PF_W;
+
for (ph = phdr; ph < phlimit; ph++) {
switch (ph->p_type) {
@@ -1062,6 +1075,10 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path)
obj->tlsinitsize = ph->p_filesz;
obj->tlsinit = (void*)(ph->p_vaddr + obj->relocbase);
break;
+
+ case PT_GNU_STACK:
+ obj->stack_flags = ph->p_flags;
+ break;
}
}
if (nsegs < 1) {
@@ -1679,6 +1696,7 @@ do_load_object(int fd, const char *name, char *path, struct stat *sbp,
obj_count++;
obj_loads++;
linkmap_add(obj); /* for GDB & dlinfo() */
+ max_stack_flags |= obj->stack_flags;
dbg(" %p .. %p: %s", obj->mapbase,
obj->mapbase + obj->mapsize - 1, obj->path);
@@ -2202,6 +2220,8 @@ dlopen_object(const char *name, Obj_Entry *refobj, int lo_flags, int mode)
name);
GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL);
+ map_stacks_exec();
+
/* Call the init functions. */
objlist_call_init(&initlist, &lockstate);
objlist_clear(&initlist);
@@ -3872,6 +3892,28 @@ fetch_ventry(const Obj_Entry *obj, unsigned long symnum)
return NULL;
}
+int
+_rtld_get_stack_prot(void)
+{
+
+ return (stack_prot);
+}
+
+static void
+map_stacks_exec(void)
+{
+ void (*thr_map_stacks_exec)(void);
+
+ if ((max_stack_flags & PF_X) == 0 || (stack_prot & PROT_EXEC) != 0)
+ return;
+ thr_map_stacks_exec = (void (*)(void))(uintptr_t)
+ get_program_var_addr("__pthread_map_stacks_exec");
+ if (thr_map_stacks_exec != NULL) {
+ stack_prot |= PROT_EXEC;
+ thr_map_stacks_exec();
+ }
+}
+
void
symlook_init(SymLook *dst, const char *name)
{
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index b70e8b6..8941d29 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -157,6 +157,7 @@ typedef struct Struct_Obj_Entry {
const Elf_Phdr *phdr; /* Program header if it is mapped, else NULL */
size_t phsize; /* Size of program header in bytes */
const char *interp; /* Pathname of the interpreter, if any */
+ Elf_Word stack_flags;
/* TLS information */
int tlsindex; /* Index in DTV for this module */
diff --git a/sys/sys/link_elf.h b/sys/sys/link_elf.h
index 93fe1de..45b9430 100644
--- a/sys/sys/link_elf.h
+++ b/sys/sys/link_elf.h
@@ -93,6 +93,7 @@ __BEGIN_DECLS
typedef int (*__dl_iterate_hdr_callback)(struct dl_phdr_info *, size_t, void *);
extern int dl_iterate_phdr(__dl_iterate_hdr_callback, void *);
int _rtld_addr_phdr(const void *, struct dl_phdr_info *);
+int _rtld_get_stack_prot(void);
__END_DECLS
OpenPOWER on IntegriCloud