elf: Do not duplicate the GLIBC_TUNABLES string
[platform/upstream/glibc.git] / elf / tst-execstack.c
index 4b06615..560b353 100644 (file)
@@ -2,10 +2,12 @@
    on load of a DSO that requires executable stacks.  */
 
 #include <dlfcn.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <error.h>
+#include <stackinfo.h>
 
 static void
 print_maps (void)
@@ -45,9 +47,42 @@ waiter_thread (void *arg)
 }
 #endif
 
+static bool allow_execstack = true;
+
+
 static int
 do_test (void)
 {
+  /* Check whether SELinux is enabled and disallows executable stacks.  */
+  FILE *fp = fopen ("/selinux/enforce", "r");
+  if (fp != NULL)
+    {
+      char *line = NULL;
+      size_t linelen = 0;
+
+      bool enabled = false;
+      ssize_t n = getline (&line, &linelen, fp);
+      if (n > 0 && line[0] != '0')
+       enabled = true;
+
+      fclose (fp);
+
+      if (enabled)
+       {
+         fp = fopen ("/selinux/booleans/allow_execstack", "r");
+         if (fp != NULL)
+           {
+             n = getline (&line, &linelen, fp);
+             if (n > 0 && line[0] == '0')
+               allow_execstack = false;
+           }
+
+         fclose (fp);
+       }
+    }
+
+  printf ("executable stacks %sallowed\n", allow_execstack ? "" : "not ");
+
   static void *f;              /* Address of this is used in other threads. */
 
 #if USE_PTHREADS
@@ -72,12 +107,46 @@ do_test (void)
 
   print_maps ();
 
+#if USE_PTHREADS
+  void *old_stack_addr, *new_stack_addr;
+  size_t stack_size;
+  pthread_t me = pthread_self ();
+  pthread_attr_t attr;
+  int ret = 0;
+
+  ret = pthread_getattr_np (me, &attr);
+  if (ret)
+    {
+      printf ("before execstack: pthread_getattr_np returned error: %s\n",
+             strerror (ret));
+      return 1;
+    }
+
+  ret = pthread_attr_getstack (&attr, &old_stack_addr, &stack_size);
+  if (ret)
+    {
+      printf ("before execstack: pthread_attr_getstack returned error: %s\n",
+             strerror (ret));
+      return 1;
+    }
+# if _STACK_GROWS_DOWN
+    old_stack_addr += stack_size;
+# else
+    old_stack_addr -= stack_size;
+# endif
+#endif
+
   /* Loading this module should force stacks to become executable.  */
-  void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
+#if USE_PTHREADS
+  const char *soname = "tst-execstack-threads-mod.so";
+#else
+  const char *soname = "tst-execstack-mod.so";
+#endif
+  void *h = dlopen (soname, RTLD_LAZY);
   if (h == NULL)
     {
       printf ("cannot load: %s\n", dlerror ());
-      return 1;
+      return allow_execstack;
     }
 
   f = dlsym (h, "tryme");
@@ -94,6 +163,46 @@ do_test (void)
 
   print_maps ();
 
+#if USE_PTHREADS
+  ret = pthread_getattr_np (me, &attr);
+  if (ret)
+    {
+      printf ("after execstack: pthread_getattr_np returned error: %s\n",
+             strerror (ret));
+      return 1;
+    }
+
+  ret = pthread_attr_getstack (&attr, &new_stack_addr, &stack_size);
+  if (ret)
+    {
+      printf ("after execstack: pthread_attr_getstack returned error: %s\n",
+             strerror (ret));
+      return 1;
+    }
+
+# if _STACK_GROWS_DOWN
+    new_stack_addr += stack_size;
+# else
+    new_stack_addr -= stack_size;
+# endif
+
+  /* It is possible that the dlopen'd module may have been mmapped just below
+     the stack.  The stack size is taken as MIN(stack rlimit size, end of last
+     vma) in pthread_getattr_np.  If rlimit is set high enough, it is possible
+     that the size may have changed.  A subsequent call to
+     pthread_attr_getstack returns the size and (bottom - size) as the
+     stacksize and stackaddr respectively.  If the size changes due to the
+     above, then both stacksize and stackaddr can change, but the stack bottom
+     should remain the same, which is computed as stackaddr + stacksize.  */
+  if (old_stack_addr != new_stack_addr)
+    {
+      printf ("Stack end changed, old: %p, new: %p\n",
+             old_stack_addr, new_stack_addr);
+      return 1;
+    }
+  printf ("Stack address remains the same: %p\n", old_stack_addr);
+#endif
+
   /* Test that growing the stack region gets new executable pages too.  */
   deeper ((void (*) (void)) f);
 
@@ -113,21 +222,20 @@ do_test (void)
      Let them run to test it.  */
   pthread_barrier_wait (&go_barrier);
 
-  pthread_exit (0);
+  pthread_exit ((void *) (long int) (! allow_execstack));
 #endif
 
-  return 0;
+  return ! allow_execstack;
 }
 
 static void
 deeper (void (*f) (void))
 {
   char stack[1100 * 1024];
-  memfrob (stack, sizeof stack);
+  explicit_bzero (stack, sizeof stack);
   (*f) ();
   memfrob (stack, sizeof stack);
 }
 
 
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>