1#include <stdio.h>
2#include <strings.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <signal.h>
6#include <setjmp.h>
7#include <sys/mman.h>
8
9int test_func();
10void	catch_segv(int);
11jmp_buf resume;
12
13#define func_len	256
14
15#define ALT_STK_SIZE	(MINSIGSTKSZ + pagesize)
16
17#if __i386__
18typedef	unsigned int		psint_t;
19#endif
20#if __x86_64__
21typedef unsigned long long	psint_t;
22#endif
23
24int verbose = 0;
25
26#define msg(...)	do { if (verbose) printf(__VA_ARGS__); } while (0);
27
28/*
29 * Test whether the architecture allows execution from the stack and heap data areas.  What's
30 * allowed varies by architecture due to backwards compatibility.  We also run a separate test
31 * where we turn on PROT_EXEC explicitly which should always allow execution to take place.
32 *
33 * The "expected" array tells us what the result of each test should be based on the architecture.
34 * The code assumes the test numbers in the macros below are consecutive starting from 0.
35 */
36
37#define HEAP_TEST	0
38#define HEAP_PROT_EXEC	1
39#define STACK_TEST	2
40#define STACK_PROT_EXEC	3
41
42#define	SUCCEED	 1
43#define FAIL	-1	/* can't use 0 since setjmp uses that */
44
45int expected[4] = {
46#if NXDATA32TESTNONX
47	SUCCEED,		/* execute from heap */
48	SUCCEED,		/* exeucte from heap with PROT_EXEC */
49	FAIL,			/* execute from stack */
50	SUCCEED,		/* exeucte from stack with PROT_EXEC */
51#elif __i386__
52	FAIL,		/* execute from heap */
53	SUCCEED,		/* exeucte from heap with PROT_EXEC */
54	FAIL,			/* execute from stack */
55	SUCCEED,		/* exeucte from stack with PROT_EXEC */
56#endif
57#if __x86_64__
58	FAIL,			/* execute from heap */
59	SUCCEED,		/* exeucte from heap with PROT_EXEC */
60	FAIL,			/* execute from stack */
61	SUCCEED,		/* exeucte from stack with PROT_EXEC */
62#endif
63};
64
65
66int main(int argc, char *argv[])
67{
68	int (*func)();
69	int result, test;
70	char buf[func_len + 4];
71	psint_t base;
72	unsigned int len;
73	psint_t pagesize;
74	size_t	count;
75	stack_t sigstk;
76	struct sigaction sigact;
77	char *cmd_name;
78	int c;
79
80	cmd_name = argv[0];
81
82	while ((c = getopt(argc, argv, "v")) != -1) {
83		switch (c) {
84		case 'v':
85			verbose = 1;
86			break;
87
88		case '?':
89		default:
90			fprintf(stderr, "usage: data_exec [-v]\n");
91			exit(1);
92		}
93	}
94
95	pagesize = getpagesize();
96
97	sigstk.ss_sp = malloc(ALT_STK_SIZE);
98	sigstk.ss_size = ALT_STK_SIZE;
99	sigstk.ss_flags = 0;
100
101	if (sigaltstack(&sigstk, NULL) < 0) {
102		perror("sigaltstack");
103		exit(1);
104	}
105
106	sigact.sa_handler = catch_segv;
107	sigact.sa_flags = SA_ONSTACK;
108	sigemptyset(&sigact.sa_mask);
109
110	if (sigaction(SIGSEGV, &sigact, NULL) == -1) {
111		perror("sigaction SIGSEGV");
112		exit(1);
113	}
114
115        if (sigaction(SIGBUS, &sigact, NULL) == -1) {
116                perror("sigaction SIGBUS");
117                exit(1);
118        }
119
120	test = HEAP_TEST;
121
122restart:
123
124	if ((result = setjmp(resume)) != 0) {
125		if (result != expected[test]) {
126			printf("%s: test %d failed, expected %d, got %d\n", cmd_name, test, expected[test], result);
127			exit(2);
128		}
129
130		test++;
131		goto restart;
132	}
133
134	switch (test) {
135	case HEAP_TEST:
136		msg("attempting to execute from malloc'ed area..\n");
137
138		func = (void *)malloc(func_len);
139
140		func = (void *)((char *)func + ((psint_t)test_func & 0x3));
141
142		bcopy(test_func, func, func_len);
143
144		result = (*func)();
145		msg("execution suceeded, result is %d\n\n", result);
146		longjmp(resume, SUCCEED);
147
148	case HEAP_PROT_EXEC:
149		msg("attempting to execute from malloc'ed area with PROT_EXEC..\n");
150
151		func = (void *)malloc(func_len);
152
153		func = (void *)((char *)func + ((psint_t)test_func & 0x3));
154		bcopy(test_func, func, func_len);
155
156		base = (psint_t)func & ~(pagesize - 1);
157		len  = func_len + (psint_t)func - base;
158
159		if(mprotect((void *)base, len, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
160			perror("mprotect of stack");
161			exit(1);
162		}
163
164		result = (*func)();
165		msg("execution suceeded, result is %d\n\n", result);
166		longjmp(resume, SUCCEED);
167
168	case STACK_TEST:
169		msg("attempting to execute from stack...\n");
170
171		func = (void *)(buf + ((psint_t)test_func & 0x3));
172		bcopy(test_func, func, func_len);
173
174		result = (*func)();
175		msg("stack execution suceeded, result from stack exec is %d\n\n", result);
176		longjmp(resume, SUCCEED);
177
178	case STACK_PROT_EXEC:
179		msg("attempting to execute from stack with PROT_EXEC...\n");
180
181		func = (void *)(buf + ((psint_t)test_func & 0x3));
182		bcopy(test_func, func, func_len);
183
184		base = (psint_t)func & ~(pagesize - 1);
185		len  = func_len + (psint_t)func - base;
186
187		if(mprotect((void *)base, len, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
188			perror("mprotect of stack");
189			exit(1);
190		}
191
192		result = (*func)();
193		msg("stack execution suceeded, result from stack exec is %d\n", result);
194		longjmp(resume, SUCCEED);
195	}
196
197	msg("All tests passed.\n");
198	exit(0);
199}
200
201
202int
203test_func()
204{
205	return 42;
206}
207
208
209void
210catch_segv(int sig)
211{
212	msg("got sig %d\n\n", sig);
213	longjmp(resume, FAIL);
214}
215