1*c9938a9dSMichael Ellerman // SPDX-License-Identifier: GPL-2.0
2*c9938a9dSMichael Ellerman /*
3*c9938a9dSMichael Ellerman * Test that signal delivery is able to expand the stack segment without
4*c9938a9dSMichael Ellerman * triggering a SEGV.
5*c9938a9dSMichael Ellerman *
6*c9938a9dSMichael Ellerman * Based on test code by Tom Lane.
7*c9938a9dSMichael Ellerman */
8*c9938a9dSMichael Ellerman
9*c9938a9dSMichael Ellerman #include <err.h>
10*c9938a9dSMichael Ellerman #include <stdio.h>
11*c9938a9dSMichael Ellerman #include <stdlib.h>
12*c9938a9dSMichael Ellerman #include <signal.h>
13*c9938a9dSMichael Ellerman #include <sys/types.h>
14*c9938a9dSMichael Ellerman #include <unistd.h>
15*c9938a9dSMichael Ellerman
16*c9938a9dSMichael Ellerman #include "../pmu/lib.h"
17*c9938a9dSMichael Ellerman #include "utils.h"
18*c9938a9dSMichael Ellerman
19*c9938a9dSMichael Ellerman #define _KB (1024)
20*c9938a9dSMichael Ellerman #define _MB (1024 * 1024)
21*c9938a9dSMichael Ellerman
22*c9938a9dSMichael Ellerman static char *stack_base_ptr;
23*c9938a9dSMichael Ellerman static char *stack_top_ptr;
24*c9938a9dSMichael Ellerman
25*c9938a9dSMichael Ellerman static volatile sig_atomic_t sig_occurred = 0;
26*c9938a9dSMichael Ellerman
sigusr1_handler(int signal_arg)27*c9938a9dSMichael Ellerman static void sigusr1_handler(int signal_arg)
28*c9938a9dSMichael Ellerman {
29*c9938a9dSMichael Ellerman sig_occurred = 1;
30*c9938a9dSMichael Ellerman }
31*c9938a9dSMichael Ellerman
consume_stack(unsigned int stack_size,union pipe write_pipe)32*c9938a9dSMichael Ellerman static int consume_stack(unsigned int stack_size, union pipe write_pipe)
33*c9938a9dSMichael Ellerman {
34*c9938a9dSMichael Ellerman char stack_cur;
35*c9938a9dSMichael Ellerman
36*c9938a9dSMichael Ellerman if ((stack_base_ptr - &stack_cur) < stack_size)
37*c9938a9dSMichael Ellerman return consume_stack(stack_size, write_pipe);
38*c9938a9dSMichael Ellerman else {
39*c9938a9dSMichael Ellerman stack_top_ptr = &stack_cur;
40*c9938a9dSMichael Ellerman
41*c9938a9dSMichael Ellerman FAIL_IF(notify_parent(write_pipe));
42*c9938a9dSMichael Ellerman
43*c9938a9dSMichael Ellerman while (!sig_occurred)
44*c9938a9dSMichael Ellerman barrier();
45*c9938a9dSMichael Ellerman }
46*c9938a9dSMichael Ellerman
47*c9938a9dSMichael Ellerman return 0;
48*c9938a9dSMichael Ellerman }
49*c9938a9dSMichael Ellerman
child(unsigned int stack_size,union pipe write_pipe)50*c9938a9dSMichael Ellerman static int child(unsigned int stack_size, union pipe write_pipe)
51*c9938a9dSMichael Ellerman {
52*c9938a9dSMichael Ellerman struct sigaction act;
53*c9938a9dSMichael Ellerman char stack_base;
54*c9938a9dSMichael Ellerman
55*c9938a9dSMichael Ellerman act.sa_handler = sigusr1_handler;
56*c9938a9dSMichael Ellerman sigemptyset(&act.sa_mask);
57*c9938a9dSMichael Ellerman act.sa_flags = 0;
58*c9938a9dSMichael Ellerman if (sigaction(SIGUSR1, &act, NULL) < 0)
59*c9938a9dSMichael Ellerman err(1, "sigaction");
60*c9938a9dSMichael Ellerman
61*c9938a9dSMichael Ellerman stack_base_ptr = (char *) (((size_t) &stack_base + 65535) & ~65535UL);
62*c9938a9dSMichael Ellerman
63*c9938a9dSMichael Ellerman FAIL_IF(consume_stack(stack_size, write_pipe));
64*c9938a9dSMichael Ellerman
65*c9938a9dSMichael Ellerman printf("size 0x%06x: OK, stack base %p top %p (%zx used)\n",
66*c9938a9dSMichael Ellerman stack_size, stack_base_ptr, stack_top_ptr,
67*c9938a9dSMichael Ellerman stack_base_ptr - stack_top_ptr);
68*c9938a9dSMichael Ellerman
69*c9938a9dSMichael Ellerman return 0;
70*c9938a9dSMichael Ellerman }
71*c9938a9dSMichael Ellerman
test_one_size(unsigned int stack_size)72*c9938a9dSMichael Ellerman static int test_one_size(unsigned int stack_size)
73*c9938a9dSMichael Ellerman {
74*c9938a9dSMichael Ellerman union pipe read_pipe, write_pipe;
75*c9938a9dSMichael Ellerman pid_t pid;
76*c9938a9dSMichael Ellerman
77*c9938a9dSMichael Ellerman FAIL_IF(pipe(read_pipe.fds) == -1);
78*c9938a9dSMichael Ellerman FAIL_IF(pipe(write_pipe.fds) == -1);
79*c9938a9dSMichael Ellerman
80*c9938a9dSMichael Ellerman pid = fork();
81*c9938a9dSMichael Ellerman if (pid == 0) {
82*c9938a9dSMichael Ellerman close(read_pipe.read_fd);
83*c9938a9dSMichael Ellerman close(write_pipe.write_fd);
84*c9938a9dSMichael Ellerman exit(child(stack_size, read_pipe));
85*c9938a9dSMichael Ellerman }
86*c9938a9dSMichael Ellerman
87*c9938a9dSMichael Ellerman close(read_pipe.write_fd);
88*c9938a9dSMichael Ellerman close(write_pipe.read_fd);
89*c9938a9dSMichael Ellerman FAIL_IF(sync_with_child(read_pipe, write_pipe));
90*c9938a9dSMichael Ellerman
91*c9938a9dSMichael Ellerman kill(pid, SIGUSR1);
92*c9938a9dSMichael Ellerman
93*c9938a9dSMichael Ellerman FAIL_IF(wait_for_child(pid));
94*c9938a9dSMichael Ellerman
95*c9938a9dSMichael Ellerman close(read_pipe.read_fd);
96*c9938a9dSMichael Ellerman close(write_pipe.write_fd);
97*c9938a9dSMichael Ellerman
98*c9938a9dSMichael Ellerman return 0;
99*c9938a9dSMichael Ellerman }
100*c9938a9dSMichael Ellerman
test(void)101*c9938a9dSMichael Ellerman int test(void)
102*c9938a9dSMichael Ellerman {
103*c9938a9dSMichael Ellerman unsigned int i, size;
104*c9938a9dSMichael Ellerman
105*c9938a9dSMichael Ellerman // Test with used stack from 1MB - 64K to 1MB + 64K
106*c9938a9dSMichael Ellerman // Increment by 64 to get more coverage of odd sizes
107*c9938a9dSMichael Ellerman for (i = 0; i < (128 * _KB); i += 64) {
108*c9938a9dSMichael Ellerman size = i + (1 * _MB) - (64 * _KB);
109*c9938a9dSMichael Ellerman FAIL_IF(test_one_size(size));
110*c9938a9dSMichael Ellerman }
111*c9938a9dSMichael Ellerman
112*c9938a9dSMichael Ellerman return 0;
113*c9938a9dSMichael Ellerman }
114*c9938a9dSMichael Ellerman
main(void)115*c9938a9dSMichael Ellerman int main(void)
116*c9938a9dSMichael Ellerman {
117*c9938a9dSMichael Ellerman return test_harness(test, "stack_expansion_signal");
118*c9938a9dSMichael Ellerman }
119