unit1655.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 2019 - 2022, 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 "curlcheck.h"
  25. #include "doh.h" /* from the lib dir */
  26. static CURLcode unit_setup(void)
  27. {
  28. /* whatever you want done first */
  29. return CURLE_OK;
  30. }
  31. static void unit_stop(void)
  32. {
  33. /* done before shutting down and exiting */
  34. }
  35. #ifndef CURL_DISABLE_DOH
  36. UNITTEST_START
  37. /*
  38. * Prove detection of write overflow using a short buffer and a name
  39. * of maximal valid length.
  40. *
  41. * Prove detection of other invalid input.
  42. */
  43. do {
  44. static const char max[] =
  45. /* ..|....1.........2.........3.........4.........5.........6... */
  46. /* 3456789012345678901234567890123456789012345678901234567890123 */
  47. "this.is.a.maximum-length.hostname." /* 34: 34 */
  48. "with-no-label-of-greater-length-than-the-sixty-three-characters."
  49. /* 64: 98 */
  50. "specified.in.the.RFCs." /* 22: 120 */
  51. "and.with.a.QNAME.encoding.whose.length.is.exactly." /* 50: 170 */
  52. "the.maximum.length.allowed." /* 27: 197 */
  53. "that.is.two-hundred.and.fifty-six." /* 34: 231 */
  54. "including.the.last.null." /* 24: 255 */
  55. "";
  56. static const char toolong[] =
  57. /* ..|....1.........2.........3.........4.........5.........6... */
  58. /* 3456789012345678901234567890123456789012345678901234567890123 */
  59. "here.is.a.hostname.which.is.just.barely.too.long." /* 49: 49 */
  60. "to.be.encoded.as.a.QNAME.of.the.maximum.allowed.length."
  61. /* 55: 104 */
  62. "which.is.256.including.a.final.zero-length.label." /* 49: 153 */
  63. "representing.the.root.node.so.that.a.name.with." /* 47: 200 */
  64. "a.trailing.dot.may.have.up.to." /* 30: 230 */
  65. "255.characters.never.more." /* 26: 256 */
  66. "";
  67. static const char emptylabel[] =
  68. "this.is.an.otherwise-valid.hostname."
  69. ".with.an.empty.label.";
  70. static const char outsizelabel[] =
  71. "this.is.an.otherwise-valid.hostname."
  72. "with-a-label-of-greater-length-than-the-sixty-three-characters-"
  73. "specified.in.the.RFCs.";
  74. int i;
  75. struct test {
  76. const char *name;
  77. const DOHcode expected_result;
  78. };
  79. /* plays the role of struct dnsprobe in urldata.h */
  80. struct demo {
  81. unsigned char dohbuffer[255 + 16]; /* deliberately short buffer */
  82. unsigned char canary1;
  83. unsigned char canary2;
  84. unsigned char canary3;
  85. };
  86. const struct test playlist[4] = {
  87. { toolong, DOH_DNS_NAME_TOO_LONG }, /* expect early failure */
  88. { emptylabel, DOH_DNS_BAD_LABEL }, /* also */
  89. { outsizelabel, DOH_DNS_BAD_LABEL }, /* also */
  90. { max, DOH_OK } /* expect buffer overwrite */
  91. };
  92. for(i = 0; i < (int)(sizeof(playlist)/sizeof(*playlist)); i++) {
  93. const char *name = playlist[i].name;
  94. size_t olen = 100000;
  95. struct demo victim;
  96. DOHcode d;
  97. victim.canary1 = 87; /* magic numbers, arbitrarily picked */
  98. victim.canary2 = 35;
  99. victim.canary3 = 41;
  100. d = doh_encode(name, DNS_TYPE_A, victim.dohbuffer,
  101. sizeof(struct demo), /* allow room for overflow */
  102. &olen);
  103. fail_unless(d == playlist[i].expected_result,
  104. "result returned was not as expected");
  105. if(d == playlist[i].expected_result) {
  106. if(name == max) {
  107. fail_if(victim.canary1 == 87,
  108. "demo one-byte buffer overwrite did not happen");
  109. }
  110. else {
  111. fail_unless(victim.canary1 == 87,
  112. "one-byte buffer overwrite has happened");
  113. }
  114. fail_unless(victim.canary2 == 35,
  115. "two-byte buffer overwrite has happened");
  116. fail_unless(victim.canary3 == 41,
  117. "three-byte buffer overwrite has happened");
  118. }
  119. else {
  120. if(d == DOH_OK) {
  121. fail_unless(olen <= sizeof(victim.dohbuffer), "wrote outside bounds");
  122. fail_unless(olen > strlen(name), "unrealistic low size");
  123. }
  124. }
  125. }
  126. } while(0);
  127. /* run normal cases and try to trigger buffer length related errors */
  128. do {
  129. DNStype dnstype = DNS_TYPE_A;
  130. unsigned char buffer[128];
  131. const size_t buflen = sizeof(buffer);
  132. const size_t magic1 = 9765;
  133. size_t olen1 = magic1;
  134. const char *sunshine1 = "a.com";
  135. const char *dotshine1 = "a.com.";
  136. const char *sunshine2 = "aa.com";
  137. size_t olen2;
  138. DOHcode ret2;
  139. size_t olen;
  140. DOHcode ret = doh_encode(sunshine1, dnstype, buffer, buflen, &olen1);
  141. fail_unless(ret == DOH_OK, "sunshine case 1 should pass fine");
  142. fail_if(olen1 == magic1, "olen has not been assigned properly");
  143. fail_unless(olen1 > strlen(sunshine1), "bad out length");
  144. /* with a trailing dot, the response should have the same length */
  145. olen2 = magic1;
  146. ret2 = doh_encode(dotshine1, dnstype, buffer, buflen, &olen2);
  147. fail_unless(ret2 == DOH_OK, "dotshine case should pass fine");
  148. fail_if(olen2 == magic1, "olen has not been assigned properly");
  149. fail_unless(olen1 == olen2, "olen should not grow for a trailing dot");
  150. /* add one letter, the response should be one longer */
  151. olen2 = magic1;
  152. ret2 = doh_encode(sunshine2, dnstype, buffer, buflen, &olen2);
  153. fail_unless(ret2 == DOH_OK, "sunshine case 2 should pass fine");
  154. fail_if(olen2 == magic1, "olen has not been assigned properly");
  155. fail_unless(olen1 + 1 == olen2, "olen should grow with the hostname");
  156. /* pass a short buffer, should fail */
  157. ret = doh_encode(sunshine1, dnstype, buffer, olen1 - 1, &olen);
  158. fail_if(ret == DOH_OK, "short buffer should have been noticed");
  159. /* pass a minimum buffer, should succeed */
  160. ret = doh_encode(sunshine1, dnstype, buffer, olen1, &olen);
  161. fail_unless(ret == DOH_OK, "minimal length buffer should be long enough");
  162. fail_unless(olen == olen1, "bad buffer length");
  163. } while(0);
  164. UNITTEST_STOP
  165. #else /* CURL_DISABLE_DOH */
  166. UNITTEST_START
  167. {
  168. return 1; /* nothing to do, just fail */
  169. }
  170. UNITTEST_STOP
  171. #endif