Back to index

glibc  2.9
tst-stackguard1.c
Go to the documentation of this file.
00001 /* Copyright (C) 2005 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <stdbool.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <sys/wait.h>
00026 #include <stackguard-macros.h>
00027 #include <unistd.h>
00028 
00029 static const char *command;
00030 static bool child;
00031 static uintptr_t stack_chk_guard_copy;
00032 static bool stack_chk_guard_copy_set;
00033 static int fds[2];
00034 
00035 static void __attribute__ ((constructor))
00036 con (void)
00037 {
00038   stack_chk_guard_copy = STACK_CHK_GUARD;
00039   stack_chk_guard_copy_set = true;
00040 }
00041 
00042 static int
00043 uintptr_t_cmp (const void *a, const void *b)
00044 {
00045   if (*(uintptr_t *) a < *(uintptr_t *) b)
00046     return 1;
00047   if (*(uintptr_t *) a > *(uintptr_t *) b)
00048     return -1;
00049   return 0;
00050 }
00051 
00052 static int
00053 do_test (void)
00054 {
00055   if (!stack_chk_guard_copy_set)
00056     {
00057       puts ("constructor has not been run");
00058       return 1;
00059     }
00060 
00061   if (stack_chk_guard_copy != STACK_CHK_GUARD)
00062     {
00063       puts ("STACK_CHK_GUARD changed between constructor and do_test");
00064       return 1;
00065     }
00066 
00067   if (child)
00068     {
00069       write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
00070       return 0;
00071     }
00072 
00073   if (command == NULL)
00074     {
00075       puts ("missing --command or --child argument");
00076       return 1;
00077     }
00078 
00079 #define N 16
00080   uintptr_t child_stack_chk_guards[N + 1];
00081   child_stack_chk_guards[N] = stack_chk_guard_copy;
00082   int i;
00083   for (i = 0; i < N; ++i)
00084     {
00085       if (pipe (fds) < 0)
00086        {
00087          printf ("couldn't create pipe: %m\n");
00088          return 1;
00089        }
00090 
00091       pid_t pid = fork ();
00092       if (pid < 0)
00093        {
00094          printf ("fork failed: %m\n");
00095          return 1;
00096        }
00097 
00098       if (!pid)
00099        {
00100          if (stack_chk_guard_copy != STACK_CHK_GUARD)
00101            {
00102              puts ("STACK_CHK_GUARD changed after fork");
00103              exit (1);
00104            }
00105 
00106          close (fds[0]);
00107          close (2);
00108          dup2 (fds[1], 2);
00109          close (fds[1]);
00110 
00111          system (command);
00112          exit (0);
00113        }
00114 
00115       close (fds[1]);
00116 
00117       if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
00118                                 sizeof (uintptr_t))) != sizeof (uintptr_t))
00119        {
00120          puts ("could not read stack_chk_guard value from child");
00121          return 1;
00122        }
00123 
00124       close (fds[0]);
00125 
00126       pid_t termpid;
00127       int status;
00128       termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
00129       if (termpid == -1)
00130        {
00131          printf ("waitpid failed: %m\n");
00132          return 1;
00133        }
00134       else if (termpid != pid)
00135        {
00136          printf ("waitpid returned %ld != %ld\n",
00137                 (long int) termpid, (long int) pid);
00138          return 1;
00139        }
00140       else if (!WIFEXITED (status) || WEXITSTATUS (status))
00141        {
00142          puts ("child hasn't exited with exit status 0");
00143          return 1;
00144        }
00145     }
00146 
00147   qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
00148 
00149   uintptr_t default_guard = 0;
00150   unsigned char *p = (unsigned char *) &default_guard;
00151   p[sizeof (uintptr_t) - 1] = 255;
00152   p[sizeof (uintptr_t) - 2] = '\n';
00153   p[0] = 0;
00154 
00155   /* Test if the stack guard canaries are either randomized,
00156      or equal to the default stack guard canary value.
00157      Even with randomized stack guards it might happen
00158      that the random number generator generates the same
00159      values, but if that happens in more than half from
00160      the 16 runs, something is very wrong.  */
00161   int ndifferences = 0;
00162   int ndefaults = 0;
00163   for (i = 0; i < N; ++i) 
00164     {
00165       if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1])
00166        ndifferences++;
00167       else if (child_stack_chk_guards[i] == default_guard)
00168        ndefaults++;
00169     }
00170 
00171   printf ("differences %d defaults %d\n", ndifferences, ndefaults);
00172 
00173   if (ndifferences < N / 2 && ndefaults < N / 2)
00174     {
00175       puts ("stack guard canaries are not randomized enough");
00176       puts ("nor equal to the default canary value");
00177       return 1;
00178     }
00179 
00180   return 0;
00181 }
00182 
00183 #define OPT_COMMAND  10000
00184 #define OPT_CHILD    10001
00185 #define CMDLINE_OPTIONS     \
00186   { "command", required_argument, NULL, OPT_COMMAND },  \
00187   { "child", no_argument, NULL, OPT_CHILD },
00188 #define CMDLINE_PROCESS     \
00189   case OPT_COMMAND:  \
00190     command = optarg;       \
00191     break;           \
00192   case OPT_CHILD:    \
00193     child = true;    \
00194     break;
00195 #define TEST_FUNCTION do_test ()
00196 #include "../test-skeleton.c"