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 <pthread.h>
00022 #include <stdbool.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <sys/wait.h>
00027 #include <elf/stackguard-macros.h>
00028 #include <unistd.h>
00029 
00030 static const char *command;
00031 static bool child;
00032 static uintptr_t stack_chk_guard_copy;
00033 static bool stack_chk_guard_copy_set;
00034 static int fds[2];
00035 
00036 static void __attribute__ ((constructor))
00037 con (void)
00038 {
00039   stack_chk_guard_copy = STACK_CHK_GUARD;
00040   stack_chk_guard_copy_set = true;
00041 }
00042 
00043 static int
00044 uintptr_t_cmp (const void *a, const void *b)
00045 {
00046   if (*(uintptr_t *) a < *(uintptr_t *) b)
00047     return 1;
00048   if (*(uintptr_t *) a > *(uintptr_t *) b)
00049     return -1;
00050   return 0;
00051 }
00052 
00053 static void *
00054 tf (void *arg)
00055 {
00056   if (stack_chk_guard_copy != STACK_CHK_GUARD)
00057     {
00058       puts ("STACK_CHK_GUARD changed in thread");
00059       return (void *) 1L;
00060     }
00061   return NULL;
00062 }
00063 
00064 static int
00065 do_test (void)
00066 {
00067   if (!stack_chk_guard_copy_set)
00068     {
00069       puts ("constructor has not been run");
00070       return 1;
00071     }
00072 
00073   if (stack_chk_guard_copy != STACK_CHK_GUARD)
00074     {
00075       puts ("STACK_CHK_GUARD changed between constructor and do_test");
00076       return 1;
00077     }
00078 
00079   if (child)
00080     {
00081       int i;
00082       pthread_t th[4];
00083       void *ret;
00084       for (i = 0; i < 4; ++i)
00085        if (pthread_create (&th[i], NULL, tf, NULL))
00086          {
00087            puts ("thread creation failed");
00088            return 1;
00089          }
00090       for (i = 0; i < 4; ++i)
00091        if (pthread_join (th[i], &ret))
00092          {
00093            puts ("thread join failed");
00094            return 1;
00095          }
00096        else if (ret != NULL)
00097          return 1;
00098 
00099       write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
00100       return 0;
00101     }
00102 
00103   if (command == NULL)
00104     {
00105       puts ("missing --command or --child argument");
00106       return 1;
00107     }
00108 
00109 #define N 16
00110   uintptr_t child_stack_chk_guards[N + 1];
00111   child_stack_chk_guards[N] = stack_chk_guard_copy;
00112   int i;
00113   for (i = 0; i < N; ++i)
00114     {
00115       if (pipe (fds) < 0)
00116        {
00117          printf ("couldn't create pipe: %m\n");
00118          return 1;
00119        }
00120 
00121       pid_t pid = fork ();
00122       if (pid < 0)
00123        {
00124          printf ("fork failed: %m\n");
00125          return 1;
00126        }
00127 
00128       if (!pid)
00129        {
00130          if (stack_chk_guard_copy != STACK_CHK_GUARD)
00131            {
00132              puts ("STACK_CHK_GUARD changed after fork");
00133              exit (1);
00134            }
00135 
00136          close (fds[0]);
00137          close (2);
00138          dup2 (fds[1], 2);
00139          close (fds[1]);
00140 
00141          system (command);
00142          exit (0);
00143        }
00144 
00145       close (fds[1]);
00146 
00147       if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
00148                                 sizeof (uintptr_t))) != sizeof (uintptr_t))
00149        {
00150          puts ("could not read stack_chk_guard value from child");
00151          return 1;
00152        }
00153 
00154       close (fds[0]);
00155 
00156       pid_t termpid;
00157       int status;
00158       termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
00159       if (termpid == -1)
00160        {
00161          printf ("waitpid failed: %m\n");
00162          return 1;
00163        }
00164       else if (termpid != pid)
00165        {
00166          printf ("waitpid returned %ld != %ld\n",
00167                 (long int) termpid, (long int) pid);
00168          return 1;
00169        }
00170       else if (!WIFEXITED (status) || WEXITSTATUS (status))
00171        {
00172          puts ("child hasn't exited with exit status 0");
00173          return 1;
00174        }
00175     }
00176 
00177   qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
00178 
00179   uintptr_t default_guard = 0;
00180   unsigned char *p = (unsigned char *) &default_guard;
00181   p[sizeof (uintptr_t) - 1] = 255;
00182   p[sizeof (uintptr_t) - 2] = '\n';
00183   p[0] = 0;
00184 
00185   /* Test if the stack guard canaries are either randomized,
00186      or equal to the default stack guard canary value.
00187      Even with randomized stack guards it might happen
00188      that the random number generator generates the same
00189      values, but if that happens in more than half from
00190      the 16 runs, something is very wrong.  */
00191   int ndifferences = 0;
00192   int ndefaults = 0;
00193   for (i = 0; i < N; ++i) 
00194     {
00195       if (child_stack_chk_guards[i] != child_stack_chk_guards[i+1])
00196        ndifferences++;
00197       else if (child_stack_chk_guards[i] == default_guard)
00198        ndefaults++;
00199     }
00200 
00201   printf ("differences %d defaults %d\n", ndifferences, ndefaults);
00202 
00203   if (ndifferences < N / 2 && ndefaults < N / 2)
00204     {
00205       puts ("stack guard canaries are not randomized enough");
00206       puts ("nor equal to the default canary value");
00207       return 1;
00208     }
00209 
00210   return 0;
00211 }
00212 
00213 #define OPT_COMMAND  10000
00214 #define OPT_CHILD    10001
00215 #define CMDLINE_OPTIONS     \
00216   { "command", required_argument, NULL, OPT_COMMAND },  \
00217   { "child", no_argument, NULL, OPT_CHILD },
00218 #define CMDLINE_PROCESS     \
00219   case OPT_COMMAND:  \
00220     command = optarg;       \
00221     break;           \
00222   case OPT_CHILD:    \
00223     child = true;    \
00224     break;
00225 #define TEST_FUNCTION do_test ()
00226 #include "../test-skeleton.c"