fuzzmain.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #include "civetweb.h"
  2. #include <errno.h>
  3. #include <stdint.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #if defined(_WIN32)
  7. #error "Currently not supported"
  8. #else
  9. #include <unistd.h>
  10. #define test_sleep(x) (sleep(x))
  11. #include <arpa/inet.h>
  12. #include <netinet/in.h>
  13. #include <netinet/ip.h>
  14. #include <sys/socket.h>
  15. #include <sys/types.h>
  16. typedef int SOCKET;
  17. #define closesocket(a) (close(a))
  18. #endif
  19. static uint64_t call_count = 0;
  20. static struct mg_context *ctx;
  21. static const char *OPTIONS[] = {"listening_ports",
  22. "8080,8443s",
  23. "document_root",
  24. "fuzztest/docroot",
  25. "ssl_certificate",
  26. "resources/cert/server.pem",
  27. NULL,
  28. NULL};
  29. static void
  30. init_civetweb(void)
  31. {
  32. struct mg_callbacks callbacks;
  33. memset(&callbacks, 0, sizeof(callbacks));
  34. ctx = mg_start(&callbacks, 0, OPTIONS);
  35. if (!ctx) {
  36. fprintf(stderr, "\nCivetWeb test server failed to start\n");
  37. abort();
  38. }
  39. /* Give server 5 seconds to start, before flooding with requests.
  40. * Don't know if this is required for fuzz-tests, but it was helpful
  41. * when testing starting/stopping the server multiple times in test
  42. * container environments. */
  43. test_sleep(5);
  44. }
  45. static int
  46. test_http_request(const char *server,
  47. uint16_t port,
  48. int use_ssl,
  49. const char *uri)
  50. {
  51. /* Client var */
  52. struct mg_connection *client;
  53. char client_err_buf[256];
  54. char client_data_buf[4096];
  55. const struct mg_response_info *client_ri;
  56. int64_t data_read;
  57. int r;
  58. client = mg_connect_client(
  59. server, port, use_ssl, client_err_buf, sizeof(client_err_buf));
  60. if ((client == NULL) || (0 != strcmp(client_err_buf, ""))) {
  61. fprintf(stderr,
  62. "%s connection to server [%s] port [%u] failed: [%s]\n",
  63. use_ssl ? "HTTPS" : "HTTP",
  64. server,
  65. port,
  66. client_err_buf);
  67. if (client) {
  68. mg_close_connection(client);
  69. }
  70. /* In heavy fuzz testing, sometimes we run out of available sockets.
  71. * Wait for some seconds, and retry. */
  72. test_sleep(5);
  73. /* retry once */
  74. client = mg_connect_client(
  75. server, port, use_ssl, client_err_buf, sizeof(client_err_buf));
  76. if (!client) {
  77. fprintf(stderr, "Retry: error\n");
  78. return 1;
  79. }
  80. fprintf(stderr, "Retry: success\n");
  81. }
  82. mg_printf(client, "GET %s HTTP/1.0\r\n\r\n", uri);
  83. r = mg_get_response(client, client_err_buf, sizeof(client_err_buf), 10000);
  84. if ((r < 0) || (0 != strcmp(client_err_buf, ""))) {
  85. mg_close_connection(client);
  86. return 1;
  87. }
  88. client_ri = mg_get_response_info(client);
  89. if (client_ri == NULL) {
  90. mg_close_connection(client);
  91. return 1;
  92. }
  93. data_read = 0;
  94. while (data_read < client_ri->content_length) {
  95. /* store the first sizeof(client_data_buf) bytes
  96. * of the HTTP response. */
  97. r = mg_read(client,
  98. client_data_buf + data_read,
  99. sizeof(client_data_buf) - (size_t)data_read);
  100. if (r > 0) {
  101. data_read += r;
  102. }
  103. /* buffer filled? */
  104. if (sizeof(client_data_buf) == (size_t)data_read) {
  105. /* ignore the rest */
  106. while (r > 0) {
  107. char trash[1024];
  108. r = mg_read(client, trash, sizeof(trash));
  109. }
  110. break;
  111. }
  112. }
  113. /* Nothing left to read */
  114. r = mg_read(client, client_data_buf, sizeof(client_data_buf));
  115. if (r != 0) {
  116. mg_close_connection(client);
  117. return 1;
  118. }
  119. mg_close_connection(client);
  120. return 0;
  121. }
  122. static int
  123. LLVMFuzzerTestOneInput_URI(const uint8_t *data, size_t size)
  124. {
  125. static char URI[1024 * 64]; /* static, to avoid stack overflow */
  126. if (call_count == 0) {
  127. memset(URI, 0, sizeof(URI));
  128. init_civetweb();
  129. }
  130. call_count++;
  131. if (size < sizeof(URI)) {
  132. memcpy(URI, data, size);
  133. URI[size] = 0;
  134. } else {
  135. return 1;
  136. }
  137. printf("URI: %s\n", URI);
  138. return test_http_request("127.0.0.1", 8080, 0, URI);
  139. }
  140. static int
  141. LLVMFuzzerTestOneInput_REQUEST(const uint8_t *data, size_t size)
  142. {
  143. if (call_count == 0) {
  144. init_civetweb();
  145. }
  146. call_count++;
  147. int r;
  148. SOCKET sock = socket(AF_INET, SOCK_STREAM, 6);
  149. if (sock == -1) {
  150. r = errno;
  151. fprintf(stderr, "Error: Cannot create socket [%s]\n", strerror(r));
  152. return 1;
  153. }
  154. struct sockaddr_in sin;
  155. memset(&sin, 0, sizeof(sin));
  156. sin.sin_family = AF_INET;
  157. sin.sin_addr.s_addr = inet_addr("127.0.0.1");
  158. sin.sin_port = htons(8080);
  159. r = connect(sock, (struct sockaddr *)&sin, sizeof(sin));
  160. if (r != 0) {
  161. r = errno;
  162. fprintf(stderr, "Error: Cannot connect [%s]\n", strerror(r));
  163. closesocket(sock);
  164. return 1;
  165. }
  166. char trash[1024];
  167. r = send(sock, data, size, 0);
  168. if (r != size) {
  169. fprintf(stderr, "Warning: %i bytes sent (TODO: Repeat)\n", r);
  170. }
  171. int data_read = 0;
  172. while ((r = recv(sock, trash, sizeof(trash), 0)) > 0) {
  173. data_read += r;
  174. };
  175. shutdown(sock, SHUT_RDWR);
  176. closesocket(sock);
  177. static int max_data_read = 0;
  178. if (data_read > max_data_read) {
  179. max_data_read = data_read;
  180. printf("GOT data: %i\n", data_read);
  181. }
  182. }
  183. int
  184. LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
  185. {
  186. #if defined(TEST_FUZZ1)
  187. /* fuzz target 1: different URI for HTTP/1 server */
  188. return LLVMFuzzerTestOneInput_URI(data, size);
  189. #elif defined(TEST_FUZZ2)
  190. /* fuzz target 2: different requests for HTTP/1 server */
  191. return LLVMFuzzerTestOneInput_REQUEST(data, size);
  192. #else
  193. /* planned targets */
  194. /* fuzz target 3: different responses for HTTP/1 client */
  195. /* fuzz target 4: different requests for HTTP/2 server */
  196. /* fuzz target 5: calling an internal server test function,
  197. * bypassing network sockets */
  198. #error "Unknown fuzz target"
  199. #endif
  200. }