Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 8 Jan 2011 17:11:49 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r217153 - in head: libexec/rtld-elf sys/sys
Message-ID:  <201101081711.p08HBnuA098255@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101081711.p08HBnuA098255>