1  /* Test passing invalid arguments to crypt*().
       2  
       3     Written by Zack Weinberg <zackw at panix.com> in 2018.
       4     To the extent possible under law, Zack Weinberg has waived all
       5     copyright and related or neighboring rights to this work.
       6  
       7     See https://creativecommons.org/publicdomain/zero/1.0/ for further
       8     details.  */
       9  
      10  #include "crypt-port.h"
      11  
      12  #include <errno.h>
      13  #include <setjmp.h>
      14  #include <stdio.h>
      15  #include <string.h>
      16  #include <signal.h>
      17  #include <sys/mman.h>
      18  
      19  /* The behavior tested below should be consistent for all hashing
      20     methods.  */
      21  static const char *settings[] =
      22  {
      23  #if INCLUDE_descrypt || INCLUDE_bigcrypt
      24    "Mp",
      25  #endif
      26  #if INCLUDE_bsdicrypt
      27    "_J9..MJHn",
      28  #endif
      29  #if INCLUDE_md5crypt
      30    "$1$MJHnaAke",
      31  #endif
      32  #if INCLUDE_nt
      33    "$3$",
      34  #endif
      35  #if INCLUDE_sunmd5
      36    /* exercise all paths of the bug-compatibility logic */
      37    "$md5,rounds=55349$BPm.fm03$",
      38    "$md5,rounds=55349$BPm.fm03$x",
      39    "$md5,rounds=55349$BPm.fm03$$",
      40    "$md5,rounds=55349$BPm.fm03$$x",
      41    "$md5$BPm.fm03$",
      42    "$md5$BPm.fm03$x",
      43    "$md5$BPm.fm03$$",
      44    "$md5$BPm.fm03$$x",
      45  #endif
      46  #if INCLUDE_sha1crypt
      47    "$sha1$248488$ggu.H673kaZ5$",
      48  #endif
      49  #if INCLUDE_sha256crypt
      50    "$5$MJHnaAkegEVYHsFK",
      51    "$5$rounds=10191$MJHnaAkegEVYHsFK",
      52  #endif
      53  #if INCLUDE_sha512crypt
      54    "$6$MJHnaAkegEVYHsFK",
      55    "$6$rounds=10191$MJHnaAkegEVYHsFK",
      56  #endif
      57  #if INCLUDE_bcrypt_a
      58    "$2a$05$UBVLHeMpJ/QQCv3XqJx8zO",
      59  #endif
      60  #if INCLUDE_bcrypt
      61    "$2b$05$UBVLHeMpJ/QQCv3XqJx8zO",
      62  #endif
      63  #if INCLUDE_bcrypt_x
      64    "$2x$05$UBVLHeMpJ/QQCv3XqJx8zO",
      65  #endif
      66  #if INCLUDE_bcrypt_y
      67    "$2y$05$UBVLHeMpJ/QQCv3XqJx8zO",
      68  #endif
      69  #if INCLUDE_yescrypt
      70    "$y$j9T$MJHnaAkegEVYHsFKkmfzJ1",
      71  #endif
      72  #if INCLUDE_scrypt
      73    "$7$CU..../....MJHnaAkegEVYHsFKkmfzJ1",
      74  #endif
      75  #if INCLUDE_gost_yescrypt
      76    "$gy$j9T$MJHnaAkegEVYHsFKkmfzJ1",
      77  #endif
      78  };
      79  
      80  /* In some of the tests below, a segmentation fault is the expected result.  */
      81  static sigjmp_buf env;
      82  static void
      83  segv_handler (int sig)
      84  {
      85    siglongjmp (env, sig);
      86  }
      87  
      88  static bool error_occurred;
      89  
      90  #ifndef XCRYPT_USE_ASAN /* see comments in do_tests */
      91  static void
      92  expect_no_fault (const char *tag,
      93                   const char *phrase, const char *setting, const char *expect,
      94                   void (*testfn) (const char *, const char *,
      95                                   const char *, const char *))
      96  {
      97    int rv = sigsetjmp (env, 1);
      98    if (!rv)
      99      testfn (tag, phrase, setting, expect);
     100    else
     101      {
     102        printf ("FAIL: %s: Unexpected %s\n", tag, strsignal (rv));
     103        error_occurred = 1;
     104      }
     105  }
     106  #endif
     107  
     108  static void
     109  expect_a_fault (const char *tag,
     110                  const char *phrase, const char *setting, const char *expect,
     111                  void (*testfn) (const char *, const char *,
     112                                  const char *, const char *))
     113  {
     114    int rv = sigsetjmp (env, 1);
     115    if (!rv)
     116      {
     117        testfn (tag, phrase, setting, expect);
     118        printf ("ERROR: %s: No signal occurred\n", tag);
     119        error_occurred = true;
     120      }
     121  }
     122  
     123  static void
     124  check (const char *tag, const char *expect, const char *got)
     125  {
     126    int err = errno;
     127    if ((got == 0 && expect != 0)
     128        || (got != 0 && expect == 0)
     129        || (got != 0 && expect != 0 && strcmp(got, expect) != 0))
     130      {
     131        printf ("FAIL: %s: exp '%s' got '%s'\n",
     132                tag, expect ? expect : "(nil)",
     133                got ? got : "(nil)");
     134        error_occurred = true;
     135      }
     136    if ((expect == 0 || expect[0] == '*') && err != EINVAL)
     137      {
     138        printf ("FAIL: %s: exp '%s' got '%s'\n",
     139                tag, strerror (EINVAL), strerror (err));
     140        error_occurred = true;
     141      }
     142  }
     143  
     144  static void
     145  test_crypt (const char *tag,
     146              const char *phrase, const char *setting, const char *expect)
     147  {
     148    char *got = crypt (phrase, setting);
     149    check (tag, expect, got);
     150  }
     151  
     152  static void
     153  test_crypt_r (const char *tag,
     154                const char *phrase, const char *setting, const char *expect)
     155  {
     156    struct crypt_data data;
     157    memset (&data, 0, sizeof data);
     158    char *got = crypt_r (phrase, setting, &data);
     159    check (tag, expect, got);
     160  }
     161  
     162  static void
     163  test_crypt_rn (const char *tag,
     164                 const char *phrase, const char *setting, const char *expect)
     165  {
     166    struct crypt_data data;
     167    memset (&data, 0, sizeof data);
     168  
     169    char *got = crypt_rn (phrase, setting, &data, (int) sizeof data);
     170    check (tag, expect, got);
     171  }
     172  
     173  static void
     174  test_crypt_ra (const char *tag,
     175                 const char *phrase, const char *setting, const char *expect)
     176  {
     177    /* cheat - crypt_ra doesn't actually care whether its scratch area
     178       is on the heap as long as it's big enough */
     179    struct crypt_data data;
     180    memset (&data, 0, sizeof data);
     181    void *datap = &data;
     182    int datas = (int) sizeof data;
     183  
     184    char *got = crypt_ra (phrase, setting, &datap, &datas);
     185    check (tag, expect, got);
     186  }
     187  
     188  #if ENABLE_FAILURE_TOKENS
     189  # define FT0 "*0"
     190  # define FT1 "*1"
     191  #else
     192  # define FT0 0
     193  # define FT1 0
     194  #endif
     195  
     196  /* PAGE should point to PAGESIZE bytes of read-write memory followed
     197     by another PAGESIZE bytes of inaccessible memory.  */
     198  
     199  static void
     200  do_tests(char *page, size_t pagesize)
     201  {
     202    static const char phrase[] =
     203      "the ritual question of how much is two plus two";
     204  
     205    /* This copy operation intentionally omits the NUL; 'p1' points to a
     206       sequence of nonzero bytes followed immediately by inaccessible
     207       memory.  */
     208    memcpy (page + pagesize - (sizeof phrase - 1), phrase, sizeof phrase - 1);
     209    const char *p1 = page + pagesize - (sizeof phrase - 1);
     210    const char *p2 = page + pagesize;
     211    size_t i;
     212  
     213    /* Our crypt*() functions return NULL / a failure token, with errno set
     214       to EINVAL, when either the setting or the phrase argument is NULL.
     215       ASan's interceptors for crypt*() instead crash the program when either
     216       argument is NULL -- this is arguably a better choice, but for
     217       compatibility's sake we can't change what our functions do.  There is
     218       no way to disable interception of specific functions as far as I can
     219       tell.  Therefore, these tests are skipped when compiled with ASan.  */
     220  #ifndef XCRYPT_USE_ASAN
     221    /* When SETTING is null, it shouldn't matter what PHRASE is.  */
     222    expect_no_fault ("0.0.crypt",    0,  0, FT0, test_crypt);
     223    expect_no_fault ("0.0.crypt_r",  0,  0, FT0, test_crypt_r);
     224    expect_no_fault ("0.0.crypt_rn", 0,  0, 0,    test_crypt_rn);
     225    expect_no_fault ("0.0.crypt_ra", 0,  0, 0,    test_crypt_ra);
     226  
     227    expect_no_fault ("''.0.crypt",    "", 0, FT0, test_crypt);
     228    expect_no_fault ("''.0.crypt_r",  "", 0, FT0, test_crypt_r);
     229    expect_no_fault ("''.0.crypt_rn", "", 0, 0,    test_crypt_rn);
     230    expect_no_fault ("''.0.crypt_ra", "", 0, 0,    test_crypt_ra);
     231  
     232    expect_no_fault ("ph.0.crypt",    phrase, 0, FT0, test_crypt);
     233    expect_no_fault ("ph.0.crypt_r",  phrase, 0, FT0, test_crypt_r);
     234    expect_no_fault ("ph.0.crypt_rn", phrase, 0, 0,    test_crypt_rn);
     235    expect_no_fault ("ph.0.crypt_ra", phrase, 0, 0,    test_crypt_ra);
     236  
     237    expect_no_fault ("p1.0.crypt",    p1, 0, FT0, test_crypt);
     238    expect_no_fault ("p1.0.crypt_r",  p1, 0, FT0, test_crypt_r);
     239    expect_no_fault ("p1.0.crypt_rn", p1, 0, 0,    test_crypt_rn);
     240    expect_no_fault ("p1.0.crypt_ra", p1, 0, 0,    test_crypt_ra);
     241  
     242    expect_no_fault ("p2.0.crypt",    p2, 0, FT0, test_crypt);
     243    expect_no_fault ("p2.0.crypt_r",  p2, 0, FT0, test_crypt_r);
     244    expect_no_fault ("p2.0.crypt_rn", p2, 0, 0,    test_crypt_rn);
     245    expect_no_fault ("p2.0.crypt_ra", p2, 0, 0,    test_crypt_ra);
     246  
     247    /* Conversely, when PHRASE is null,
     248       it shouldn't matter what SETTING is...  */
     249    expect_no_fault ("0.''.crypt",    0, "", FT0,  test_crypt);
     250    expect_no_fault ("0.''.crypt_r",  0, "", FT0,  test_crypt_r);
     251    expect_no_fault ("0.''.crypt_rn", 0, "", 0,    test_crypt_rn);
     252    expect_no_fault ("0.''.crypt_ra", 0, "", 0,    test_crypt_ra);
     253  
     254    expect_no_fault ("0.'*'.crypt",    0, "*", FT0,  test_crypt);
     255    expect_no_fault ("0.'*'.crypt_r",  0, "*", FT0,  test_crypt_r);
     256    expect_no_fault ("0.'*'.crypt_rn", 0, "*", 0,    test_crypt_rn);
     257    expect_no_fault ("0.'*'.crypt_ra", 0, "*", 0,    test_crypt_ra);
     258  
     259    expect_no_fault ("0.'*0'.crypt",    0, "*0", FT1,  test_crypt);
     260    expect_no_fault ("0.'*0'.crypt_r",  0, "*0", FT1,  test_crypt_r);
     261    expect_no_fault ("0.'*0'.crypt_rn", 0, "*0", 0,    test_crypt_rn);
     262    expect_no_fault ("0.'*0'.crypt_ra", 0, "*0", 0,    test_crypt_ra);
     263  
     264    expect_no_fault ("0.'*1'.crypt",    0, "*1", FT0,  test_crypt);
     265    expect_no_fault ("0.'*1'.crypt_r",  0, "*1", FT0,  test_crypt_r);
     266    expect_no_fault ("0.'*1'.crypt_rn", 0, "*1", 0,    test_crypt_rn);
     267    expect_no_fault ("0.'*1'.crypt_ra", 0, "*1", 0,    test_crypt_ra);
     268  
     269    expect_no_fault ("0.p1.crypt",    0, p1, FT0,  test_crypt);
     270    expect_no_fault ("0.p1.crypt_r",  0, p1, FT0,  test_crypt_r);
     271    expect_no_fault ("0.p1.crypt_rn", 0, p1, 0,    test_crypt_rn);
     272    expect_no_fault ("0.p1.crypt_ra", 0, p1, 0,    test_crypt_ra);
     273  
     274    /* ... except for the case where SETTING is nonnull but there are
     275       fewer than 2 readable characters at SETTING, in which case we'll
     276       crash before we get to the null check in do_crypt.  This is a
     277       bug, but it's impractical to fix without breaking the property
     278       that 'crypt' _never_ creates a failure token that is equal to the
     279       setting string, which is more important than this corner case.  */
     280    expect_a_fault ("0.p2.crypt",    0, p2, FT0,  test_crypt);
     281    expect_a_fault ("0.p2.crypt_r",  0, p2, FT0,  test_crypt_r);
     282    expect_a_fault ("0.p2.crypt_rn", 0, p2, 0,    test_crypt_rn);
     283    expect_a_fault ("0.p2.crypt_ra", 0, p2, 0,    test_crypt_ra);
     284  #endif /* no ASan */
     285  
     286    /* When SETTING is valid, passing an invalid string as PHRASE should
     287       crash reliably.  */
     288    for (i = 0; i < ARRAY_SIZE (settings); i++)
     289      {
     290        snprintf (page, pagesize, "p1.'%s'.crypt", settings[i]);
     291        expect_a_fault (page, p1, settings[i], FT0,  test_crypt);
     292  
     293        snprintf (page, pagesize, "p1.'%s'.crypt_r", settings[i]);
     294        expect_a_fault (page, p1, settings[i], FT0,  test_crypt_r);
     295  
     296        snprintf (page, pagesize, "p1.'%s'.crypt_rn", settings[i]);
     297        expect_a_fault (page, p1, settings[i], 0,    test_crypt_rn);
     298  
     299        snprintf (page, pagesize, "p1.'%s'.crypt_ra", settings[i]);
     300        expect_a_fault (page, p1, settings[i], 0,    test_crypt_ra);
     301  
     302        snprintf (page, pagesize, "p2.'%s'.crypt", settings[i]);
     303        expect_a_fault (page, p2, settings[i], FT0,  test_crypt);
     304  
     305        snprintf (page, pagesize, "p2.'%s'.crypt_r", settings[i]);
     306        expect_a_fault (page, p2, settings[i], FT0,  test_crypt_r);
     307  
     308        snprintf (page, pagesize, "p2.'%s'.crypt_rn", settings[i]);
     309        expect_a_fault (page, p2, settings[i], 0,    test_crypt_rn);
     310  
     311        snprintf (page, pagesize, "p2.'%s'.crypt_ra", settings[i]);
     312        expect_a_fault (page, p2, settings[i], 0,    test_crypt_ra);
     313      }
     314  
     315    /* Conversely, when PHRASE is valid, passing an invalid string as SETTING
     316       should crash reliably.  */
     317    expect_a_fault ("ph.p2.crypt",    phrase, p2, FT0,  test_crypt);
     318    expect_a_fault ("ph.p2.crypt_r",  phrase, p2, FT0,  test_crypt_r);
     319    expect_a_fault ("ph.p2.crypt_rn", phrase, p2, 0,    test_crypt_rn);
     320    expect_a_fault ("ph.p2.crypt_ra", phrase, p2, 0,    test_crypt_ra);
     321  
     322    for (i = 0; i < ARRAY_SIZE (settings); i++)
     323      {
     324        p1 = memcpy (page + pagesize - strlen (settings[i]),
     325                     settings[i], strlen (settings[i]));
     326  
     327        snprintf (page, pagesize, "ph.'%s'.crypt", settings[i]);
     328        expect_a_fault (page, phrase, p1, FT0, test_crypt);
     329  
     330        snprintf (page, pagesize, "ph.'%s'.crypt_r", settings[i]);
     331        expect_a_fault (page, phrase, p1, FT0, test_crypt_r);
     332  
     333        snprintf (page, pagesize, "ph.'%s'.crypt_rn", settings[i]);
     334        expect_a_fault (page, phrase, p1, 0,    test_crypt_rn);
     335  
     336        snprintf (page, pagesize, "ph.'%s'.crypt_ra", settings[i]);
     337        expect_a_fault (page, phrase, p1, 0,    test_crypt_ra);
     338      }
     339  }
     340  
     341  int
     342  main (void)
     343  {
     344    /* Set up a two-page region whose first page is read-write and
     345       whose second page is inaccessible.  */
     346    long pagesize_l = sysconf (_SC_PAGESIZE);
     347    if (pagesize_l < 256)
     348      {
     349        printf ("ERROR: pagesize of %ld is too small\n", pagesize_l);
     350        return 99;
     351      }
     352  
     353    size_t pagesize = (size_t) pagesize_l;
     354    char *page = mmap (0, pagesize * 2, PROT_READ|PROT_WRITE,
     355                       MAP_PRIVATE|MAP_ANON, -1, 0);
     356    if (page == MAP_FAILED)
     357      {
     358        perror ("mmap");
     359        return 99;
     360      }
     361    memset (page, 'x', pagesize * 2);
     362    if (mprotect (page + pagesize, pagesize, PROT_NONE))
     363      {
     364        perror ("mprotect");
     365        return 99;
     366      }
     367  
     368    struct sigaction sa, os, ob;
     369    sigfillset (&sa.sa_mask);
     370    sa.sa_flags = SA_RESTART;
     371    sa.sa_handler = segv_handler;
     372    if (sigaction (SIGBUS, &sa, &ob) || sigaction (SIGSEGV, &sa, &os))
     373      {
     374        perror ("sigaction");
     375        return 1;
     376      }
     377  
     378    do_tests (page, pagesize);
     379  
     380    sigaction (SIGBUS, &ob, 0);
     381    sigaction (SIGSEGV, &os, 0);
     382  
     383    return error_occurred;
     384  }