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
This commit is contained in:
parent
291c06a127
commit
212f264cd6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=217153
@ -28,4 +28,5 @@ FBSDprivate_1.0 {
|
||||
_rtld_atfork_pre;
|
||||
_rtld_atfork_post;
|
||||
_rtld_addr_phdr;
|
||||
_rtld_get_stack_prot;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user