xref: /aosp_15_r20/external/ltp/testcases/cve/stack_clash.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2017 Pavel Boldin <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2023 Rick Edgecombe <[email protected]>
5*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) Linux Test Project, 2017-2023
6*49cdfc7eSAndroid Build Coastguard Worker  */
7*49cdfc7eSAndroid Build Coastguard Worker 
8*49cdfc7eSAndroid Build Coastguard Worker /*\
9*49cdfc7eSAndroid Build Coastguard Worker  * [Description]
10*49cdfc7eSAndroid Build Coastguard Worker  *
11*49cdfc7eSAndroid Build Coastguard Worker  * This is a regression test of the Stack Clash [1] vulnerability. This tests
12*49cdfc7eSAndroid Build Coastguard Worker  * that there is at least 256 PAGE_SIZE of stack guard gap which is considered
13*49cdfc7eSAndroid Build Coastguard Worker  * hard to hop above. Code adapted from the Novell's bugzilla [2].
14*49cdfc7eSAndroid Build Coastguard Worker  *
15*49cdfc7eSAndroid Build Coastguard Worker  * The code `mmap(2)`s region close to the stack end. The code then allocates
16*49cdfc7eSAndroid Build Coastguard Worker  * memory on stack until it hits guard page and SIGSEGV or SIGBUS is generated
17*49cdfc7eSAndroid Build Coastguard Worker  * by the kernel. The signal handler checks that fault address is further than
18*49cdfc7eSAndroid Build Coastguard Worker  * THRESHOLD from the mmapped area.
19*49cdfc7eSAndroid Build Coastguard Worker  *
20*49cdfc7eSAndroid Build Coastguard Worker  * We read /proc/self/maps to examine exact top of the stack and `mmap(2)`
21*49cdfc7eSAndroid Build Coastguard Worker  * our region exactly GAP_PAGES * PAGE_SIZE away. We read /proc/cmdline to
22*49cdfc7eSAndroid Build Coastguard Worker  * see if a different stack_guard_gap size is configured. We set stack limit
23*49cdfc7eSAndroid Build Coastguard Worker  * to infinity and preallocate REQ_STACK_SIZE bytes of stack so that no calls
24*49cdfc7eSAndroid Build Coastguard Worker  * after `mmap` are moving stack further.
25*49cdfc7eSAndroid Build Coastguard Worker  *
26*49cdfc7eSAndroid Build Coastguard Worker  * If the architecture meets certain requirements (only x86_64 is verified)
27*49cdfc7eSAndroid Build Coastguard Worker  * then the test also tests that new mmap()s can't be placed in the stack's
28*49cdfc7eSAndroid Build Coastguard Worker  * guard gap. This part of the test works by forcing a bottom up search. The
29*49cdfc7eSAndroid Build Coastguard Worker  * assumptions are that the stack grows down (start gap) and either:
30*49cdfc7eSAndroid Build Coastguard Worker  *
31*49cdfc7eSAndroid Build Coastguard Worker  * 1. The default search is top down, and will switch to bottom up if
32*49cdfc7eSAndroid Build Coastguard Worker  *      space is exhausted.
33*49cdfc7eSAndroid Build Coastguard Worker  * 2. The default search is bottom up and the stack is above mmap base.
34*49cdfc7eSAndroid Build Coastguard Worker  *
35*49cdfc7eSAndroid Build Coastguard Worker  * [1] https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash
36*49cdfc7eSAndroid Build Coastguard Worker  * [2] https://bugzilla.novell.com/show_bug.cgi?id=CVE-2017-1000364
37*49cdfc7eSAndroid Build Coastguard Worker  */
38*49cdfc7eSAndroid Build Coastguard Worker 
39*49cdfc7eSAndroid Build Coastguard Worker #include <sys/wait.h>
40*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
41*49cdfc7eSAndroid Build Coastguard Worker #include <unistd.h>
42*49cdfc7eSAndroid Build Coastguard Worker #include <alloca.h>
43*49cdfc7eSAndroid Build Coastguard Worker #include <signal.h>
44*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
45*49cdfc7eSAndroid Build Coastguard Worker 
46*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
47*49cdfc7eSAndroid Build Coastguard Worker #include "tst_kconfig.h"
48*49cdfc7eSAndroid Build Coastguard Worker #include "tst_safe_stdio.h"
49*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/mmap.h"
50*49cdfc7eSAndroid Build Coastguard Worker 
51*49cdfc7eSAndroid Build Coastguard Worker static unsigned long page_size;
52*49cdfc7eSAndroid Build Coastguard Worker static unsigned long page_mask;
53*49cdfc7eSAndroid Build Coastguard Worker static unsigned long GAP_PAGES = 256;
54*49cdfc7eSAndroid Build Coastguard Worker static unsigned long THRESHOLD;
55*49cdfc7eSAndroid Build Coastguard Worker static int STACK_GROWSDOWN;
56*49cdfc7eSAndroid Build Coastguard Worker 
57*49cdfc7eSAndroid Build Coastguard Worker #define SIGNAL_STACK_SIZE	(1UL<<20)
58*49cdfc7eSAndroid Build Coastguard Worker #define FRAME_SIZE		1024
59*49cdfc7eSAndroid Build Coastguard Worker #define REQ_STACK_SIZE		(1024 * 1024)
60*49cdfc7eSAndroid Build Coastguard Worker 
61*49cdfc7eSAndroid Build Coastguard Worker #define EXIT_TESTBROKE		TBROK
62*49cdfc7eSAndroid Build Coastguard Worker 
exhaust_stack_into_sigsegv(void)63*49cdfc7eSAndroid Build Coastguard Worker void exhaust_stack_into_sigsegv(void)
64*49cdfc7eSAndroid Build Coastguard Worker {
65*49cdfc7eSAndroid Build Coastguard Worker 	volatile char * ptr = alloca(FRAME_SIZE - sizeof(long));
66*49cdfc7eSAndroid Build Coastguard Worker 	*ptr = '\0';
67*49cdfc7eSAndroid Build Coastguard Worker 	exhaust_stack_into_sigsegv();
68*49cdfc7eSAndroid Build Coastguard Worker }
69*49cdfc7eSAndroid Build Coastguard Worker 
70*49cdfc7eSAndroid Build Coastguard Worker #define MAPPED_LEN page_size
71*49cdfc7eSAndroid Build Coastguard Worker static unsigned long mapped_addr;
72*49cdfc7eSAndroid Build Coastguard Worker 
segv_handler(int sig,siginfo_t * info,void * data LTP_ATTRIBUTE_UNUSED)73*49cdfc7eSAndroid Build Coastguard Worker void segv_handler(int sig, siginfo_t *info, void *data LTP_ATTRIBUTE_UNUSED)
74*49cdfc7eSAndroid Build Coastguard Worker {
75*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long fault_addr = (unsigned long)info->si_addr;
76*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long mmap_end = mapped_addr + MAPPED_LEN;
77*49cdfc7eSAndroid Build Coastguard Worker 	ssize_t diff;
78*49cdfc7eSAndroid Build Coastguard Worker 
79*49cdfc7eSAndroid Build Coastguard Worker 	if (sig != SIGSEGV && sig != SIGBUS)
80*49cdfc7eSAndroid Build Coastguard Worker 		return;
81*49cdfc7eSAndroid Build Coastguard Worker 
82*49cdfc7eSAndroid Build Coastguard Worker 	if (STACK_GROWSDOWN)
83*49cdfc7eSAndroid Build Coastguard Worker 		diff = fault_addr - mmap_end;
84*49cdfc7eSAndroid Build Coastguard Worker 	else
85*49cdfc7eSAndroid Build Coastguard Worker 		diff = mapped_addr - fault_addr;
86*49cdfc7eSAndroid Build Coastguard Worker 
87*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO,
88*49cdfc7eSAndroid Build Coastguard Worker 		"mmap = [%lx, %lx), addr = %lx, diff = %zx, THRESHOLD = %lx",
89*49cdfc7eSAndroid Build Coastguard Worker 		mapped_addr, mmap_end, fault_addr, diff, THRESHOLD);
90*49cdfc7eSAndroid Build Coastguard Worker 	if (diff < 0 || (unsigned long)diff < THRESHOLD)
91*49cdfc7eSAndroid Build Coastguard Worker 		_exit(EXIT_FAILURE);
92*49cdfc7eSAndroid Build Coastguard Worker 	else
93*49cdfc7eSAndroid Build Coastguard Worker 		_exit(EXIT_SUCCESS);
94*49cdfc7eSAndroid Build Coastguard Worker }
95*49cdfc7eSAndroid Build Coastguard Worker 
96*49cdfc7eSAndroid Build Coastguard Worker #ifdef __x86_64__
force_bottom_up(void)97*49cdfc7eSAndroid Build Coastguard Worker static void force_bottom_up(void)
98*49cdfc7eSAndroid Build Coastguard Worker {
99*49cdfc7eSAndroid Build Coastguard Worker 	FILE *fh;
100*49cdfc7eSAndroid Build Coastguard Worker 	char buf[1024];
101*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long start, end, size, lastend = 0;
102*49cdfc7eSAndroid Build Coastguard Worker 
103*49cdfc7eSAndroid Build Coastguard Worker 	/* start filling from mmap_min_addr */
104*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_SCANF("/proc/sys/vm/mmap_min_addr", "%lu", &lastend);
105*49cdfc7eSAndroid Build Coastguard Worker 
106*49cdfc7eSAndroid Build Coastguard Worker 	fh = SAFE_FOPEN("/proc/self/maps", "r");
107*49cdfc7eSAndroid Build Coastguard Worker 
108*49cdfc7eSAndroid Build Coastguard Worker 	while (!feof(fh)) {
109*49cdfc7eSAndroid Build Coastguard Worker 		if (fgets(buf, sizeof(buf), fh) == NULL)
110*49cdfc7eSAndroid Build Coastguard Worker 			goto out;
111*49cdfc7eSAndroid Build Coastguard Worker 
112*49cdfc7eSAndroid Build Coastguard Worker 		if (sscanf(buf, "%lx-%lx", &start, &end) != 2) {
113*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK | TERRNO, "sscanf");
114*49cdfc7eSAndroid Build Coastguard Worker 			goto out;
115*49cdfc7eSAndroid Build Coastguard Worker 		}
116*49cdfc7eSAndroid Build Coastguard Worker 
117*49cdfc7eSAndroid Build Coastguard Worker 		size = start - lastend;
118*49cdfc7eSAndroid Build Coastguard Worker 
119*49cdfc7eSAndroid Build Coastguard Worker 		/* Skip the PROT_NONE that was just added (!size). */
120*49cdfc7eSAndroid Build Coastguard Worker 		if (!size) {
121*49cdfc7eSAndroid Build Coastguard Worker 			lastend = end;
122*49cdfc7eSAndroid Build Coastguard Worker 			continue;
123*49cdfc7eSAndroid Build Coastguard Worker 		}
124*49cdfc7eSAndroid Build Coastguard Worker 
125*49cdfc7eSAndroid Build Coastguard Worker 		/* If the next area is the stack, quit. */
126*49cdfc7eSAndroid Build Coastguard Worker 		if (!!strstr(buf, "[stack]"))
127*49cdfc7eSAndroid Build Coastguard Worker 			break;
128*49cdfc7eSAndroid Build Coastguard Worker 
129*49cdfc7eSAndroid Build Coastguard Worker 		/* This is not cleaned up. */
130*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_MMAP((void *)lastend, size, PROT_NONE,
131*49cdfc7eSAndroid Build Coastguard Worker 			  MAP_ANON|MAP_PRIVATE|MAP_FIXED_NOREPLACE, -1, 0);
132*49cdfc7eSAndroid Build Coastguard Worker 
133*49cdfc7eSAndroid Build Coastguard Worker 		lastend = end;
134*49cdfc7eSAndroid Build Coastguard Worker 	}
135*49cdfc7eSAndroid Build Coastguard Worker 
136*49cdfc7eSAndroid Build Coastguard Worker out:
137*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FCLOSE(fh);
138*49cdfc7eSAndroid Build Coastguard Worker }
139*49cdfc7eSAndroid Build Coastguard Worker #endif
140*49cdfc7eSAndroid Build Coastguard Worker 
read_stack_addr_from_proc(unsigned long * stack_size)141*49cdfc7eSAndroid Build Coastguard Worker unsigned long read_stack_addr_from_proc(unsigned long *stack_size)
142*49cdfc7eSAndroid Build Coastguard Worker {
143*49cdfc7eSAndroid Build Coastguard Worker 	FILE *fh;
144*49cdfc7eSAndroid Build Coastguard Worker 	char buf[1024];
145*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long stack_top = -1UL, start, end;
146*49cdfc7eSAndroid Build Coastguard Worker 
147*49cdfc7eSAndroid Build Coastguard Worker 	fh = SAFE_FOPEN("/proc/self/maps", "r");
148*49cdfc7eSAndroid Build Coastguard Worker 
149*49cdfc7eSAndroid Build Coastguard Worker 	while (!feof(fh)) {
150*49cdfc7eSAndroid Build Coastguard Worker 		if (fgets(buf, sizeof(buf), fh) == NULL) {
151*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK | TERRNO, "fgets");
152*49cdfc7eSAndroid Build Coastguard Worker 			goto out;
153*49cdfc7eSAndroid Build Coastguard Worker 		}
154*49cdfc7eSAndroid Build Coastguard Worker 
155*49cdfc7eSAndroid Build Coastguard Worker 		if (!strstr(buf, "[stack"))
156*49cdfc7eSAndroid Build Coastguard Worker 			continue;
157*49cdfc7eSAndroid Build Coastguard Worker 
158*49cdfc7eSAndroid Build Coastguard Worker 		if (sscanf(buf, "%lx-%lx", &start, &end) != 2) {
159*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK | TERRNO, "sscanf");
160*49cdfc7eSAndroid Build Coastguard Worker 			goto out;
161*49cdfc7eSAndroid Build Coastguard Worker 		}
162*49cdfc7eSAndroid Build Coastguard Worker 
163*49cdfc7eSAndroid Build Coastguard Worker 		*stack_size = end - start;
164*49cdfc7eSAndroid Build Coastguard Worker 
165*49cdfc7eSAndroid Build Coastguard Worker 		if (STACK_GROWSDOWN)
166*49cdfc7eSAndroid Build Coastguard Worker 			stack_top = start;
167*49cdfc7eSAndroid Build Coastguard Worker 		else
168*49cdfc7eSAndroid Build Coastguard Worker 			stack_top = end;
169*49cdfc7eSAndroid Build Coastguard Worker 		break;
170*49cdfc7eSAndroid Build Coastguard Worker 	}
171*49cdfc7eSAndroid Build Coastguard Worker 
172*49cdfc7eSAndroid Build Coastguard Worker out:
173*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FCLOSE(fh);
174*49cdfc7eSAndroid Build Coastguard Worker 	return stack_top;
175*49cdfc7eSAndroid Build Coastguard Worker }
176*49cdfc7eSAndroid Build Coastguard Worker 
dump_proc_self_maps(void)177*49cdfc7eSAndroid Build Coastguard Worker void dump_proc_self_maps(void)
178*49cdfc7eSAndroid Build Coastguard Worker {
179*49cdfc7eSAndroid Build Coastguard Worker 	static char buf[64];
180*49cdfc7eSAndroid Build Coastguard Worker 	static const char *cmd[] = {"cat", buf, NULL};
181*49cdfc7eSAndroid Build Coastguard Worker 	sprintf(buf, "/proc/%d/maps", getpid());
182*49cdfc7eSAndroid Build Coastguard Worker 	tst_cmd(cmd, NULL, NULL, 0);
183*49cdfc7eSAndroid Build Coastguard Worker }
184*49cdfc7eSAndroid Build Coastguard Worker 
preallocate_stack(unsigned long required)185*49cdfc7eSAndroid Build Coastguard Worker void __attribute__((noinline)) preallocate_stack(unsigned long required)
186*49cdfc7eSAndroid Build Coastguard Worker {
187*49cdfc7eSAndroid Build Coastguard Worker 	volatile char *garbage;
188*49cdfc7eSAndroid Build Coastguard Worker 
189*49cdfc7eSAndroid Build Coastguard Worker 	garbage = alloca(required);
190*49cdfc7eSAndroid Build Coastguard Worker 	garbage[0] = garbage[required - 1] = '\0';
191*49cdfc7eSAndroid Build Coastguard Worker }
192*49cdfc7eSAndroid Build Coastguard Worker 
193*49cdfc7eSAndroid Build Coastguard Worker #ifdef __x86_64__
do_mmap_placement_test(unsigned long stack_addr,unsigned long gap)194*49cdfc7eSAndroid Build Coastguard Worker static void do_mmap_placement_test(unsigned long stack_addr, unsigned long gap)
195*49cdfc7eSAndroid Build Coastguard Worker {
196*49cdfc7eSAndroid Build Coastguard Worker 	void *map_test_gap;
197*49cdfc7eSAndroid Build Coastguard Worker 
198*49cdfc7eSAndroid Build Coastguard Worker 	force_bottom_up();
199*49cdfc7eSAndroid Build Coastguard Worker 
200*49cdfc7eSAndroid Build Coastguard Worker 	/*
201*49cdfc7eSAndroid Build Coastguard Worker 	 * force_bottom_up() used up all the spaces below the stack. The search down
202*49cdfc7eSAndroid Build Coastguard Worker 	 * path should fail, and search up might take a look at the guard gap
203*49cdfc7eSAndroid Build Coastguard Worker 	 * region. If it avoids it, the allocation will be above the stack. If it
204*49cdfc7eSAndroid Build Coastguard Worker 	 * uses it, the allocation will be in the gap and the test should fail.
205*49cdfc7eSAndroid Build Coastguard Worker 	 */
206*49cdfc7eSAndroid Build Coastguard Worker 	map_test_gap = SAFE_MMAP(0, MAPPED_LEN,
207*49cdfc7eSAndroid Build Coastguard Worker 				 PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
208*49cdfc7eSAndroid Build Coastguard Worker 
209*49cdfc7eSAndroid Build Coastguard Worker 	if (stack_addr - gap <= (unsigned long)map_test_gap &&
210*49cdfc7eSAndroid Build Coastguard Worker 		(unsigned long)map_test_gap <= stack_addr) {
211*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "New mmap was placed in the guard gap.");
212*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_MUNMAP(map_test_gap, MAPPED_LEN);
213*49cdfc7eSAndroid Build Coastguard Worker 	}
214*49cdfc7eSAndroid Build Coastguard Worker }
215*49cdfc7eSAndroid Build Coastguard Worker #endif
216*49cdfc7eSAndroid Build Coastguard Worker 
do_child(void)217*49cdfc7eSAndroid Build Coastguard Worker void do_child(void)
218*49cdfc7eSAndroid Build Coastguard Worker {
219*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long stack_addr, stack_size;
220*49cdfc7eSAndroid Build Coastguard Worker 	stack_t signal_stack;
221*49cdfc7eSAndroid Build Coastguard Worker 	struct sigaction segv_sig = {.sa_sigaction = segv_handler, .sa_flags = SA_ONSTACK|SA_SIGINFO};
222*49cdfc7eSAndroid Build Coastguard Worker 	void *map;
223*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long gap = GAP_PAGES * page_size;
224*49cdfc7eSAndroid Build Coastguard Worker 	struct rlimit rlimit;
225*49cdfc7eSAndroid Build Coastguard Worker 
226*49cdfc7eSAndroid Build Coastguard Worker 	rlimit.rlim_cur = rlimit.rlim_max = RLIM_INFINITY;
227*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_SETRLIMIT(RLIMIT_STACK, &rlimit);
228*49cdfc7eSAndroid Build Coastguard Worker 
229*49cdfc7eSAndroid Build Coastguard Worker 	preallocate_stack(REQ_STACK_SIZE);
230*49cdfc7eSAndroid Build Coastguard Worker 
231*49cdfc7eSAndroid Build Coastguard Worker 	stack_addr = read_stack_addr_from_proc(&stack_size);
232*49cdfc7eSAndroid Build Coastguard Worker 	if (stack_addr == -1UL) {
233*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "can't read stack top from /proc/self/maps");
234*49cdfc7eSAndroid Build Coastguard Worker 		return;
235*49cdfc7eSAndroid Build Coastguard Worker 	}
236*49cdfc7eSAndroid Build Coastguard Worker 
237*49cdfc7eSAndroid Build Coastguard Worker 	if (STACK_GROWSDOWN)
238*49cdfc7eSAndroid Build Coastguard Worker 		mapped_addr = stack_addr - gap - MAPPED_LEN;
239*49cdfc7eSAndroid Build Coastguard Worker 	else
240*49cdfc7eSAndroid Build Coastguard Worker 		mapped_addr = stack_addr + gap;
241*49cdfc7eSAndroid Build Coastguard Worker 
242*49cdfc7eSAndroid Build Coastguard Worker 	mapped_addr &= page_mask;
243*49cdfc7eSAndroid Build Coastguard Worker 	map = SAFE_MMAP((void *)mapped_addr, MAPPED_LEN,
244*49cdfc7eSAndroid Build Coastguard Worker 			PROT_READ|PROT_WRITE,
245*49cdfc7eSAndroid Build Coastguard Worker 			MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
246*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Stack:0x%lx+0x%lx mmap:%p+0x%lx",
247*49cdfc7eSAndroid Build Coastguard Worker 		stack_addr, stack_size, map, MAPPED_LEN);
248*49cdfc7eSAndroid Build Coastguard Worker 
249*49cdfc7eSAndroid Build Coastguard Worker 	signal_stack.ss_sp = SAFE_MALLOC(SIGNAL_STACK_SIZE);
250*49cdfc7eSAndroid Build Coastguard Worker 	signal_stack.ss_size = SIGNAL_STACK_SIZE;
251*49cdfc7eSAndroid Build Coastguard Worker 	signal_stack.ss_flags = 0;
252*49cdfc7eSAndroid Build Coastguard Worker 	if (sigaltstack(&signal_stack, NULL) == -1) {
253*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO, "sigaltstack");
254*49cdfc7eSAndroid Build Coastguard Worker 		return;
255*49cdfc7eSAndroid Build Coastguard Worker 	}
256*49cdfc7eSAndroid Build Coastguard Worker 	if (sigaction(SIGSEGV, &segv_sig, NULL) == -1 ||
257*49cdfc7eSAndroid Build Coastguard Worker 	    sigaction(SIGBUS,  &segv_sig, NULL) == -1) {
258*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO, "sigaction");
259*49cdfc7eSAndroid Build Coastguard Worker 		return;
260*49cdfc7eSAndroid Build Coastguard Worker 	}
261*49cdfc7eSAndroid Build Coastguard Worker 
262*49cdfc7eSAndroid Build Coastguard Worker #ifdef DEBUG
263*49cdfc7eSAndroid Build Coastguard Worker 	dump_proc_self_maps();
264*49cdfc7eSAndroid Build Coastguard Worker #endif
265*49cdfc7eSAndroid Build Coastguard Worker 
266*49cdfc7eSAndroid Build Coastguard Worker #ifdef __x86_64__
267*49cdfc7eSAndroid Build Coastguard Worker 	do_mmap_placement_test(stack_addr, gap);
268*49cdfc7eSAndroid Build Coastguard Worker #endif
269*49cdfc7eSAndroid Build Coastguard Worker 
270*49cdfc7eSAndroid Build Coastguard Worker 	/* Now see if it can grow too close to an adjacent region. */
271*49cdfc7eSAndroid Build Coastguard Worker 	exhaust_stack_into_sigsegv();
272*49cdfc7eSAndroid Build Coastguard Worker }
273*49cdfc7eSAndroid Build Coastguard Worker 
setup(void)274*49cdfc7eSAndroid Build Coastguard Worker void setup(void)
275*49cdfc7eSAndroid Build Coastguard Worker {
276*49cdfc7eSAndroid Build Coastguard Worker 	page_size = sysconf(_SC_PAGESIZE);
277*49cdfc7eSAndroid Build Coastguard Worker 	page_mask = ~(page_size - 1);
278*49cdfc7eSAndroid Build Coastguard Worker 
279*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_kcmdline_var params = TST_KCMDLINE_INIT("stack_guard_gap");
280*49cdfc7eSAndroid Build Coastguard Worker 	tst_kcmdline_parse(&params, 1);
281*49cdfc7eSAndroid Build Coastguard Worker 
282*49cdfc7eSAndroid Build Coastguard Worker 	if (params.found) {
283*49cdfc7eSAndroid Build Coastguard Worker 		GAP_PAGES= atol(params.value);
284*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "stack_guard_gap = %ld", GAP_PAGES);
285*49cdfc7eSAndroid Build Coastguard Worker 	}
286*49cdfc7eSAndroid Build Coastguard Worker 
287*49cdfc7eSAndroid Build Coastguard Worker 	THRESHOLD = (GAP_PAGES - 1) * page_size;
288*49cdfc7eSAndroid Build Coastguard Worker 
289*49cdfc7eSAndroid Build Coastguard Worker 	{
290*49cdfc7eSAndroid Build Coastguard Worker 		volatile int *a = alloca(128);
291*49cdfc7eSAndroid Build Coastguard Worker 
292*49cdfc7eSAndroid Build Coastguard Worker 		{
293*49cdfc7eSAndroid Build Coastguard Worker 			volatile int *b = alloca(128);
294*49cdfc7eSAndroid Build Coastguard Worker 
295*49cdfc7eSAndroid Build Coastguard Worker 			STACK_GROWSDOWN = a > b;
296*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TINFO, "STACK_GROWSDOWN = %d == %p > %p", STACK_GROWSDOWN, a, b);
297*49cdfc7eSAndroid Build Coastguard Worker 		}
298*49cdfc7eSAndroid Build Coastguard Worker 	}
299*49cdfc7eSAndroid Build Coastguard Worker }
300*49cdfc7eSAndroid Build Coastguard Worker 
stack_clash_test(void)301*49cdfc7eSAndroid Build Coastguard Worker void stack_clash_test(void)
302*49cdfc7eSAndroid Build Coastguard Worker {
303*49cdfc7eSAndroid Build Coastguard Worker 	int status;
304*49cdfc7eSAndroid Build Coastguard Worker 	pid_t pid;
305*49cdfc7eSAndroid Build Coastguard Worker 
306*49cdfc7eSAndroid Build Coastguard Worker 	pid = SAFE_FORK();
307*49cdfc7eSAndroid Build Coastguard Worker 	if (!pid) {
308*49cdfc7eSAndroid Build Coastguard Worker 		do_child();
309*49cdfc7eSAndroid Build Coastguard Worker 		exit(EXIT_TESTBROKE);
310*49cdfc7eSAndroid Build Coastguard Worker 		return;
311*49cdfc7eSAndroid Build Coastguard Worker 	}
312*49cdfc7eSAndroid Build Coastguard Worker 
313*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_WAITPID(pid, &status, 0);
314*49cdfc7eSAndroid Build Coastguard Worker 
315*49cdfc7eSAndroid Build Coastguard Worker 	if (WIFEXITED(status)) {
316*49cdfc7eSAndroid Build Coastguard Worker 		switch (WEXITSTATUS(status)) {
317*49cdfc7eSAndroid Build Coastguard Worker 		case EXIT_FAILURE:
318*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL, "stack is too close to the mmaped area");
319*49cdfc7eSAndroid Build Coastguard Worker 			return;
320*49cdfc7eSAndroid Build Coastguard Worker 		case EXIT_SUCCESS:
321*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TPASS, "stack is far enough from mmaped area");
322*49cdfc7eSAndroid Build Coastguard Worker 			return;
323*49cdfc7eSAndroid Build Coastguard Worker 		default:
324*49cdfc7eSAndroid Build Coastguard Worker 		case EXIT_TESTBROKE:
325*49cdfc7eSAndroid Build Coastguard Worker 			break;
326*49cdfc7eSAndroid Build Coastguard Worker 		}
327*49cdfc7eSAndroid Build Coastguard Worker 	}
328*49cdfc7eSAndroid Build Coastguard Worker 
329*49cdfc7eSAndroid Build Coastguard Worker 	tst_brk(TBROK, "Child %s", tst_strstatus(status));
330*49cdfc7eSAndroid Build Coastguard Worker }
331*49cdfc7eSAndroid Build Coastguard Worker 
332*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
333*49cdfc7eSAndroid Build Coastguard Worker 	.forks_child = 1,
334*49cdfc7eSAndroid Build Coastguard Worker 	.needs_root = 1,
335*49cdfc7eSAndroid Build Coastguard Worker 	.setup = setup,
336*49cdfc7eSAndroid Build Coastguard Worker 	.test_all = stack_clash_test,
337*49cdfc7eSAndroid Build Coastguard Worker 	.tags = (const struct tst_tag[]) {
338*49cdfc7eSAndroid Build Coastguard Worker 		{"CVE", "2017-1000364"},
339*49cdfc7eSAndroid Build Coastguard Worker 		{"linux-git", "58c5d0d6d522"},
340*49cdfc7eSAndroid Build Coastguard Worker 		{}
341*49cdfc7eSAndroid Build Coastguard Worker 	}
342*49cdfc7eSAndroid Build Coastguard Worker };
343