svn commit: r217153 - in head: libexec/rtld-elf sys/sys
Konstantin Belousov
kib at FreeBSD.org
Sat Jan 8 17:11:49 UTC 2011
Author: kib
Date: Sat Jan 8 17:11:49 2011
New Revision: 217153
URL: http://svn.freebsd.org/changeset/base/217153
Log:
In rtld, read the initial stack access mode from AT_STACKPROT as set
by kernel, and parse PT_GNU_STACK phdr from linked and loaded dsos.
If the loaded dso requires executable stack, as specified by PF_X bit
of p_flags of PT_GNU_STACK phdr, but current stack protection does not
permit execution, the __pthread_map_stacks_exec symbol is looked up
and called. It should be implemented in libc or threading library and
change the protection mode of all thread stacks to be executable.
Provide a private interface _rtld_get_stack_prot() to export the stack
access mode as calculated by rtld.
Reviewed by: kan
Modified:
head/libexec/rtld-elf/Symbol.map
head/libexec/rtld-elf/map_object.c
head/libexec/rtld-elf/rtld.c
head/libexec/rtld-elf/rtld.h
head/sys/sys/link_elf.h
Modified: head/libexec/rtld-elf/Symbol.map
==============================================================================
--- head/libexec/rtld-elf/Symbol.map Sat Jan 8 16:30:59 2011 (r217152)
+++ head/libexec/rtld-elf/Symbol.map Sat Jan 8 17:11:49 2011 (r217153)
@@ -28,4 +28,5 @@ FBSDprivate_1.0 {
_rtld_atfork_pre;
_rtld_atfork_post;
_rtld_addr_phdr;
+ _rtld_get_stack_prot;
};
Modified: head/libexec/rtld-elf/map_object.c
==============================================================================
--- head/libexec/rtld-elf/map_object.c Sat Jan 8 16:30:59 2011 (r217152)
+++ head/libexec/rtld-elf/map_object.c Sat Jan 8 17:11:49 2011 (r217153)
@@ -83,6 +83,7 @@ map_object(int fd, const char *path, con
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, con
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, con
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, con
obj->tlsinitsize = phtls->p_filesz;
obj->tlsinit = mapbase + phtls->p_vaddr;
}
+ obj->stack_flags = stack_flags;
return obj;
}
Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c Sat Jan 8 16:30:59 2011 (r217152)
+++ head/libexec/rtld-elf/rtld.c Sat Jan 8 17:11:49 2011 (r217153)
@@ -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_
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_
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_
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 ph
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 ph
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,
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_Entr
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, unsig
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)
{
Modified: head/libexec/rtld-elf/rtld.h
==============================================================================
--- head/libexec/rtld-elf/rtld.h Sat Jan 8 16:30:59 2011 (r217152)
+++ head/libexec/rtld-elf/rtld.h Sat Jan 8 17:11:49 2011 (r217153)
@@ -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 */
Modified: head/sys/sys/link_elf.h
==============================================================================
--- head/sys/sys/link_elf.h Sat Jan 8 16:30:59 2011 (r217152)
+++ head/sys/sys/link_elf.h Sat Jan 8 17:11:49 2011 (r217153)
@@ -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
More information about the svn-src-all
mailing list