quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

unit1655.c (7104B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 #include "unitcheck.h"
     25 
     26 #include "doh.h" /* from the lib dir */
     27 
     28 static CURLcode test_unit1655(char *arg)
     29 {
     30   UNITTEST_BEGIN_SIMPLE
     31 
     32 #ifndef CURL_DISABLE_DOH
     33   /*
     34    * Prove detection of write overflow using a short buffer and a name
     35    * of maximal valid length.
     36    *
     37    * Prove detection of other invalid input.
     38    */
     39   do {
     40     static const char max[] =
     41       /* ..|....1.........2.........3.........4.........5.........6... */
     42       /* 3456789012345678901234567890123456789012345678901234567890123 */
     43       "this.is.a.maximum-length.hostname."                  /* 34:  34 */
     44       "with-no-label-of-greater-length-than-the-sixty-three-characters."
     45                                                             /* 64:  98 */
     46       "specified.in.the.RFCs."                              /* 22: 120 */
     47       "and.with.a.QNAME.encoding.whose.length.is.exactly."  /* 50: 170 */
     48       "the.maximum.length.allowed."                         /* 27: 197 */
     49       "that.is.two-hundred.and.fifty-six."                  /* 34: 231 */
     50       "including.the.last.null."                            /* 24: 255 */
     51       "";
     52     static const char toolong[] =
     53       /* ..|....1.........2.........3.........4.........5.........6... */
     54       /* 3456789012345678901234567890123456789012345678901234567890123 */
     55       "here.is.a.hostname.which.is.just.barely.too.long."   /* 49:  49 */
     56       "to.be.encoded.as.a.QNAME.of.the.maximum.allowed.length."
     57                                                             /* 55: 104 */
     58       "which.is.256.including.a.final.zero-length.label."   /* 49: 153 */
     59       "representing.the.root.node.so.that.a.name.with."     /* 47: 200 */
     60       "a.trailing.dot.may.have.up.to."                      /* 30: 230 */
     61       "255.characters.never.more."                          /* 26: 256 */
     62       "";
     63     static const char emptylabel[] =
     64       "this.is.an.otherwise-valid.hostname."
     65       ".with.an.empty.label.";
     66     static const char outsizelabel[] =
     67       "this.is.an.otherwise-valid.hostname."
     68       "with-a-label-of-greater-length-than-the-sixty-three-characters-"
     69       "specified.in.the.RFCs.";
     70     int i;
     71 
     72     struct test {
     73       const char *name;
     74       const DOHcode expected_result;
     75     };
     76 
     77     /* plays the role of struct dnsprobe in urldata.h */
     78     struct demo {
     79       unsigned char dohbuffer[255 + 16]; /* deliberately short buffer */
     80       unsigned char canary1;
     81       unsigned char canary2;
     82       unsigned char canary3;
     83     };
     84 
     85     const struct test playlist[4] = {
     86       { toolong, DOH_DNS_NAME_TOO_LONG },  /* expect early failure */
     87       { emptylabel, DOH_DNS_BAD_LABEL },   /* also */
     88       { outsizelabel, DOH_DNS_BAD_LABEL }, /* also */
     89       { max, DOH_OK }                      /* expect buffer overwrite */
     90     };
     91 
     92     for(i = 0; i < (int)(CURL_ARRAYSIZE(playlist)); i++) {
     93       const char *name = playlist[i].name;
     94       size_t olen = 100000;
     95       struct demo victim;
     96       DOHcode d;
     97 
     98       victim.canary1 = 87; /* magic numbers, arbitrarily picked */
     99       victim.canary2 = 35;
    100       victim.canary3 = 41;
    101       d = doh_req_encode(name, DNS_TYPE_A, victim.dohbuffer,
    102                          sizeof(struct demo), /* allow room for overflow */
    103                          &olen);
    104 
    105       fail_unless(d == playlist[i].expected_result,
    106                   "result returned was not as expected");
    107       if(d == playlist[i].expected_result) {
    108         if(name == max) {
    109           fail_if(victim.canary1 == 87,
    110                   "demo one-byte buffer overwrite did not happen");
    111         }
    112         else {
    113           fail_unless(victim.canary1 == 87,
    114                       "one-byte buffer overwrite has happened");
    115         }
    116         fail_unless(victim.canary2 == 35,
    117                     "two-byte buffer overwrite has happened");
    118         fail_unless(victim.canary3 == 41,
    119                     "three-byte buffer overwrite has happened");
    120       }
    121       else {
    122         if(d == DOH_OK) {
    123           fail_unless(olen <= sizeof(victim.dohbuffer),
    124             "wrote outside bounds");
    125           fail_unless(olen > strlen(name), "unrealistic low size");
    126         }
    127       }
    128     }
    129   } while(0);
    130 
    131   /* run normal cases and try to trigger buffer length related errors */
    132   do {
    133     DNStype dnstype = DNS_TYPE_A;
    134     unsigned char buffer[128];
    135     const size_t buflen = sizeof(buffer);
    136     const size_t magic1 = 9765;
    137     size_t olen1 = magic1;
    138     static const char *sunshine1 = "a.com";
    139     static const char *dotshine1 = "a.com.";
    140     static const char *sunshine2 = "aa.com";
    141     size_t olen2;
    142     DOHcode ret2;
    143     size_t olen;
    144 
    145     DOHcode ret = doh_req_encode(sunshine1, dnstype, buffer, buflen, &olen1);
    146     fail_unless(ret == DOH_OK, "sunshine case 1 should pass fine");
    147     fail_if(olen1 == magic1, "olen has not been assigned properly");
    148     fail_unless(olen1 > strlen(sunshine1), "bad out length");
    149 
    150     /* with a trailing dot, the response should have the same length */
    151     olen2 = magic1;
    152     ret2 = doh_req_encode(dotshine1, dnstype, buffer, buflen, &olen2);
    153     fail_unless(ret2 == DOH_OK, "dotshine case should pass fine");
    154     fail_if(olen2 == magic1, "olen has not been assigned properly");
    155     fail_unless(olen1 == olen2, "olen should not grow for a trailing dot");
    156 
    157     /* add one letter, the response should be one longer */
    158     olen2 = magic1;
    159     ret2 = doh_req_encode(sunshine2, dnstype, buffer, buflen, &olen2);
    160     fail_unless(ret2 == DOH_OK, "sunshine case 2 should pass fine");
    161     fail_if(olen2 == magic1, "olen has not been assigned properly");
    162     fail_unless(olen1 + 1 == olen2, "olen should grow with the hostname");
    163 
    164     /* pass a short buffer, should fail */
    165     ret = doh_req_encode(sunshine1, dnstype, buffer, olen1 - 1, &olen);
    166     fail_if(ret == DOH_OK, "short buffer should have been noticed");
    167 
    168     /* pass a minimum buffer, should succeed */
    169     ret = doh_req_encode(sunshine1, dnstype, buffer, olen1, &olen);
    170     fail_unless(ret == DOH_OK, "minimal length buffer should be long enough");
    171     fail_unless(olen == olen1, "bad buffer length");
    172   } while(0);
    173 
    174 #endif /* CURL_DISABLE_DOH */
    175 
    176   UNITTEST_END_SIMPLE
    177 }