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