Blame elf/tst-execstack.c

Packit Service 82fcde
/* Test program for making nonexecutable stacks executable
Packit Service 82fcde
   on load of a DSO that requires executable stacks.  */
Packit Service 82fcde
Packit Service 82fcde
#include <dlfcn.h>
Packit Service 82fcde
#include <stdbool.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <error.h>
Packit Service 82fcde
#include <stackinfo.h>
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
print_maps (void)
Packit Service 82fcde
{
Packit Service 82fcde
#if 0
Packit Service 82fcde
  char *cmd = NULL;
Packit Service 82fcde
  asprintf (&cmd, "cat /proc/%d/maps", getpid ());
Packit Service 82fcde
  system (cmd);
Packit Service 82fcde
  free (cmd);
Packit Service 82fcde
#endif
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void deeper (void (*f) (void));
Packit Service 82fcde
Packit Service 82fcde
#if USE_PTHREADS
Packit Service 82fcde
# include <pthread.h>
Packit Service 82fcde
Packit Service 82fcde
static void *
Packit Service 82fcde
tryme_thread (void *f)
Packit Service 82fcde
{
Packit Service 82fcde
  (*((void (*) (void)) f)) ();
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static pthread_barrier_t startup_barrier, go_barrier;
Packit Service 82fcde
static void *
Packit Service 82fcde
waiter_thread (void *arg)
Packit Service 82fcde
{
Packit Service 82fcde
  void **f = arg;
Packit Service 82fcde
  pthread_barrier_wait (&startup_barrier);
Packit Service 82fcde
  pthread_barrier_wait (&go_barrier);
Packit Service 82fcde
Packit Service 82fcde
  (*((void (*) (void)) *f)) ();
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
static bool allow_execstack = true;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_test (void)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Check whether SELinux is enabled and disallows executable stacks.  */
Packit Service 82fcde
  FILE *fp = fopen ("/selinux/enforce", "r");
Packit Service 82fcde
  if (fp != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      char *line = NULL;
Packit Service 82fcde
      size_t linelen = 0;
Packit Service 82fcde
Packit Service 82fcde
      bool enabled = false;
Packit Service 82fcde
      ssize_t n = getline (&line, &linelen, fp);
Packit Service 82fcde
      if (n > 0 && line[0] != '0')
Packit Service 82fcde
	enabled = true;
Packit Service 82fcde
Packit Service 82fcde
      fclose (fp);
Packit Service 82fcde
Packit Service 82fcde
      if (enabled)
Packit Service 82fcde
	{
Packit Service 82fcde
	  fp = fopen ("/selinux/booleans/allow_execstack", "r");
Packit Service 82fcde
	  if (fp != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      n = getline (&line, &linelen, fp);
Packit Service 82fcde
	      if (n > 0 && line[0] == '0')
Packit Service 82fcde
		allow_execstack = false;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  fclose (fp);
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  printf ("executable stacks %sallowed\n", allow_execstack ? "" : "not ");
Packit Service 82fcde
Packit Service 82fcde
  static void *f;		/* Address of this is used in other threads. */
Packit Service 82fcde
Packit Service 82fcde
#if USE_PTHREADS
Packit Service 82fcde
  /* Create some threads while stacks are nonexecutable.  */
Packit Service 82fcde
  #define N 5
Packit Service 82fcde
  pthread_t thr[N];
Packit Service 82fcde
Packit Service 82fcde
  pthread_barrier_init (&startup_barrier, NULL, N + 1);
Packit Service 82fcde
  pthread_barrier_init (&go_barrier, NULL, N + 1);
Packit Service 82fcde
Packit Service 82fcde
  for (int i = 0; i < N; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      int rc = pthread_create (&thr[i], NULL, &waiter_thread, &f);
Packit Service 82fcde
      if (rc)
Packit Service 82fcde
	error (1, rc, "pthread_create");
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Make sure they are all there using their stacks.  */
Packit Service 82fcde
  pthread_barrier_wait (&startup_barrier);
Packit Service 82fcde
  puts ("threads waiting");
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  print_maps ();
Packit Service 82fcde
Packit Service 82fcde
#if USE_PTHREADS
Packit Service 82fcde
  void *old_stack_addr, *new_stack_addr;
Packit Service 82fcde
  size_t stack_size;
Packit Service 82fcde
  pthread_t me = pthread_self ();
Packit Service 82fcde
  pthread_attr_t attr;
Packit Service 82fcde
  int ret = 0;
Packit Service 82fcde
Packit Service 82fcde
  ret = pthread_getattr_np (me, &attr);
Packit Service 82fcde
  if (ret)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("before execstack: pthread_getattr_np returned error: %s\n",
Packit Service 82fcde
	      strerror (ret));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  ret = pthread_attr_getstack (&attr, &old_stack_addr, &stack_size);
Packit Service 82fcde
  if (ret)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("before execstack: pthread_attr_getstack returned error: %s\n",
Packit Service 82fcde
	      strerror (ret));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
# if _STACK_GROWS_DOWN
Packit Service 82fcde
    old_stack_addr += stack_size;
Packit Service 82fcde
# else
Packit Service 82fcde
    old_stack_addr -= stack_size;
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Loading this module should force stacks to become executable.  */
Packit Service 82fcde
  void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
Packit Service 82fcde
  if (h == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("cannot load: %s\n", dlerror ());
Packit Service 82fcde
      return allow_execstack;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  f = dlsym (h, "tryme");
Packit Service 82fcde
  if (f == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("symbol not found: %s\n", dlerror ());
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Test if that really made our stack executable.
Packit Service 82fcde
     The `tryme' function should crash if not.  */
Packit Service 82fcde
Packit Service 82fcde
  (*((void (*) (void)) f)) ();
Packit Service 82fcde
Packit Service 82fcde
  print_maps ();
Packit Service 82fcde
Packit Service 82fcde
#if USE_PTHREADS
Packit Service 82fcde
  ret = pthread_getattr_np (me, &attr);
Packit Service 82fcde
  if (ret)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("after execstack: pthread_getattr_np returned error: %s\n",
Packit Service 82fcde
	      strerror (ret));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  ret = pthread_attr_getstack (&attr, &new_stack_addr, &stack_size);
Packit Service 82fcde
  if (ret)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("after execstack: pthread_attr_getstack returned error: %s\n",
Packit Service 82fcde
	      strerror (ret));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
# if _STACK_GROWS_DOWN
Packit Service 82fcde
    new_stack_addr += stack_size;
Packit Service 82fcde
# else
Packit Service 82fcde
    new_stack_addr -= stack_size;
Packit Service 82fcde
# endif
Packit Service 82fcde
Packit Service 82fcde
  /* It is possible that the dlopen'd module may have been mmapped just below
Packit Service 82fcde
     the stack.  The stack size is taken as MIN(stack rlimit size, end of last
Packit Service 82fcde
     vma) in pthread_getattr_np.  If rlimit is set high enough, it is possible
Packit Service 82fcde
     that the size may have changed.  A subsequent call to
Packit Service 82fcde
     pthread_attr_getstack returns the size and (bottom - size) as the
Packit Service 82fcde
     stacksize and stackaddr respectively.  If the size changes due to the
Packit Service 82fcde
     above, then both stacksize and stackaddr can change, but the stack bottom
Packit Service 82fcde
     should remain the same, which is computed as stackaddr + stacksize.  */
Packit Service 82fcde
  if (old_stack_addr != new_stack_addr)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("Stack end changed, old: %p, new: %p\n",
Packit Service 82fcde
	      old_stack_addr, new_stack_addr);
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  printf ("Stack address remains the same: %p\n", old_stack_addr);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  /* Test that growing the stack region gets new executable pages too.  */
Packit Service 82fcde
  deeper ((void (*) (void)) f);
Packit Service 82fcde
Packit Service 82fcde
  print_maps ();
Packit Service 82fcde
Packit Service 82fcde
#if USE_PTHREADS
Packit Service 82fcde
  /* Test that a fresh thread now gets an executable stack.  */
Packit Service 82fcde
  {
Packit Service 82fcde
    pthread_t th;
Packit Service 82fcde
    int rc = pthread_create (&th, NULL, &tryme_thread, f);
Packit Service 82fcde
    if (rc)
Packit Service 82fcde
      error (1, rc, "pthread_create");
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  puts ("threads go");
Packit Service 82fcde
  /* The existing threads' stacks should have been changed.
Packit Service 82fcde
     Let them run to test it.  */
Packit Service 82fcde
  pthread_barrier_wait (&go_barrier);
Packit Service 82fcde
Packit Service 82fcde
  pthread_exit ((void *) (long int) (! allow_execstack));
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  return ! allow_execstack;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
deeper (void (*f) (void))
Packit Service 82fcde
{
Packit Service 82fcde
  char stack[1100 * 1024];
Packit Service 82fcde
  memfrob (stack, sizeof stack);
Packit Service 82fcde
  (*f) ();
Packit Service 82fcde
  memfrob (stack, sizeof stack);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
#include <support/test-driver.c>