fuzzmain.c 4.8 KB

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