Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
glibc/debug/tst-longjmp_chk2.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
119 lines (101 sloc)
2.87 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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" |