Add more checks for valid ld.so.cache file (bug 18093)
[platform/upstream/glibc.git] / elf / tst-ptrguard1.c
1 /* Copyright (C) 2013-2018 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 _GNU_SOURCE
29 #define _GNU_SOURCE
30 #endif
31 /* Requires _GNU_SOURCE  */
32 #include <getopt.h>
33
34 #ifndef POINTER_CHK_GUARD
35 extern uintptr_t __pointer_chk_guard;
36 # define POINTER_CHK_GUARD __pointer_chk_guard
37 #endif
38
39 static const char *command;
40 static bool child;
41 static uintptr_t ptr_chk_guard_copy;
42 static bool ptr_chk_guard_copy_set;
43 static int fds[2];
44
45 static void __attribute__ ((constructor))
46 con (void)
47 {
48   ptr_chk_guard_copy = POINTER_CHK_GUARD;
49   ptr_chk_guard_copy_set = true;
50 }
51
52 static int
53 uintptr_t_cmp (const void *a, const void *b)
54 {
55   if (*(uintptr_t *) a < *(uintptr_t *) b)
56     return 1;
57   if (*(uintptr_t *) a > *(uintptr_t *) b)
58     return -1;
59   return 0;
60 }
61
62 static int
63 do_test (void)
64 {
65   if (!ptr_chk_guard_copy_set)
66     {
67       puts ("constructor has not been run");
68       return 1;
69     }
70
71   if (ptr_chk_guard_copy != POINTER_CHK_GUARD)
72     {
73       puts ("POINTER_CHK_GUARD changed between constructor and do_test");
74       return 1;
75     }
76
77   if (child)
78     {
79       write (2, &ptr_chk_guard_copy, sizeof (ptr_chk_guard_copy));
80       return 0;
81     }
82
83   if (command == NULL)
84     {
85       puts ("missing --command or --child argument");
86       return 1;
87     }
88
89 #define N 16
90   uintptr_t child_ptr_chk_guards[N + 1];
91   child_ptr_chk_guards[N] = ptr_chk_guard_copy;
92   int i;
93   for (i = 0; i < N; ++i)
94     {
95       if (pipe (fds) < 0)
96         {
97           printf ("couldn't create pipe: %m\n");
98           return 1;
99         }
100
101       pid_t pid = fork ();
102       if (pid < 0)
103         {
104           printf ("fork failed: %m\n");
105           return 1;
106         }
107
108       if (!pid)
109         {
110           if (ptr_chk_guard_copy != POINTER_CHK_GUARD)
111             {
112               puts ("POINTER_CHK_GUARD changed after fork");
113               exit (1);
114             }
115
116           close (fds[0]);
117           close (2);
118           dup2 (fds[1], 2);
119           close (fds[1]);
120
121           system (command);
122           exit (0);
123         }
124
125       close (fds[1]);
126
127       if (TEMP_FAILURE_RETRY (read (fds[0], &child_ptr_chk_guards[i],
128                                     sizeof (uintptr_t))) != sizeof (uintptr_t))
129         {
130           puts ("could not read ptr_chk_guard value from child");
131           return 1;
132         }
133
134       close (fds[0]);
135
136       pid_t termpid;
137       int status;
138       termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
139       if (termpid == -1)
140         {
141           printf ("waitpid failed: %m\n");
142           return 1;
143         }
144       else if (termpid != pid)
145         {
146           printf ("waitpid returned %ld != %ld\n",
147                   (long int) termpid, (long int) pid);
148           return 1;
149         }
150       else if (!WIFEXITED (status) || WEXITSTATUS (status))
151         {
152           puts ("child hasn't exited with exit status 0");
153           return 1;
154         }
155     }
156
157   qsort (child_ptr_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
158
159   /* The default pointer guard is the same as the default stack guard.
160      They are only set to default if dl_random is NULL.  */
161   uintptr_t default_guard = 0;
162   unsigned char *p = (unsigned char *) &default_guard;
163   p[sizeof (uintptr_t) - 1] = 255;
164   p[sizeof (uintptr_t) - 2] = '\n';
165   p[0] = 0;
166
167   /* Test if the pointer guard canaries are either randomized,
168      or equal to the default pointer guard value.
169      Even with randomized pointer guards it might happen
170      that the random number generator generates the same
171      values, but if that happens in more than half from
172      the 16 runs, something is very wrong.  */
173   int ndifferences = 0;
174   int ndefaults = 0;
175   for (i = 0; i < N; ++i)
176     {
177       if (child_ptr_chk_guards[i] != child_ptr_chk_guards[i+1])
178         ndifferences++;
179       else if (child_ptr_chk_guards[i] == default_guard)
180         ndefaults++;
181     }
182
183   printf ("differences %d defaults %d\n", ndifferences, ndefaults);
184
185   if (ndifferences < N / 2 && ndefaults < N / 2)
186     {
187       puts ("pointer guard values are not randomized enough");
188       puts ("nor equal to the default value");
189       return 1;
190     }
191
192   return 0;
193 }
194
195 #define OPT_COMMAND     10000
196 #define OPT_CHILD       10001
197 #define CMDLINE_OPTIONS \
198   { "command", required_argument, NULL, OPT_COMMAND },  \
199   { "child", no_argument, NULL, OPT_CHILD },
200
201 static void __attribute((used))
202 cmdline_process_function (int c)
203 {
204   switch (c)
205     {
206       case OPT_COMMAND:
207         command = optarg;
208         break;
209       case OPT_CHILD:
210         child = true;
211         break;
212     }
213 }
214
215 #define CMDLINE_PROCESS cmdline_process_function
216
217 #include <support/test-driver.c>