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