1 /* Verify longjmp fortify checking does not reject signal stacks.  */
2 #include <assert.h>
3 #include <setjmp.h>
4 #include <signal.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/types.h>
9 #include <sys/time.h>
10 #include <sys/resource.h>
11 #include <unistd.h>
12 
13 static int do_test (void);
14 #define TEST_FUNCTION do_test ()
15 #include "../test-skeleton.c"
16 
17 static jmp_buf mainloop;
18 static sigset_t mainsigset;
19 static volatile sig_atomic_t pass;
20 
21 static void
write_indented(const char * str)22 write_indented (const char *str)
23 {
24   for (int i = 0; i < pass; ++i)
25     write_message (" ");
26   write_message (str);
27 }
28 
29 static void
stackoverflow_handler(int sig)30 stackoverflow_handler (int sig)
31 {
32   stack_t altstack;
33   /* Sanity check to keep test from looping forever (in case the longjmp
34      chk code is slightly broken).  */
35   pass++;
36   sigaltstack (NULL, &altstack);
37   write_indented ("in signal handler\n");
38   if (altstack.ss_flags & SS_ONSTACK)
39     write_indented ("on alternate stack\n");
40   siglongjmp (mainloop, pass);
41 }
42 
43 
44 static volatile int *
recurse_1(int n,volatile int * p)45 recurse_1 (int n, volatile int *p)
46 {
47   if (n >= 0)
48     *recurse_1 (n + 1, p) += n;
49   return p;
50 }
51 
52 
53 static int
recurse(int n)54 recurse (int n)
55 {
56   int sum = 0;
57   return *recurse_1 (n, &sum);
58 }
59 
60 
61 static int
do_test(void)62 do_test (void)
63 {
64   char mystack[SIGSTKSZ];
65   stack_t altstack;
66   struct sigaction action;
67   sigset_t emptyset;
68   /* Before starting the endless recursion, try to be friendly to the user's
69      machine.  On some Linux 2.2.x systems, there is no stack limit for user
70      processes at all.  We don't want to kill such systems.  */
71   struct rlimit rl;
72   rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
73   setrlimit (RLIMIT_STACK, &rl);
74   /* Install the alternate stack.  */
75   altstack.ss_sp = mystack;
76   altstack.ss_size = sizeof (mystack);
77   altstack.ss_flags = 0; /* no SS_DISABLE */
78   if (sigaltstack (&altstack, NULL) < 0)
79     {
80       puts ("first sigaltstack failed");
81       return 0;
82     }
83   /* Install the SIGSEGV handler.  */
84   sigemptyset (&action.sa_mask);
85   action.sa_handler = &stackoverflow_handler;
86   action.sa_flags = SA_ONSTACK;
87   sigaction (SIGSEGV, &action, (struct sigaction *) NULL);
88   sigaction (SIGBUS, &action, (struct sigaction *) NULL);
89 
90   /* Save the current signal mask.  */
91   sigemptyset (&emptyset);
92   sigprocmask (SIG_BLOCK, &emptyset, &mainsigset);
93 
94   /* Provoke two stack overflows in a row.  */
95   if (sigsetjmp (mainloop, 1) != 0)
96     {
97       assert (pass != 0);
98       printf ("%*sout of signal handler\n", pass, "");
99     }
100   else
101     assert (pass == 0);
102 
103   sigaltstack (NULL, &altstack);
104   if (altstack.ss_flags & SS_ONSTACK)
105     printf ("%*son alternate stack\n", pass, "");
106   else
107     printf ("%*snot on alternate stack\n", pass, "");
108 
109   if (pass < 2)
110     {
111       recurse (0);
112       puts ("recurse call returned");
113       return 2;
114     }
115 
116   altstack.ss_flags |= SS_DISABLE;
117   if (sigaltstack (&altstack, NULL) == -1)
118     printf ("disabling alternate stack failed\n");
119   else
120     printf ("disabling alternate stack succeeded \n");
121 
122   /* Restore the signal handlers, in case we trigger a crash after the
123      tests above.  */
124   signal (SIGBUS, SIG_DFL);
125   signal (SIGSEGV, SIG_DFL);
126 
127   return 0;
128 }
129