(root)/
glibc-2.38/
nptl/
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 <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>
      29  
      30  #include <support/xunistd.h>
      31  #include <support/xstdlib.h>
      32  
      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];
      38  
      39  static void __attribute__ ((constructor))
      40  con (void)
      41  {
      42    stack_chk_guard_copy = STACK_CHK_GUARD;
      43    stack_chk_guard_copy_set = true;
      44  }
      45  
      46  static int
      47  uintptr_t_cmp (const void *a, const void *b)
      48  {
      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;
      54  }
      55  
      56  static void *
      57  tf (void *arg)
      58  {
      59    if (stack_chk_guard_copy != STACK_CHK_GUARD)
      60      {
      61        puts ("STACK_CHK_GUARD changed in thread");
      62        return (void *) 1L;
      63      }
      64    return NULL;
      65  }
      66  
      67  static int
      68  do_test (void)
      69  {
      70    if (!stack_chk_guard_copy_set)
      71      {
      72        puts ("constructor has not been run");
      73        return 1;
      74      }
      75  
      76    if (stack_chk_guard_copy != STACK_CHK_GUARD)
      77      {
      78        puts ("STACK_CHK_GUARD changed between constructor and do_test");
      79        return 1;
      80      }
      81  
      82    if (child)
      83      {
      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))
      89  	  {
      90  	    puts ("thread creation failed");
      91  	    return 1;
      92  	  }
      93        for (i = 0; i < 4; ++i)
      94  	if (pthread_join (th[i], &ret))
      95  	  {
      96  	    puts ("thread join failed");
      97  	    return 1;
      98  	  }
      99  	else if (ret != NULL)
     100  	  return 1;
     101  
     102        xwrite (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy));
     103        return 0;
     104      }
     105  
     106    if (command == NULL)
     107      {
     108        puts ("missing --command or --child argument");
     109        return 1;
     110      }
     111  
     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)
     117      {
     118        if (pipe (fds) < 0)
     119  	{
     120  	  printf ("couldn't create pipe: %m\n");
     121  	  return 1;
     122  	}
     123  
     124        pid_t pid = fork ();
     125        if (pid < 0)
     126  	{
     127  	  printf ("fork failed: %m\n");
     128  	  return 1;
     129  	}
     130  
     131        if (!pid)
     132  	{
     133  	  if (stack_chk_guard_copy != STACK_CHK_GUARD)
     134  	    {
     135  	      puts ("STACK_CHK_GUARD changed after fork");
     136  	      exit (1);
     137  	    }
     138  
     139  	  close (fds[0]);
     140  	  close (2);
     141  	  dup2 (fds[1], 2);
     142  	  close (fds[1]);
     143  
     144  	  xsystem (command);
     145  
     146  	  exit (0);
     147  	}
     148  
     149        close (fds[1]);
     150  
     151        if (TEMP_FAILURE_RETRY (read (fds[0], &child_stack_chk_guards[i],
     152  				    sizeof (uintptr_t))) != sizeof (uintptr_t))
     153  	{
     154  	  puts ("could not read stack_chk_guard value from child");
     155  	  return 1;
     156  	}
     157  
     158        close (fds[0]);
     159  
     160        pid_t termpid;
     161        int status;
     162        termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
     163        if (termpid == -1)
     164  	{
     165  	  printf ("waitpid failed: %m\n");
     166  	  return 1;
     167  	}
     168        else if (termpid != pid)
     169  	{
     170  	  printf ("waitpid returned %ld != %ld\n",
     171  		  (long int) termpid, (long int) pid);
     172  	  return 1;
     173  	}
     174        else if (!WIFEXITED (status) || WEXITSTATUS (status))
     175  	{
     176  	  puts ("child hasn't exited with exit status 0");
     177  	  return 1;
     178  	}
     179      }
     180  
     181    qsort (child_stack_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
     182  
     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;
     188  
     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)
     198      {
     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++;
     203      }
     204  
     205    printf ("differences %d defaults %d\n", ndifferences, ndefaults);
     206  
     207    if (ndifferences < N / 2 && ndefaults < N / 2)
     208      {
     209        puts ("stack guard canaries are not randomized enough");
     210        puts ("nor equal to the default canary value");
     211        return 1;
     212      }
     213  
     214    return 0;
     215  }
     216  
     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"