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