Merge glibc-ports into ports/ directory.
[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   void *h = dlopen ("tst-execstack-mod.so", RTLD_LAZY);
141   if (h == NULL)
142     {
143       printf ("cannot load: %s\n", dlerror ());
144       return allow_execstack;
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
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
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
220   pthread_exit ((void *) (long int) (! allow_execstack));
221 #endif
222
223   return ! allow_execstack;
224 }
225
226 static void
227 deeper (void (*f) (void))
228 {
229   char stack[1100 * 1024];
230   memfrob (stack, sizeof stack);
231   (*f) ();
232   memfrob (stack, sizeof stack);
233 }
234
235
236 #define TEST_FUNCTION do_test ()
237 #include "../test-skeleton.c"