Back to index

glibc  2.9
tst-execstack.c
Go to the documentation of this file.
00001 /* Test program for making nonexecutable stacks executable
00002    on load of a DSO that requires executable stacks.  */
00003 
00004 #include <dlfcn.h>
00005 #include <stdbool.h>
00006 #include <stdio.h>
00007 #include <string.h>
00008 #include <unistd.h>
00009 #include <error.h>
00010 
00011 static void
00012 print_maps (void)
00013 {
00014 #if 0
00015   char *cmd = NULL;
00016   asprintf (&cmd, "cat /proc/%d/maps", getpid ());
00017   system (cmd);
00018   free (cmd);
00019 #endif
00020 }
00021 
00022 static void deeper (void (*f) (void));
00023 
00024 #if USE_PTHREADS
00025 # include <pthread.h>
00026 
00027 static void *
00028 tryme_thread (void *f)
00029 {
00030   (*((void (*) (void)) f)) ();
00031 
00032   return 0;
00033 }
00034 
00035 static pthread_barrier_t startup_barrier, go_barrier;
00036 static void *
00037 waiter_thread (void *arg)
00038 {
00039   void **f = arg;
00040   pthread_barrier_wait (&startup_barrier);
00041   pthread_barrier_wait (&go_barrier);
00042 
00043   (*((void (*) (void)) *f)) ();
00044 
00045   return 0;
00046 }
00047 #endif
00048 
00049 
00050 static bool allow_execstack = true;
00051 
00052 
00053 static int
00054 do_test (void)
00055 {
00056   /* Check whether SELinux is enabled and disallows executable stacks.  */
00057   FILE *fp = fopen ("/selinux/enforce", "r");
00058   if (fp != NULL)
00059     {
00060       char *line = NULL;
00061       size_t linelen = 0;
00062 
00063       bool enabled = false;
00064       ssize_t n = getline (&line, &linelen, fp);
00065       if (n > 0 && line[0] != '0')
00066        enabled = true;
00067 
00068       fclose (fp);
00069 
00070       if (enabled)
00071        {
00072          fp = fopen ("/selinux/booleans/allow_execstack", "r");
00073          if (fp != NULL)
00074            {
00075              n = getline (&line, &linelen, fp);
00076              if (n > 0 && line[0] == '0')
00077               allow_execstack = false;
00078            }
00079 
00080          fclose (fp);
00081        }
00082     }
00083 
00084   printf ("executable stacks %sallowed\n", allow_execstack ? "" : "not ");
00085 
00086   static void *f;           /* Address of this is used in other threads. */
00087 
00088 #if USE_PTHREADS
00089   /* Create some threads while stacks are nonexecutable.  */
00090   #define N 5
00091   pthread_t thr[N];
00092 
00093   pthread_barrier_init (&startup_barrier, NULL, N + 1);
00094   pthread_barrier_init (&go_barrier, NULL, N + 1);
00095 
00096   for (int i = 0; i < N; ++i)
00097     {
00098       int rc = pthread_create (&thr[i], NULL, &waiter_thread, &f);
00099       if (rc)
00100        error (1, rc, "pthread_create");
00101     }
00102 
00103   /* Make sure they are all there using their stacks.  */
00104   pthread_barrier_wait (&startup_barrier);
00105   puts ("threads waiting");
00106 #endif
00107 
00108   print_maps ();
00109 
00110   /* Loading this module should force stacks to become executable.  */
00111   void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
00112   if (h == NULL)
00113     {
00114       printf ("cannot load: %s\n", dlerror ());
00115       return allow_execstack;
00116     }
00117 
00118   f = dlsym (h, "tryme");
00119   if (f == NULL)
00120     {
00121       printf ("symbol not found: %s\n", dlerror ());
00122       return 1;
00123     }
00124 
00125   /* Test if that really made our stack executable.
00126      The `tryme' function should crash if not.  */
00127 
00128   (*((void (*) (void)) f)) ();
00129 
00130   print_maps ();
00131 
00132   /* Test that growing the stack region gets new executable pages too.  */
00133   deeper ((void (*) (void)) f);
00134 
00135   print_maps ();
00136 
00137 #if USE_PTHREADS
00138   /* Test that a fresh thread now gets an executable stack.  */
00139   {
00140     pthread_t th;
00141     int rc = pthread_create (&th, NULL, &tryme_thread, f);
00142     if (rc)
00143       error (1, rc, "pthread_create");
00144   }
00145 
00146   puts ("threads go");
00147   /* The existing threads' stacks should have been changed.
00148      Let them run to test it.  */
00149   pthread_barrier_wait (&go_barrier);
00150 
00151   pthread_exit (! allow_execstack);
00152 #endif
00153 
00154   return ! allow_execstack;
00155 }
00156 
00157 static void
00158 deeper (void (*f) (void))
00159 {
00160   char stack[1100 * 1024];
00161   memfrob (stack, sizeof stack);
00162   (*f) ();
00163   memfrob (stack, sizeof stack);
00164 }
00165 
00166 
00167 #define TEST_FUNCTION do_test ()
00168 #include "../test-skeleton.c"