Replace FSF snail mail address with URLs.
[glibc.git] / nptl / tst-stackguard1.c
blob4af16c9c1565fac3037349643299792ebc0b0535
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.
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.
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.
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/>. */
19 #include <errno.h>
20 #include <pthread.h>
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/wait.h>
26 #include <elf/stackguard-macros.h>
27 #include <unistd.h>
29 static const char *command;
30 static bool child;
31 static uintptr_t stack_chk_guard_copy;
32 static bool stack_chk_guard_copy_set;
33 static int fds[2];
35 static void __attribute__ ((constructor))
36 con (void)
38 stack_chk_guard_copy = STACK_CHK_GUARD;
39 stack_chk_guard_copy_set = true;
42 static int
43 uintptr_t_cmp (const void *a, const void *b)
45 if (*(uintptr_t *) a < *(uintptr_t *) b)
46 return 1;
47 if (*(uintptr_t *) a > *(uintptr_t *) b)
48 return -1;
49 return 0;
52 static void *
53 tf (void *arg)
55 if (stack_chk_guard_copy != STACK_CHK_GUARD)
57 puts ("STACK_CHK_GUARD changed in thread");
58 return (void *) 1L;
60 return NULL;
63 static int
64 do_test (void)
66 if (!stack_chk_guard_copy_set)
68 puts ("constructor has not been run");
69 return 1;
72 if (stack_chk_guard_copy != STACK_CHK_GUARD)
74 puts ("STACK_CHK_GUARD changed between constructor and do_test");
75 return 1;
78 if (child)
80 int i;
81 pthread_t th[4];
82 void *ret;
83 for (i = 0; i < 4; ++i)
84 if (pthread_create (&th[i], NULL, tf, NULL))
86 puts ("thread creation failed");
87 return 1;
89 for (i = 0; i < 4; ++i)
90 if (pthread_join (th[i], &ret))
92 puts ("thread join failed");
93 return 1;
95 else if (ret != NULL)
96 return 1;
98 write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
99 return 0;
102 if (command == NULL)
104 puts ("missing --command or --child argument");
105 return 1;
108 #define N 16
109 uintptr_t child_stack_chk_guards[N + 1];
110 child_stack_chk_guards[N] = stack_chk_guard_copy;
111 int i;
112 for (i = 0; i < N; ++i)
114 if (pipe (fds) < 0)
116 printf ("couldn't create pipe: %m\n");
117 return 1;
120 pid_t pid = fork ();
121 if (pid < 0)
123 printf ("fork failed: %m\n");
124 return 1;
127 if (!pid)
129 if (stack_chk_guard_copy != STACK_CHK_GUARD)
131 puts ("STACK_CHK_GUARD changed after fork");
132 exit (1);
135 close (fds[0]);
136 close (2);
137 dup2 (fds[1], 2);
138 close (fds[1]);
140 system (command);
141 exit (0);
144 close (fds[1]);
146 if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
147 sizeof (uintptr_t))) != sizeof (uintptr_t))
149 puts ("could not read stack_chk_guard value from child");
150 return 1;
153 close (fds[0]);
155 pid_t termpid;
156 int status;
157 termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
158 if (termpid == -1)
160 printf ("waitpid failed: %m\n");
161 return 1;
163 else if (termpid != pid)
165 printf ("waitpid returned %ld != %ld\n",
166 (long int) termpid, (long int) pid);
167 return 1;
169 else if (!WIFEXITED (status) || WEXITSTATUS (status))
171 puts ("child hasn't exited with exit status 0");
172 return 1;
176 qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
178 uintptr_t default_guard = 0;
179 unsigned char *p = (unsigned char *) &default_guard;
180 p[sizeof (uintptr_t) - 1] = 255;
181 p[sizeof (uintptr_t) - 2] = '\n';
182 p[0] = 0;
184 /* Test if the stack guard canaries are either randomized,
185 or equal to the default stack guard canary value.
186 Even with randomized stack guards it might happen
187 that the random number generator generates the same
188 values, but if that happens in more than half from
189 the 16 runs, something is very wrong. */
190 int ndifferences = 0;
191 int ndefaults = 0;
192 for (i = 0; i < N; ++i)
194 if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1])
195 ndifferences++;
196 else if (child_stack_chk_guards[i] == default_guard)
197 ndefaults++;
200 printf ("differences %d defaults %d\n", ndifferences, ndefaults);
202 if (ndifferences < N / 2 && ndefaults < N / 2)
204 puts ("stack guard canaries are not randomized enough");
205 puts ("nor equal to the default canary value");
206 return 1;
209 return 0;
212 #define OPT_COMMAND 10000
213 #define OPT_CHILD 10001
214 #define CMDLINE_OPTIONS \
215 { "command", required_argument, NULL, OPT_COMMAND }, \
216 { "child", no_argument, NULL, OPT_CHILD },
217 #define CMDLINE_PROCESS \
218 case OPT_COMMAND: \
219 command = optarg; \
220 break; \
221 case OPT_CHILD: \
222 child = true; \
223 break;
224 #define TEST_FUNCTION do_test ()
225 #include "../test-skeleton.c"