1  /* Test and measure __strcpy_chk functions.
       2     Copyright (C) 1999-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifndef STRCPY_RESULT
      20  # define STRCPY_RESULT(dst, len) dst
      21  # define TEST_MAIN
      22  # define TEST_NAME "strcpy_chk"
      23  # include "../string/test-string.h"
      24  
      25  /* This test case implicitly tests the availability of the __chk_fail
      26     symbol, which is part of the public ABI and may be used
      27     externally. */
      28  extern void __attribute__ ((noreturn)) __chk_fail (void);
      29  char *simple_strcpy_chk (char *, const char *, size_t);
      30  extern char *normal_strcpy (char *, const char *, size_t)
      31    __asm ("strcpy");
      32  extern char *__strcpy_chk (char *, const char *, size_t);
      33  
      34  IMPL (simple_strcpy_chk, 0)
      35  IMPL (normal_strcpy, 1)
      36  IMPL (__strcpy_chk, 2)
      37  
      38  char *
      39  simple_strcpy_chk (char *dst, const char *src, size_t len)
      40  {
      41    char *ret = dst;
      42    if (! len)
      43      __chk_fail ();
      44    while ((*dst++ = *src++) != '\0')
      45      if (--len == 0)
      46        __chk_fail ();
      47    return ret;
      48  }
      49  #endif
      50  
      51  #include <fcntl.h>
      52  #include <paths.h>
      53  #include <setjmp.h>
      54  #include <signal.h>
      55  
      56  static int test_main (void);
      57  #define TEST_FUNCTION test_main
      58  #include <support/test-driver.c>
      59  #include <support/support.h>
      60  
      61  volatile int chk_fail_ok;
      62  jmp_buf chk_fail_buf;
      63  
      64  static void
      65  handler (int sig)
      66  {
      67    if (chk_fail_ok)
      68      {
      69        chk_fail_ok = 0;
      70        longjmp (chk_fail_buf, 1);
      71      }
      72    else
      73      _exit (127);
      74  }
      75  
      76  typedef char *(*proto_t) (char *, const char *, size_t);
      77  
      78  static void
      79  do_one_test (impl_t *impl, char *dst, const char *src,
      80  	     size_t len, size_t dlen)
      81  {
      82    char *res;
      83    if (dlen <= len)
      84      {
      85        if (impl->test == 1)
      86  	return;
      87  
      88        chk_fail_ok = 1;
      89        if (setjmp (chk_fail_buf) == 0)
      90  	{
      91  	  res = CALL (impl, dst, src, dlen);
      92  	  printf ("*** Function %s (%zd; %zd) did not __chk_fail\n",
      93  		  impl->name, len, dlen);
      94  	  chk_fail_ok = 0;
      95  	  ret = 1;
      96  	}
      97        return;
      98      }
      99    else
     100      res = CALL (impl, dst, src, dlen);
     101  
     102    if (res != STRCPY_RESULT (dst, len))
     103      {
     104        printf ("Wrong result in function %s %p %p\n", impl->name,
     105  	      res, STRCPY_RESULT (dst, len));
     106        ret = 1;
     107        return;
     108      }
     109  
     110    if (strcmp (dst, src) != 0)
     111      {
     112        printf ("Wrong result in function %s dst \"%s\" src \"%s\"\n",
     113  	      impl->name, dst, src);
     114        ret = 1;
     115        return;
     116      }
     117  }
     118  
     119  static void
     120  do_test (size_t align1, size_t align2, size_t len, size_t dlen, int max_char)
     121  {
     122    size_t i;
     123    char *s1, *s2;
     124  
     125    align1 &= 7;
     126    if (align1 + len >= page_size)
     127      return;
     128  
     129    align2 &= 7;
     130    if (align2 + len >= page_size)
     131      return;
     132  
     133    s1 = (char *) buf1 + align1;
     134    s2 = (char *) buf2 + align2;
     135  
     136    for (i = 0; i < len; i++)
     137      s1[i] = 32 + 23 * i % (max_char - 32);
     138    s1[len] = 0;
     139  
     140    FOR_EACH_IMPL (impl, 0)
     141      do_one_test (impl, s2, s1, len, dlen);
     142  }
     143  
     144  static void
     145  do_random_tests (void)
     146  {
     147    size_t i, j, n, align1, align2, len, dlen;
     148    unsigned char *p1 = buf1 + page_size - 512;
     149    unsigned char *p2 = buf2 + page_size - 512;
     150    unsigned char *res;
     151  
     152    for (n = 0; n < ITERATIONS; n++)
     153      {
     154        align1 = random () & 31;
     155        if (random () & 1)
     156  	align2 = random () & 31;
     157        else
     158  	align2 = align1 + (random () & 24);
     159        len = random () & 511;
     160        j = align1;
     161        if (align2 > j)
     162  	j = align2;
     163        if (len + j >= 511)
     164  	len = 510 - j - (random () & 7);
     165        j = len + align1 + 64;
     166        if (j > 512)
     167  	j = 512;
     168        for (i = 0; i < j; i++)
     169  	{
     170  	  if (i == len + align1)
     171  	    p1[i] = 0;
     172  	  else
     173  	    {
     174  	      p1[i] = random () & 255;
     175  	      if (i >= align1 && i < len + align1 && !p1[i])
     176  		p1[i] = (random () & 127) + 3;
     177  	    }
     178  	}
     179  
     180        switch (random () & 7)
     181  	{
     182  	case 0:
     183  	  dlen = len - (random () & 31);
     184  	  if (dlen > len)
     185  	    dlen = len;
     186  	  break;
     187  	case 1:
     188  	  dlen = (size_t) -1;
     189  	  break;
     190  	case 2:
     191  	  dlen = len + 1 + (random () & 65535);
     192  	  break;
     193  	case 3:
     194  	  dlen = len + 1 + (random () & 255);
     195  	  break;
     196  	case 4:
     197  	  dlen = len + 1 + (random () & 31);
     198  	  break;
     199  	case 5:
     200  	  dlen = len + 1 + (random () & 7);
     201  	  break;
     202  	case 6:
     203  	  dlen = len + 1 + (random () & 3);
     204  	  break;
     205  	default:
     206  	  dlen = len + 1;
     207  	  break;
     208  	}
     209  
     210        FOR_EACH_IMPL (impl, 1)
     211  	{
     212  	  if (dlen <= len)
     213  	    {
     214  	      if (impl->test != 1)
     215  		{
     216  		  chk_fail_ok = 1;
     217  		  if (setjmp (chk_fail_buf) == 0)
     218  		    {
     219  		      res = (unsigned char *)
     220  			    CALL (impl, (char *) p2 + align2,
     221  				  (char *) p1 + align1, dlen);
     222  		      printf ("Iteration %zd - did not __chk_fail\n", n);
     223  		      chk_fail_ok = 0;
     224  		      ret = 1;
     225  		    }
     226  		}
     227  	      continue;
     228  	    }
     229  	  memset (p2 - 64, '\1', 512 + 64);
     230  	  res = (unsigned char *)
     231  		CALL (impl, (char *) p2 + align2, (char *) p1 + align1, dlen);
     232  	  if (res != STRCPY_RESULT (p2 + align2, len))
     233  	    {
     234  	      printf ("\
     235  Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p\n",
     236  		      n, impl->name, align1, align2, len, res,
     237  		      STRCPY_RESULT (p2 + align2, len));
     238  	      ret = 1;
     239  	    }
     240  	  for (j = 0; j < align2 + 64; ++j)
     241  	    {
     242  	      if (p2[j - 64] != '\1')
     243  		{
     244  		  printf ("\
     245  Iteration %zd - garbage before, %s (%zd, %zd, %zd)\n",
     246  			  n, impl->name, align1, align2, len);
     247  		  ret = 1;
     248  		  break;
     249  		}
     250  	    }
     251  	  for (j = align2 + len + 1; j < 512; ++j)
     252  	    {
     253  	      if (p2[j] != '\1')
     254  		{
     255  		  printf ("\
     256  Iteration %zd - garbage after, %s (%zd, %zd, %zd)\n",
     257  			  n, impl->name, align1, align2, len);
     258  		  ret = 1;
     259  		  break;
     260  		}
     261  	    }
     262  	  if (memcmp (p1 + align1, p2 + align2, len + 1))
     263  	    {
     264  	      printf ("\
     265  Iteration %zd - different strings, %s (%zd, %zd, %zd)\n",
     266  		      n, impl->name, align1, align2, len);
     267  	      ret = 1;
     268  	    }
     269  	}
     270      }
     271  }
     272  
     273  static int
     274  test_main (void)
     275  {
     276    size_t i;
     277  
     278    set_fortify_handler (handler);
     279  
     280    test_init ();
     281  
     282    printf ("%23s", "");
     283    FOR_EACH_IMPL (impl, 0)
     284      printf ("\t%s", impl->name);
     285    putchar ('\n');
     286  
     287    for (i = 0; i < 16; ++i)
     288      {
     289        do_test (0, 0, i, i + 1, 127);
     290        do_test (0, 0, i, i + 1, 255);
     291        do_test (0, i, i, i + 1, 127);
     292        do_test (i, 0, i, i + 1, 255);
     293      }
     294  
     295    for (i = 1; i < 8; ++i)
     296      {
     297        do_test (0, 0, 8 << i, (8 << i) + 1, 127);
     298        do_test (8 - i, 2 * i, (8 << i), (8 << i) + 1, 127);
     299      }
     300  
     301    for (i = 1; i < 8; ++i)
     302      {
     303        do_test (i, 2 * i, (8 << i), (8 << i) + 1, 127);
     304        do_test (2 * i, i, (8 << i), (8 << i) + 1, 255);
     305        do_test (i, i, (8 << i), (8 << i) + 1, 127);
     306        do_test (i, i, (8 << i), (8 << i) + 1, 255);
     307      }
     308  
     309    for (i = 0; i < 16; ++i)
     310      {
     311        do_test (0, 0, i, i + 256, 127);
     312        do_test (0, 0, i, i + 256, 255);
     313        do_test (0, i, i, i + 256, 127);
     314        do_test (i, 0, i, i + 256, 255);
     315      }
     316  
     317    for (i = 1; i < 8; ++i)
     318      {
     319        do_test (0, 0, 8 << i, (8 << i) + 256, 127);
     320        do_test (8 - i, 2 * i, (8 << i), (8 << i) + 256, 127);
     321      }
     322  
     323    for (i = 1; i < 8; ++i)
     324      {
     325        do_test (i, 2 * i, (8 << i), (8 << i) + 256, 127);
     326        do_test (2 * i, i, (8 << i), (8 << i) + 256, 255);
     327        do_test (i, i, (8 << i), (8 << i) + 256, 127);
     328        do_test (i, i, (8 << i), (8 << i) + 256, 255);
     329      }
     330  
     331    for (i = 0; i < 16; ++i)
     332      {
     333        do_test (0, 0, i, i, 127);
     334        do_test (0, 0, i, i + 2, 255);
     335        do_test (0, i, i, i + 3, 127);
     336        do_test (i, 0, i, i + 4, 255);
     337      }
     338  
     339    for (i = 1; i < 8; ++i)
     340      {
     341        do_test (0, 0, 8 << i, (8 << i) - 15, 127);
     342        do_test (8 - i, 2 * i, (8 << i), (8 << i) + 5, 127);
     343      }
     344  
     345    for (i = 1; i < 8; ++i)
     346      {
     347        do_test (i, 2 * i, (8 << i), (8 << i) + i, 127);
     348        do_test (2 * i, i, (8 << i), (8 << i) + (i - 1), 255);
     349        do_test (i, i, (8 << i), (8 << i) + i + 2, 127);
     350        do_test (i, i, (8 << i), (8 << i) + i + 3, 255);
     351      }
     352  
     353    do_random_tests ();
     354    return ret;
     355  }