Blame debug/tst-longjmp_chk2.c

Packit 6c4009
/* Verify longjmp fortify checking does not reject signal stacks.
Packit 6c4009
Packit 6c4009
   Test case mostly written by Paolo Bonzini <pbonzini@redhat.com>.  */
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <setjmp.h>
Packit 6c4009
#include <signal.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/time.h>
Packit 6c4009
#include <sys/resource.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
Packit 6c4009
static int do_test (void);
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"
Packit 6c4009
Packit 6c4009
static jmp_buf mainloop;
Packit 6c4009
static sigset_t mainsigset;
Packit 6c4009
static volatile sig_atomic_t pass;
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
write_indented (const char *str)
Packit 6c4009
{
Packit 6c4009
  for (int i = 0; i < pass; ++i)
Packit 6c4009
    write_message (" ");
Packit 6c4009
  write_message (str);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
stackoverflow_handler (int sig)
Packit 6c4009
{
Packit 6c4009
  stack_t altstack;
Packit 6c4009
  /* Sanity check to keep test from looping forever (in case the longjmp
Packit 6c4009
     chk code is slightly broken).  */
Packit 6c4009
  pass++;
Packit 6c4009
  sigaltstack (NULL, &altstack);
Packit 6c4009
  write_indented ("in signal handler\n");
Packit 6c4009
  if (altstack.ss_flags & SS_ONSTACK)
Packit 6c4009
    write_indented ("on alternate stack\n");
Packit 6c4009
  siglongjmp (mainloop, pass);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static volatile int *
Packit 6c4009
recurse_1 (int n, volatile int *p)
Packit 6c4009
{
Packit 6c4009
  if (n >= 0)
Packit 6c4009
    *recurse_1 (n + 1, p) += n;
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
recurse (int n)
Packit 6c4009
{
Packit 6c4009
  int sum = 0;
Packit 6c4009
  return *recurse_1 (n, &sum);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  char mystack[SIGSTKSZ];
Packit 6c4009
  stack_t altstack;
Packit 6c4009
  struct sigaction action;
Packit 6c4009
  sigset_t emptyset;
Packit 6c4009
  /* Before starting the endless recursion, try to be friendly to the user's
Packit 6c4009
     machine.  On some Linux 2.2.x systems, there is no stack limit for user
Packit 6c4009
     processes at all.  We don't want to kill such systems.  */
Packit 6c4009
  struct rlimit rl;
Packit 6c4009
  rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
Packit 6c4009
  setrlimit (RLIMIT_STACK, &rl);
Packit 6c4009
  /* Install the alternate stack.  */
Packit 6c4009
  altstack.ss_sp = mystack;
Packit 6c4009
  altstack.ss_size = sizeof (mystack);
Packit 6c4009
  altstack.ss_flags = 0; /* no SS_DISABLE */
Packit 6c4009
  if (sigaltstack (&altstack, NULL) < 0)
Packit 6c4009
    {
Packit 6c4009
      puts ("first sigaltstack failed");
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
  /* Install the SIGSEGV handler.  */
Packit 6c4009
  sigemptyset (&action.sa_mask);
Packit 6c4009
  action.sa_handler = &stackoverflow_handler;
Packit 6c4009
  action.sa_flags = SA_ONSTACK;
Packit 6c4009
  sigaction (SIGSEGV, &action, (struct sigaction *) NULL);
Packit 6c4009
  sigaction (SIGBUS, &action, (struct sigaction *) NULL);
Packit 6c4009
Packit 6c4009
  /* Save the current signal mask.  */
Packit 6c4009
  sigemptyset (&emptyset);
Packit 6c4009
  sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
Packit 6c4009
Packit 6c4009
  /* Provoke two stack overflows in a row.  */
Packit 6c4009
  if (sigsetjmp (mainloop, 1) != 0)
Packit 6c4009
    {
Packit 6c4009
      assert (pass != 0);
Packit 6c4009
      printf ("%*sout of signal handler\n", pass, "");
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    assert (pass == 0);
Packit 6c4009
Packit 6c4009
  sigaltstack (NULL, &altstack);
Packit 6c4009
  if (altstack.ss_flags & SS_ONSTACK)
Packit 6c4009
    printf ("%*son alternate stack\n", pass, "");
Packit 6c4009
  else
Packit 6c4009
    printf ("%*snot on alternate stack\n", pass, "");
Packit 6c4009
Packit 6c4009
  if (pass < 2)
Packit 6c4009
    {
Packit 6c4009
      recurse (0);
Packit 6c4009
      puts ("recurse call returned");
Packit 6c4009
      return 2;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  altstack.ss_flags |= SS_DISABLE;
Packit 6c4009
  if (sigaltstack (&altstack, NULL) == -1)
Packit 6c4009
    printf ("disabling alternate stack failed\n");
Packit 6c4009
  else
Packit 6c4009
    printf ("disabling alternate stack succeeded \n");
Packit 6c4009
Packit 6c4009
  /* Restore the signal handlers, in case we trigger a crash after the
Packit 6c4009
     tests above.  */
Packit 6c4009
  signal (SIGBUS, SIG_DFL);
Packit 6c4009
  signal (SIGSEGV, SIG_DFL);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}