From owner-svn-src-all@FreeBSD.ORG Sat Jan 8 17:11:49 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 679A61065693; Sat, 8 Jan 2011 17:11:49 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 562058FC1E; Sat, 8 Jan 2011 17:11:49 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p08HBnuk098261; Sat, 8 Jan 2011 17:11:49 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p08HBnuA098255; Sat, 8 Jan 2011 17:11:49 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201101081711.p08HBnuA098255@svn.freebsd.org> From: Konstantin Belousov Date: Sat, 8 Jan 2011 17:11:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r217153 - in head: libexec/rtld-elf sys/sys X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 08 Jan 2011 17:11:49 -0000 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