Further harden glibc malloc metadata against 1-byte overflows.
[glibc.git] / elf / tst-execstack.c
blob02cc270d804232a588977006c7754cd6929e89dd
1 /* Test program for making nonexecutable stacks executable
2 on load of a DSO that requires executable stacks. */
4 #include <dlfcn.h>
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <error.h>
10 #include <stackinfo.h>
12 static void
13 print_maps (void)
15 #if 0
16 char *cmd = NULL;
17 asprintf (&cmd, "cat /proc/%d/maps", getpid ());
18 system (cmd);
19 free (cmd);
20 #endif
23 static void deeper (void (*f) (void));
25 #if USE_PTHREADS
26 # include <pthread.h>
28 static void *
29 tryme_thread (void *f)
31 (*((void (*) (void)) f)) ();
33 return 0;
36 static pthread_barrier_t startup_barrier, go_barrier;
37 static void *
38 waiter_thread (void *arg)
40 void **f = arg;
41 pthread_barrier_wait (&startup_barrier);
42 pthread_barrier_wait (&go_barrier);
44 (*((void (*) (void)) *f)) ();
46 return 0;
48 #endif
50 static bool allow_execstack = true;
53 static int
54 do_test (void)
56 /* Check whether SELinux is enabled and disallows executable stacks. */
57 FILE *fp = fopen ("/selinux/enforce", "r");
58 if (fp != NULL)
60 char *line = NULL;
61 size_t linelen = 0;
63 bool enabled = false;
64 ssize_t n = getline (&line, &linelen, fp);
65 if (n > 0 && line[0] != '0')
66 enabled = true;
68 fclose (fp);
70 if (enabled)
72 fp = fopen ("/selinux/booleans/allow_execstack", "r");
73 if (fp != NULL)
75 n = getline (&line, &linelen, fp);
76 if (n > 0 && line[0] == '0')
77 allow_execstack = false;
80 fclose (fp);
84 printf ("executable stacks %sallowed\n", allow_execstack ? "" : "not ");
86 static void *f; /* Address of this is used in other threads. */
88 #if USE_PTHREADS
89 /* Create some threads while stacks are nonexecutable. */
90 #define N 5
91 pthread_t thr[N];
93 pthread_barrier_init (&startup_barrier, NULL, N + 1);
94 pthread_barrier_init (&go_barrier, NULL, N + 1);
96 for (int i = 0; i < N; ++i)
98 int rc = pthread_create (&thr[i], NULL, &waiter_thread, &f);
99 if (rc)
100 error (1, rc, "pthread_create");
103 /* Make sure they are all there using their stacks. */
104 pthread_barrier_wait (&startup_barrier);
105 puts ("threads waiting");
106 #endif
108 print_maps ();
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;
117 ret = pthread_getattr_np (me, &attr);
118 if (ret)
120 printf ("before execstack: pthread_getattr_np returned error: %s\n",
121 strerror (ret));
122 return 1;
125 ret = pthread_attr_getstack (&attr, &old_stack_addr, &stack_size);
126 if (ret)
128 printf ("before execstack: pthread_attr_getstack returned error: %s\n",
129 strerror (ret));
130 return 1;
132 # if _STACK_GROWS_DOWN
133 old_stack_addr += stack_size;
134 # else
135 old_stack_addr -= stack_size;
136 # endif
137 #endif
139 /* Loading this module should force stacks to become executable. */
140 void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
141 if (h == NULL)
143 printf ("cannot load: %s\n", dlerror ());
144 return allow_execstack;
147 f = dlsym (h, "tryme");
148 if (f == NULL)
150 printf ("symbol not found: %s\n", dlerror ());
151 return 1;
154 /* Test if that really made our stack executable.
155 The `tryme' function should crash if not. */
157 (*((void (*) (void)) f)) ();
159 print_maps ();
161 #if USE_PTHREADS
162 ret = pthread_getattr_np (me, &attr);
163 if (ret)
165 printf ("after execstack: pthread_getattr_np returned error: %s\n",
166 strerror (ret));
167 return 1;
170 ret = pthread_attr_getstack (&attr, &new_stack_addr, &stack_size);
171 if (ret)
173 printf ("after execstack: pthread_attr_getstack returned error: %s\n",
174 strerror (ret));
175 return 1;
178 # if _STACK_GROWS_DOWN
179 new_stack_addr += stack_size;
180 # else
181 new_stack_addr -= stack_size;
182 # endif
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)
194 printf ("Stack end changed, old: %p, new: %p\n",
195 old_stack_addr, new_stack_addr);
196 return 1;
198 printf ("Stack address remains the same: %p\n", old_stack_addr);
199 #endif
201 /* Test that growing the stack region gets new executable pages too. */
202 deeper ((void (*) (void)) f);
204 print_maps ();
206 #if USE_PTHREADS
207 /* Test that a fresh thread now gets an executable stack. */
209 pthread_t th;
210 int rc = pthread_create (&th, NULL, &tryme_thread, f);
211 if (rc)
212 error (1, rc, "pthread_create");
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);
220 pthread_exit ((void *) (long int) (! allow_execstack));
221 #endif
223 return ! allow_execstack;
226 static void
227 deeper (void (*f) (void))
229 char stack[1100 * 1024];
230 memfrob (stack, sizeof stack);
231 (*f) ();
232 memfrob (stack, sizeof stack);
236 #define TEST_FUNCTION do_test ()
237 #include "../test-skeleton.c"