Mention IFUNC enhancements to testsuite in NEWS.
[platform/upstream/glibc.git] / elf / tst-stackguard1.c
1 /* Copyright (C) 2005 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/wait.h>
25 #include <stackguard-macros.h>
26 #include <unistd.h>
27
28 static const char *command;
29 static bool child;
30 static uintptr_t stack_chk_guard_copy;
31 static bool stack_chk_guard_copy_set;
32 static int fds[2];
33
34 static void __attribute__ ((constructor))
35 con (void)
36 {
37   stack_chk_guard_copy = STACK_CHK_GUARD;
38   stack_chk_guard_copy_set = true;
39 }
40
41 static int
42 uintptr_t_cmp (const void *a, const void *b)
43 {
44   if (*(uintptr_t *) a < *(uintptr_t *) b)
45     return 1;
46   if (*(uintptr_t *) a > *(uintptr_t *) b)
47     return -1;
48   return 0;
49 }
50
51 static int
52 do_test (void)
53 {
54   if (!stack_chk_guard_copy_set)
55     {
56       puts ("constructor has not been run");
57       return 1;
58     }
59
60   if (stack_chk_guard_copy != STACK_CHK_GUARD)
61     {
62       puts ("STACK_CHK_GUARD changed between constructor and do_test");
63       return 1;
64     }
65
66   if (child)
67     {
68       write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
69       return 0;
70     }
71
72   if (command == NULL)
73     {
74       puts ("missing --command or --child argument");
75       return 1;
76     }
77
78 #define N 16
79   uintptr_t child_stack_chk_guards[N + 1];
80   child_stack_chk_guards[N] = stack_chk_guard_copy;
81   int i;
82   for (i = 0; i < N; ++i)
83     {
84       if (pipe (fds) < 0)
85         {
86           printf ("couldn't create pipe: %m\n");
87           return 1;
88         }
89
90       pid_t pid = fork ();
91       if (pid < 0)
92         {
93           printf ("fork failed: %m\n");
94           return 1;
95         }
96
97       if (!pid)
98         {
99           if (stack_chk_guard_copy != STACK_CHK_GUARD)
100             {
101               puts ("STACK_CHK_GUARD changed after fork");
102               exit (1);
103             }
104
105           close (fds[0]);
106           close (2);
107           dup2 (fds[1], 2);
108           close (fds[1]);
109
110           system (command);
111           exit (0);
112         }
113
114       close (fds[1]);
115
116       if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
117                                     sizeof (uintptr_t))) != sizeof (uintptr_t))
118         {
119           puts ("could not read stack_chk_guard value from child");
120           return 1;
121         }
122
123       close (fds[0]);
124
125       pid_t termpid;
126       int status;
127       termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
128       if (termpid == -1)
129         {
130           printf ("waitpid failed: %m\n");
131           return 1;
132         }
133       else if (termpid != pid)
134         {
135           printf ("waitpid returned %ld != %ld\n",
136                   (long int) termpid, (long int) pid);
137           return 1;
138         }
139       else if (!WIFEXITED (status) || WEXITSTATUS (status))
140         {
141           puts ("child hasn't exited with exit status 0");
142           return 1;
143         }
144     }
145
146   qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
147
148   uintptr_t default_guard = 0;
149   unsigned char *p = (unsigned char *) &default_guard;
150   p[sizeof (uintptr_t) - 1] = 255;
151   p[sizeof (uintptr_t) - 2] = '\n';
152   p[0] = 0;
153
154   /* Test if the stack guard canaries are either randomized,
155      or equal to the default stack guard canary value.
156      Even with randomized stack guards it might happen
157      that the random number generator generates the same
158      values, but if that happens in more than half from
159      the 16 runs, something is very wrong.  */
160   int ndifferences = 0;
161   int ndefaults = 0;
162   for (i = 0; i < N; ++i) 
163     {
164       if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1])
165         ndifferences++;
166       else if (child_stack_chk_guards[i] == default_guard)
167         ndefaults++;
168     }
169
170   printf ("differences %d defaults %d\n", ndifferences, ndefaults);
171
172   if (ndifferences < N / 2 && ndefaults < N / 2)
173     {
174       puts ("stack guard canaries are not randomized enough");
175       puts ("nor equal to the default canary value");
176       return 1;
177     }
178
179   return 0;
180 }
181
182 #define OPT_COMMAND     10000
183 #define OPT_CHILD       10001
184 #define CMDLINE_OPTIONS \
185   { "command", required_argument, NULL, OPT_COMMAND },  \
186   { "child", no_argument, NULL, OPT_CHILD },
187 #define CMDLINE_PROCESS \
188   case OPT_COMMAND:     \
189     command = optarg;   \
190     break;              \
191   case OPT_CHILD:       \
192     child = true;       \
193     break;
194 #define TEST_FUNCTION do_test ()
195 #include "../test-skeleton.c"