about summary refs log tree commit diff
path: root/nptl/allocatestack.c
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/allocatestack.c')
-rw-r--r--nptl/allocatestack.c66
1 files changed, 52 insertions, 14 deletions
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;
 }