]> git.ipfire.org Git - thirdparty/glibc.git/blame - nptl/tst-stackguard1.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / nptl / tst-stackguard1.c
CommitLineData
04277e02 1/* Copyright (C) 2005-2019 Free Software Foundation, Inc.
35f1e827
UD
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
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
35f1e827
UD
18
19#include <errno.h>
20#include <pthread.h>
21#include <stdbool.h>
ceaa9889 22#include <stddef.h>
35f1e827
UD
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/wait.h>
a9538892 27#include <stackguard-macros.h>
903ae060 28#include <tls.h>
35f1e827
UD
29#include <unistd.h>
30
31static const char *command;
32static bool child;
33static uintptr_t stack_chk_guard_copy;
34static bool stack_chk_guard_copy_set;
35static int fds[2];
36
37static void __attribute__ ((constructor))
38con (void)
39{
40 stack_chk_guard_copy = STACK_CHK_GUARD;
41 stack_chk_guard_copy_set = true;
42}
43
44static int
45uintptr_t_cmp (const void *a, const void *b)
46{
47 if (*(uintptr_t *) a < *(uintptr_t *) b)
48 return 1;
49 if (*(uintptr_t *) a > *(uintptr_t *) b)
50 return -1;
51 return 0;
52}
53
54static void *
55tf (void *arg)
56{
57 if (stack_chk_guard_copy != STACK_CHK_GUARD)
58 {
59 puts ("STACK_CHK_GUARD changed in thread");
60 return (void *) 1L;
61 }
62 return NULL;
63}
64
65static int
66do_test (void)
67{
68 if (!stack_chk_guard_copy_set)
69 {
70 puts ("constructor has not been run");
71 return 1;
72 }
73
74 if (stack_chk_guard_copy != STACK_CHK_GUARD)
75 {
76 puts ("STACK_CHK_GUARD changed between constructor and do_test");
77 return 1;
78 }
79
80 if (child)
81 {
82 int i;
83 pthread_t th[4];
84 void *ret;
85 for (i = 0; i < 4; ++i)
86 if (pthread_create (&th[i], NULL, tf, NULL))
87 {
88 puts ("thread creation failed");
89 return 1;
90 }
91 for (i = 0; i < 4; ++i)
92 if (pthread_join (th[i], &ret))
93 {
94 puts ("thread join failed");
95 return 1;
96 }
97 else if (ret != NULL)
98 return 1;
99
100 write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
101 return 0;
102 }
103
104 if (command == NULL)
105 {
106 puts ("missing --command or --child argument");
107 return 1;
108 }
109
110#define N 16
111 uintptr_t child_stack_chk_guards[N + 1];
112 child_stack_chk_guards[N] = stack_chk_guard_copy;
113 int i;
114 for (i = 0; i < N; ++i)
115 {
116 if (pipe (fds) < 0)
117 {
118 printf ("couldn't create pipe: %m\n");
119 return 1;
120 }
121
122 pid_t pid = fork ();
123 if (pid < 0)
124 {
125 printf ("fork failed: %m\n");
126 return 1;
127 }
128
129 if (!pid)
130 {
131 if (stack_chk_guard_copy != STACK_CHK_GUARD)
132 {
133 puts ("STACK_CHK_GUARD changed after fork");
134 exit (1);
135 }
136
137 close (fds[0]);
138 close (2);
139 dup2 (fds[1], 2);
140 close (fds[1]);
141
142 system (command);
143 exit (0);
144 }
145
146 close (fds[1]);
147
148 if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
149 sizeof (uintptr_t))) != sizeof (uintptr_t))
150 {
151 puts ("could not read stack_chk_guard value from child");
152 return 1;
153 }
154
155 close (fds[0]);
156
157 pid_t termpid;
158 int status;
159 termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
160 if (termpid == -1)
161 {
162 printf ("waitpid failed: %m\n");
163 return 1;
164 }
165 else if (termpid != pid)
166 {
167 printf ("waitpid returned %ld != %ld\n",
168 (long int) termpid, (long int) pid);
169 return 1;
170 }
171 else if (!WIFEXITED (status) || WEXITSTATUS (status))
172 {
173 puts ("child hasn't exited with exit status 0");
174 return 1;
175 }
176 }
177
178 qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
179
180 uintptr_t default_guard = 0;
181 unsigned char *p = (unsigned char *) &default_guard;
182 p[sizeof (uintptr_t) - 1] = 255;
183 p[sizeof (uintptr_t) - 2] = '\n';
184 p[0] = 0;
185
186 /* Test if the stack guard canaries are either randomized,
187 or equal to the default stack guard canary value.
188 Even with randomized stack guards it might happen
189 that the random number generator generates the same
190 values, but if that happens in more than half from
191 the 16 runs, something is very wrong. */
192 int ndifferences = 0;
193 int ndefaults = 0;
c7afae94 194 for (i = 0; i < N; ++i)
35f1e827
UD
195 {
196 if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1])
197 ndifferences++;
198 else if (child_stack_chk_guards[i] == default_guard)
199 ndefaults++;
200 }
201
202 printf ("differences %d defaults %d\n", ndifferences, ndefaults);
203
204 if (ndifferences < N / 2 && ndefaults < N / 2)
205 {
206 puts ("stack guard canaries are not randomized enough");
207 puts ("nor equal to the default canary value");
208 return 1;
209 }
210
211 return 0;
212}
213
214#define OPT_COMMAND 10000
215#define OPT_CHILD 10001
216#define CMDLINE_OPTIONS \
217 { "command", required_argument, NULL, OPT_COMMAND }, \
218 { "child", no_argument, NULL, OPT_CHILD },
219#define CMDLINE_PROCESS \
220 case OPT_COMMAND: \
221 command = optarg; \
222 break; \
223 case OPT_CHILD: \
224 child = true; \
225 break;
226#define TEST_FUNCTION do_test ()
227#include "../test-skeleton.c"