scripts: Fix fortify checks if compiler does not support _FORTIFY_SOURCE=3
[glibc.git] / nptl / tst-stackguard1.c
blob7308b9d37a18141e0ef2e8a43252577170cc2b82
1 /* Copyright (C) 2005-2023 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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 <https://www.gnu.org/licenses/>. */
18 #include <errno.h>
19 #include <pthread.h>
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/wait.h>
26 #include <stackguard-macros.h>
27 #include <tls.h>
28 #include <unistd.h>
30 #include <support/xunistd.h>
31 #include <support/xstdlib.h>
33 static const char *command;
34 static bool child;
35 static uintptr_t stack_chk_guard_copy;
36 static bool stack_chk_guard_copy_set;
37 static int fds[2];
39 static void __attribute__ ((constructor))
40 con (void)
42 stack_chk_guard_copy = STACK_CHK_GUARD;
43 stack_chk_guard_copy_set = true;
46 static int
47 uintptr_t_cmp (const void *a, const void *b)
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;
56 static void *
57 tf (void *arg)
59 if (stack_chk_guard_copy != STACK_CHK_GUARD)
61 puts ("STACK_CHK_GUARD changed in thread");
62 return (void *) 1L;
64 return NULL;
67 static int
68 do_test (void)
70 if (!stack_chk_guard_copy_set)
72 puts ("constructor has not been run");
73 return 1;
76 if (stack_chk_guard_copy != STACK_CHK_GUARD)
78 puts ("STACK_CHK_GUARD changed between constructor and do_test");
79 return 1;
82 if (child)
84 int i;
85 pthread_t th[4];
86 void *ret;
87 for (i = 0; i < 4; ++i)
88 if (pthread_create (&th[i], NULL, tf, NULL))
90 puts ("thread creation failed");
91 return 1;
93 for (i = 0; i < 4; ++i)
94 if (pthread_join (th[i], &ret))
96 puts ("thread join failed");
97 return 1;
99 else if (ret != NULL)
100 return 1;
102 xwrite (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
103 return 0;
106 if (command == NULL)
108 puts ("missing --command or --child argument");
109 return 1;
112 #define N 16
113 uintptr_t child_stack_chk_guards[N + 1];
114 child_stack_chk_guards[N] = stack_chk_guard_copy;
115 int i;
116 for (i = 0; i < N; ++i)
118 if (pipe (fds) < 0)
120 printf ("couldn't create pipe: %m\n");
121 return 1;
124 pid_t pid = fork ();
125 if (pid < 0)
127 printf ("fork failed: %m\n");
128 return 1;
131 if (!pid)
133 if (stack_chk_guard_copy != STACK_CHK_GUARD)
135 puts ("STACK_CHK_GUARD changed after fork");
136 exit (1);
139 close (fds[0]);
140 close (2);
141 dup2 (fds[1], 2);
142 close (fds[1]);
144 xsystem (command);
146 exit (0);
149 close (fds[1]);
151 if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
152 sizeof (uintptr_t))) != sizeof (uintptr_t))
154 puts ("could not read stack_chk_guard value from child");
155 return 1;
158 close (fds[0]);
160 pid_t termpid;
161 int status;
162 termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
163 if (termpid == -1)
165 printf ("waitpid failed: %m\n");
166 return 1;
168 else if (termpid != pid)
170 printf ("waitpid returned %ld != %ld\n",
171 (long int) termpid, (long int) pid);
172 return 1;
174 else if (!WIFEXITED (status) || WEXITSTATUS (status))
176 puts ("child hasn't exited with exit status 0");
177 return 1;
181 qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
183 uintptr_t default_guard = 0;
184 unsigned char *p = (unsigned char *) &default_guard;
185 p[sizeof (uintptr_t) - 1] = 255;
186 p[sizeof (uintptr_t) - 2] = '\n';
187 p[0] = 0;
189 /* Test if the stack guard canaries are either randomized,
190 or equal to the default stack guard canary value.
191 Even with randomized stack guards it might happen
192 that the random number generator generates the same
193 values, but if that happens in more than half from
194 the 16 runs, something is very wrong. */
195 int ndifferences = 0;
196 int ndefaults = 0;
197 for (i = 0; i < N; ++i)
199 if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1])
200 ndifferences++;
201 else if (child_stack_chk_guards[i] == default_guard)
202 ndefaults++;
205 printf ("differences %d defaults %d\n", ndifferences, ndefaults);
207 if (ndifferences < N / 2 && ndefaults < N / 2)
209 puts ("stack guard canaries are not randomized enough");
210 puts ("nor equal to the default canary value");
211 return 1;
214 return 0;
217 #define OPT_COMMAND 10000
218 #define OPT_CHILD 10001
219 #define CMDLINE_OPTIONS \
220 { "command", required_argument, NULL, OPT_COMMAND }, \
221 { "child", no_argument, NULL, OPT_CHILD },
222 #define CMDLINE_PROCESS \
223 case OPT_COMMAND: \
224 command = optarg; \
225 break; \
226 case OPT_CHILD: \
227 child = true; \
228 break;
229 #define TEST_FUNCTION do_test ()
230 #include "../test-skeleton.c"