]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/tst-execstack.c
Update copyright dates not handled by scripts/update-copyrights.
[thirdparty/glibc.git] / elf / tst-execstack.c
CommitLineData
2abf9ff1
RM
1/* Test program for making nonexecutable stacks executable
2 on load of a DSO that requires executable stacks. */
3
4#include <dlfcn.h>
d9961b6a 5#include <stdbool.h>
2abf9ff1
RM
6#include <stdio.h>
7#include <string.h>
8#include <unistd.h>
9#include <error.h>
9c6ea9fa 10#include <stackinfo.h>
2abf9ff1
RM
11
12static void
13print_maps (void)
14{
15#if 0
16 char *cmd = NULL;
17 asprintf (&cmd, "cat /proc/%d/maps", getpid ());
18 system (cmd);
19 free (cmd);
20#endif
21}
22
23static void deeper (void (*f) (void));
24
25#if USE_PTHREADS
26# include <pthread.h>
27
28static void *
29tryme_thread (void *f)
30{
31 (*((void (*) (void)) f)) ();
32
33 return 0;
34}
35
36static pthread_barrier_t startup_barrier, go_barrier;
37static void *
38waiter_thread (void *arg)
39{
40 void **f = arg;
41 pthread_barrier_wait (&startup_barrier);
42 pthread_barrier_wait (&go_barrier);
43
44 (*((void (*) (void)) *f)) ();
45
46 return 0;
47}
48#endif
49
d9961b6a
UD
50static bool allow_execstack = true;
51
52
2abf9ff1
RM
53static int
54do_test (void)
55{
d9961b6a
UD
56 /* Check whether SELinux is enabled and disallows executable stacks. */
57 FILE *fp = fopen ("/selinux/enforce", "r");
58 if (fp != NULL)
59 {
60 char *line = NULL;
61 size_t linelen = 0;
62
63 bool enabled = false;
64 ssize_t n = getline (&line, &linelen, fp);
65 if (n > 0 && line[0] != '0')
66 enabled = true;
67
68 fclose (fp);
69
70 if (enabled)
71 {
72 fp = fopen ("/selinux/booleans/allow_execstack", "r");
73 if (fp != NULL)
74 {
75 n = getline (&line, &linelen, fp);
76 if (n > 0 && line[0] == '0')
77 allow_execstack = false;
78 }
79
80 fclose (fp);
81 }
82 }
83
84 printf ("executable stacks %sallowed\n", allow_execstack ? "" : "not ");
85
26e059c1 86 static void *f; /* Address of this is used in other threads. */
2abf9ff1
RM
87
88#if USE_PTHREADS
89 /* Create some threads while stacks are nonexecutable. */
90 #define N 5
91 pthread_t thr[N];
92
93 pthread_barrier_init (&startup_barrier, NULL, N + 1);
94 pthread_barrier_init (&go_barrier, NULL, N + 1);
95
96 for (int i = 0; i < N; ++i)
97 {
98 int rc = pthread_create (&thr[i], NULL, &waiter_thread, &f);
99 if (rc)
100 error (1, rc, "pthread_create");
101 }
102
103 /* Make sure they are all there using their stacks. */
104 pthread_barrier_wait (&startup_barrier);
105 puts ("threads waiting");
106#endif
107
108 print_maps ();
109
9c6ea9fa
SP
110#if USE_PTHREADS
111 void *old_stack_addr, *new_stack_addr;
112 size_t stack_size;
113 pthread_t me = pthread_self ();
114 pthread_attr_t attr;
115 int ret = 0;
116
117 ret = pthread_getattr_np (me, &attr);
118 if (ret)
119 {
120 printf ("before execstack: pthread_getattr_np returned error: %s\n",
121 strerror (ret));
122 return 1;
123 }
124
125 ret = pthread_attr_getstack (&attr, &old_stack_addr, &stack_size);
126 if (ret)
127 {
128 printf ("before execstack: pthread_attr_getstack returned error: %s\n",
129 strerror (ret));
130 return 1;
131 }
132# if _STACK_GROWS_DOWN
133 old_stack_addr += stack_size;
134# else
135 old_stack_addr -= stack_size;
136# endif
137#endif
138
2abf9ff1
RM
139 /* Loading this module should force stacks to become executable. */
140 void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
141 if (h == NULL)
142 {
143 printf ("cannot load: %s\n", dlerror ());
d9961b6a 144 return allow_execstack;
2abf9ff1
RM
145 }
146
147 f = dlsym (h, "tryme");
148 if (f == NULL)
149 {
150 printf ("symbol not found: %s\n", dlerror ());
151 return 1;
152 }
153
154 /* Test if that really made our stack executable.
155 The `tryme' function should crash if not. */
156
157 (*((void (*) (void)) f)) ();
158
159 print_maps ();
160
9c6ea9fa
SP
161#if USE_PTHREADS
162 ret = pthread_getattr_np (me, &attr);
163 if (ret)
164 {
165 printf ("after execstack: pthread_getattr_np returned error: %s\n",
166 strerror (ret));
167 return 1;
168 }
169
170 ret = pthread_attr_getstack (&attr, &new_stack_addr, &stack_size);
171 if (ret)
172 {
173 printf ("after execstack: pthread_attr_getstack returned error: %s\n",
174 strerror (ret));
175 return 1;
176 }
177
178# if _STACK_GROWS_DOWN
179 new_stack_addr += stack_size;
180# else
181 new_stack_addr -= stack_size;
182# endif
183
184 /* It is possible that the dlopen'd module may have been mmapped just below
185 the stack. The stack size is taken as MIN(stack rlimit size, end of last
186 vma) in pthread_getattr_np. If rlimit is set high enough, it is possible
187 that the size may have changed. A subsequent call to
188 pthread_attr_getstack returns the size and (bottom - size) as the
189 stacksize and stackaddr respectively. If the size changes due to the
190 above, then both stacksize and stackaddr can change, but the stack bottom
191 should remain the same, which is computed as stackaddr + stacksize. */
192 if (old_stack_addr != new_stack_addr)
193 {
194 printf ("Stack end changed, old: %p, new: %p\n",
195 old_stack_addr, new_stack_addr);
196 return 1;
197 }
198 printf ("Stack address remains the same: %p\n", old_stack_addr);
199#endif
200
2abf9ff1
RM
201 /* Test that growing the stack region gets new executable pages too. */
202 deeper ((void (*) (void)) f);
203
204 print_maps ();
205
206#if USE_PTHREADS
207 /* Test that a fresh thread now gets an executable stack. */
208 {
209 pthread_t th;
210 int rc = pthread_create (&th, NULL, &tryme_thread, f);
211 if (rc)
212 error (1, rc, "pthread_create");
213 }
214
215 puts ("threads go");
216 /* The existing threads' stacks should have been changed.
217 Let them run to test it. */
218 pthread_barrier_wait (&go_barrier);
219
3005703b 220 pthread_exit ((void *) (long int) (! allow_execstack));
2abf9ff1
RM
221#endif
222
d9961b6a 223 return ! allow_execstack;
2abf9ff1
RM
224}
225
226static void
227deeper (void (*f) (void))
228{
229 char stack[1100 * 1024];
230 memfrob (stack, sizeof stack);
231 (*f) ();
232 memfrob (stack, sizeof stack);
233}
234
235
36fe25fd 236#include <support/test-driver.c>