about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-09-25 03:16:53 +0000
committerUlrich Drepper <drepper@redhat.com>2003-09-25 03:16:53 +0000
commit279f1143afdb06e263dfab510a3e2cbb022014fe (patch)
treec5a4a51ecb1e2673162ca08c584a56515c34415d
parent977169541668f2287c5f8e239e5743eb9cefcb63 (diff)
downloadglibc-279f1143afdb06e263dfab510a3e2cbb022014fe.tar.gz
glibc-279f1143afdb06e263dfab510a3e2cbb022014fe.tar.xz
glibc-279f1143afdb06e263dfab510a3e2cbb022014fe.zip
Update.
	* allocatestack.c (change_stack_perm): Split out from
	__make_stacks_executable.
	(allocate_stack): If the required permission changed between the time
	we started preparing the stack and queueing it, change the permission.
	(__make_stacks_executable): Call change_stack_perm.
-rw-r--r--nptl/ChangeLog6
-rw-r--r--nptl/allocatestack.c66
2 files changed, 58 insertions, 14 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 0ee343c3d1..e18c9cac21 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,5 +1,11 @@
 2003-09-24  Ulrich Drepper  <drepper@redhat.com>
 
+	* allocatestack.c (change_stack_perm): Split out from
+	__make_stacks_executable.
+	(allocate_stack): If the required permission changed between the time
+	we started preparing the stack and queueing it, change the permission.
+	(__make_stacks_executable): Call change_stack_perm.
+
 	* Makefile: Build tst-execstack-mod locally.
 	* tst-execstack-mod.c: New file.
 
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index dc501650b8..24292e7295 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -249,6 +249,29 @@ queue_stack (struct pthread *stack)
 }
 
 
+static int
+internal_function
+change_stack_perm (struct pthread *pd
+#ifdef NEED_SEPARATE_REGISTER_STACK
+		   , size_t pagemask
+#endif
+		   )
+{
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  void *stack = (pd->stackblock
+		 + (((((pd->stackblock_size - pd->guardsize) / 2)
+		      & pagemask) + pd->guardsize) & pagemask));
+  size_t len = pd->stackblock + pd->stackblock_size - stack;
+#else
+  void *stack = pd->stackblock + pd->guardsize;
+  size_t len = pd->stackblock_size - pd->guardsize;
+#endif
+  if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+    return errno;
+
+  return 0;
+}
+
 
 static int
 allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
@@ -493,6 +516,28 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 	  lll_unlock (stack_cache_lock);
 
 
+	  /* There might have been a race.  Another thread might have
+	     caused the stacks to get exec permission while this new
+	     stack was prepared.  Detect if this was possible and
+	     change the permission if necessary.  */
+	  if (__builtin_expect ((GL(dl_stack_flags) & PF_X) != 0
+				&& (prot & PROT_EXEC) == 0, 0))
+	    {
+	      int err = change_stack_perm (pd
+#ifdef NEED_SEPARATE_REGISTER_STACK
+					   , ~pagesize_m1
+#endif
+					   );
+	      if (err != 0)
+		{
+		  /* Free the stack memory we just allocated.  */
+		  (void) munmap (mem, size);
+
+		  return err;
+		}
+	    }
+
+
 	  /* Note that all of the stack and the thread descriptor is
 	     zeroed.  This means we do not have to initialize fields
 	     with initial value zero.  This is specifically true for
@@ -630,26 +675,19 @@ __make_stacks_executable (void)
   list_t *runp;
   list_for_each (runp, &stack_used)
     {
-      struct pthread *const pd = list_entry (runp, struct pthread, list);
+      err = change_stack_perm (list_entry (runp, struct pthread, list)
 #ifdef NEED_SEPARATE_REGISTER_STACK
-      void *stack = (pd->stackblock
-		     + (((((pd->stackblock_size - pd->guardsize) / 2)
-			  & pagemask) + pd->guardsize) & pagemask));
-      size_t len = pd->stackblock + pd->stackblock_size - stack;
-#else
-      void *stack = pd->stackblock + pd->guardsize;
-      size_t len = pd->stackblock_size - pd->guardsize;
+			       , pagemask
 #endif
-      if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
-	{
-	  err = errno;
-	  break;
-	}
+			       );
+      if (err != 0)
+	break;
     }
 
   lll_unlock (stack_cache_lock);
 
-  _dl_make_stack_executable ();
+  if (err == 0)
+    _dl_make_stack_executable ();
 
   return err;
 }