5896c8bdd9
If the longjmp checking code is slightly broken, this code can loop forever which isn't too helpful. Add a sanity check to keep that from happening. Signed-off-by: Mike Frysinger <vapier@gentoo.org>
120 lines
2.9 KiB
C
120 lines
2.9 KiB
C
/* Verify longjmp fortify checking does not reject signal stacks.
|
|
|
|
Test case mostly written by Paolo Bonzini <pbonzini@redhat.com>. */
|
|
#include <assert.h>
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
|
|
|
|
static jmp_buf mainloop;
|
|
static sigset_t mainsigset;
|
|
static int pass;
|
|
|
|
|
|
static void
|
|
stackoverflow_handler (int sig)
|
|
{
|
|
stack_t altstack;
|
|
/* Sanity check to keep test from looping forever (in case the longjmp
|
|
chk code is slightly broken). */
|
|
pass++;
|
|
assert (pass < 5);
|
|
sigaltstack (NULL, &altstack);
|
|
/* Using printf is not really kosher in signal handlers but we know
|
|
it will work. */
|
|
printf ("%*sin signal handler\n", pass, "");
|
|
if (altstack.ss_flags & SS_ONSTACK)
|
|
printf ("%*son alternate stack\n", pass, "");
|
|
siglongjmp (mainloop, pass);
|
|
}
|
|
|
|
|
|
static volatile int *
|
|
recurse_1 (int n, volatile int *p)
|
|
{
|
|
if (n >= 0)
|
|
*recurse_1 (n + 1, p) += n;
|
|
return p;
|
|
}
|
|
|
|
|
|
static int
|
|
recurse (int n)
|
|
{
|
|
int sum = 0;
|
|
return *recurse_1 (n, &sum);
|
|
}
|
|
|
|
|
|
static int
|
|
do_test (void)
|
|
{
|
|
char mystack[SIGSTKSZ];
|
|
stack_t altstack;
|
|
struct sigaction action;
|
|
sigset_t emptyset;
|
|
/* Before starting the endless recursion, try to be friendly to the user's
|
|
machine. On some Linux 2.2.x systems, there is no stack limit for user
|
|
processes at all. We don't want to kill such systems. */
|
|
struct rlimit rl;
|
|
rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
|
|
setrlimit (RLIMIT_STACK, &rl);
|
|
/* Install the alternate stack. */
|
|
altstack.ss_sp = mystack;
|
|
altstack.ss_size = sizeof (mystack);
|
|
altstack.ss_flags = 0; /* no SS_DISABLE */
|
|
if (sigaltstack (&altstack, NULL) < 0)
|
|
{
|
|
puts ("first sigaltstack failed");
|
|
return 0;
|
|
}
|
|
/* Install the SIGSEGV handler. */
|
|
sigemptyset (&action.sa_mask);
|
|
action.sa_handler = &stackoverflow_handler;
|
|
action.sa_flags = SA_ONSTACK;
|
|
sigaction (SIGSEGV, &action, (struct sigaction *) NULL);
|
|
sigaction (SIGBUS, &action, (struct sigaction *) NULL);
|
|
|
|
/* Save the current signal mask. */
|
|
sigemptyset (&emptyset);
|
|
sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
|
|
|
|
/* Provoke two stack overflows in a row. */
|
|
if (sigsetjmp (mainloop, 1) != 0)
|
|
{
|
|
assert (pass != 0);
|
|
printf ("%*sout of signal handler\n", pass, "");
|
|
}
|
|
else
|
|
assert (pass == 0);
|
|
|
|
sigaltstack (NULL, &altstack);
|
|
if (altstack.ss_flags & SS_ONSTACK)
|
|
printf ("%*son alternate stack\n", pass, "");
|
|
else
|
|
printf ("%*snot on alternate stack\n", pass, "");
|
|
|
|
if (pass < 2)
|
|
{
|
|
recurse (0);
|
|
puts ("recurse call returned");
|
|
return 2;
|
|
}
|
|
|
|
altstack.ss_flags |= SS_DISABLE;
|
|
if (sigaltstack (&altstack, NULL) == -1)
|
|
printf ("disabling alternate stack failed\n");
|
|
else
|
|
printf ("disabling alternate stack succeeded \n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define TEST_FUNCTION do_test ()
|
|
#include "../test-skeleton.c"
|