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