nptl: Rename tst-execstack to tst-execstack-threads
[platform/upstream/glibc.git] / elf / tst-execstack.c
1 /* Test program for making nonexecutable stacks executable
2    on load of a DSO that requires executable stacks.  */
3
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>
11
12 static void
13 print_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
23 static void deeper (void (*f) (void));
24
25 #if USE_PTHREADS
26 # include <pthread.h>
27
28 static void *
29 tryme_thread (void *f)
30 {
31   (*((void (*) (void)) f)) ();
32
33   return 0;
34 }
35
36 static pthread_barrier_t startup_barrier, go_barrier;
37 static void *
38 waiter_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
50 static bool allow_execstack = true;
51
52
53 static int
54 do_test (void)
55 {
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
86   static void *f;               /* Address of this is used in other threads. */
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
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
139   /* Loading this module should force stacks to become executable.  */
140 #if USE_PTHREADS
141   const char *soname = "tst-execstack-threads-mod.so";
142 #else
143   const char *soname = "tst-execstack-mod.so";
144 #endif
145   void *h = dlopen (soname, RTLD_LAZY);
146   if (h == NULL)
147     {
148       printf ("cannot load: %s\n", dlerror ());
149       return allow_execstack;
150     }
151
152   f = dlsym (h, "tryme");
153   if (f == NULL)
154     {
155       printf ("symbol not found: %s\n", dlerror ());
156       return 1;
157     }
158
159   /* Test if that really made our stack executable.
160      The `tryme' function should crash if not.  */
161
162   (*((void (*) (void)) f)) ();
163
164   print_maps ();
165
166 #if USE_PTHREADS
167   ret = pthread_getattr_np (me, &attr);
168   if (ret)
169     {
170       printf ("after execstack: pthread_getattr_np returned error: %s\n",
171               strerror (ret));
172       return 1;
173     }
174
175   ret = pthread_attr_getstack (&attr, &new_stack_addr, &stack_size);
176   if (ret)
177     {
178       printf ("after execstack: pthread_attr_getstack returned error: %s\n",
179               strerror (ret));
180       return 1;
181     }
182
183 # if _STACK_GROWS_DOWN
184     new_stack_addr += stack_size;
185 # else
186     new_stack_addr -= stack_size;
187 # endif
188
189   /* It is possible that the dlopen'd module may have been mmapped just below
190      the stack.  The stack size is taken as MIN(stack rlimit size, end of last
191      vma) in pthread_getattr_np.  If rlimit is set high enough, it is possible
192      that the size may have changed.  A subsequent call to
193      pthread_attr_getstack returns the size and (bottom - size) as the
194      stacksize and stackaddr respectively.  If the size changes due to the
195      above, then both stacksize and stackaddr can change, but the stack bottom
196      should remain the same, which is computed as stackaddr + stacksize.  */
197   if (old_stack_addr != new_stack_addr)
198     {
199       printf ("Stack end changed, old: %p, new: %p\n",
200               old_stack_addr, new_stack_addr);
201       return 1;
202     }
203   printf ("Stack address remains the same: %p\n", old_stack_addr);
204 #endif
205
206   /* Test that growing the stack region gets new executable pages too.  */
207   deeper ((void (*) (void)) f);
208
209   print_maps ();
210
211 #if USE_PTHREADS
212   /* Test that a fresh thread now gets an executable stack.  */
213   {
214     pthread_t th;
215     int rc = pthread_create (&th, NULL, &tryme_thread, f);
216     if (rc)
217       error (1, rc, "pthread_create");
218   }
219
220   puts ("threads go");
221   /* The existing threads' stacks should have been changed.
222      Let them run to test it.  */
223   pthread_barrier_wait (&go_barrier);
224
225   pthread_exit ((void *) (long int) (! allow_execstack));
226 #endif
227
228   return ! allow_execstack;
229 }
230
231 static void
232 deeper (void (*f) (void))
233 {
234   char stack[1100 * 1024];
235   explicit_bzero (stack, sizeof stack);
236   (*f) ();
237   memfrob (stack, sizeof stack);
238 }
239
240
241 #include <support/test-driver.c>