Update.
authorUlrich Drepper <drepper@redhat.com>
Thu, 25 Sep 2003 03:16:53 +0000 (03:16 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 25 Sep 2003 03:16:53 +0000 (03:16 +0000)
* 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.

nptl/ChangeLog
nptl/allocatestack.c

index 0ee343c..e18c9ca 100644 (file)
@@ -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.
 
index dc50165..24292e7 100644 (file)
@@ -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;
 }