[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#344105: libc6: [powerpc] _dl_map_object_from_fd removes data segment execute permission



Package: libc6
Version: 2.3.5-9
Severity: normal
Tags: patch


When using a kernel with a 64kB page size we noticed a glibc issue where
execute permission can be removed from the GOT. Since the GOT needs to be
executable we then die (it uses a trick with a blrl instruction in
order to find the GOT address).

Details of this bug can be found at:

http://sources.redhat.com/bugzilla/show_bug.cgi?id=1346

The upstream fix, rediffed and tested against 2.3.5-9 is below.


	2005-09-20  Roland McGrath  <roland@redhat.com>

	[BZ #1346]
	* elf/dl-load.c (_dl_map_object_from_fd) [HAVE_Z_RELRO]: Do relro
	magic on __stack_prot only if [SHARED].  Skip mprotect if __stack_prot
	lies outside the page-rounded-down relro region.

--- elf/dl-load.c~	2005-12-14 22:27:00.000000000 -0600
+++ elf/dl-load.c	2005-12-14 22:35:59.000000000 -0600
@@ -1314,22 +1314,36 @@
 
   if (__builtin_expect ((stack_flags &~ GL(dl_stack_flags)) & PF_X, 0))
     {
+      if (__builtin_expect (__check_caller (RETURN_ADDRESS (0), allow_ldso),
+			    0) != 0)
+	{
+	  errstring = N_("invalid caller");
+	  goto call_lose;
+	}
+
       /* The stack is presently not executable, but this module
 	 requires that it be executable.  We must change the
 	 protection of the variable which contains the flags used in
 	 the mprotect calls.  */
-#ifdef HAVE_Z_RELRO
+#if defined HAVE_Z_RELRO && defined SHARED
       if (mode & __RTLD_DLOPEN)
 	{
-	  uintptr_t p = ((uintptr_t) &__stack_prot) & ~(GLRO(dl_pagesize) - 1);
-	  size_t s = (uintptr_t) &__stack_prot - p + sizeof (int);
+	  const uintptr_t p = (uintptr_t) &__stack_prot & -GLRO(dl_pagesize);
+	  const size_t s = (uintptr_t) (&__stack_prot + 1) - p;
 
-	  __mprotect ((void *) p, s, PROT_READ|PROT_WRITE);
-	  if (__builtin_expect (__check_caller (RETURN_ADDRESS (0),
-						allow_ldso|allow_libc) == 0,
-				0))
+	  struct link_map *const m = &GL(dl_rtld_map);
+	  const uintptr_t relro_end = ((m->l_addr + m->l_relro_addr
+					+ m->l_relro_size)
+				       & -GLRO(dl_pagesize));
+	  if (__builtin_expect (p + s <= relro_end, 1))
+	    {
+	      /* The variable lies in the region protected by RELRO.  */
+	      __mprotect ((void *) p, s, PROT_READ|PROT_WRITE);
+	      __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
+	      __mprotect ((void *) p, s, PROT_READ);
+	    }
+	  else
 	    __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
-	  __mprotect ((void *) p, s, PROT_READ);
 	}
       else
 #endif


-- System Information:
Debian Release: testing/unstable
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: powerpc (ppc)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6.15-rc6-gdf7addbb
Locale: LANG=en_AU, LC_CTYPE=en_AU (charmap=ISO-8859-1)

-- no debconf information



Reply to: