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 |
22 | write_indented (const char *str) |
23 | { |
24 | for (int i = 0; i < pass; ++i) |
25 | write_message (message: " " ); |
26 | write_message (message: str); |
27 | } |
28 | |
29 | static void |
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, oss: &altstack); |
37 | write_indented (str: "in signal handler\n" ); |
38 | if (altstack.ss_flags & SS_ONSTACK) |
39 | write_indented (str: "on alternate stack\n" ); |
40 | siglongjmp (env: mainloop, val: pass); |
41 | } |
42 | |
43 | |
44 | static volatile int * |
45 | recurse_1 (int n, volatile int *p) |
46 | { |
47 | if (n >= 0) |
48 | *recurse_1 (n: n + 1, p) += n; |
49 | return p; |
50 | } |
51 | |
52 | |
53 | static int |
54 | recurse (int n) |
55 | { |
56 | int sum = 0; |
57 | return *recurse_1 (n, p: &sum); |
58 | } |
59 | |
60 | |
61 | static int |
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, rlimits: &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 (ss: &altstack, NULL) < 0) |
79 | { |
80 | puts (s: "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, act: &action, oact: (struct sigaction *) NULL); |
88 | sigaction (SIGBUS, act: &action, oact: (struct sigaction *) NULL); |
89 | |
90 | /* Save the current signal mask. */ |
91 | sigemptyset (&emptyset); |
92 | sigprocmask (SIG_BLOCK, set: &emptyset, oset: &mainsigset); |
93 | |
94 | /* Provoke two stack overflows in a row. */ |
95 | if (sigsetjmp (mainloop, 1) != 0) |
96 | { |
97 | assert (pass != 0); |
98 | printf (format: "%*sout of signal handler\n" , pass, "" ); |
99 | } |
100 | else |
101 | assert (pass == 0); |
102 | |
103 | sigaltstack (NULL, oss: &altstack); |
104 | if (altstack.ss_flags & SS_ONSTACK) |
105 | printf (format: "%*son alternate stack\n" , pass, "" ); |
106 | else |
107 | printf (format: "%*snot on alternate stack\n" , pass, "" ); |
108 | |
109 | if (pass < 2) |
110 | { |
111 | recurse (n: 0); |
112 | puts (s: "recurse call returned" ); |
113 | return 2; |
114 | } |
115 | |
116 | altstack.ss_flags |= SS_DISABLE; |
117 | if (sigaltstack (ss: &altstack, NULL) == -1) |
118 | printf (format: "disabling alternate stack failed\n" ); |
119 | else |
120 | printf (format: "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 | |