bel2125 5 роки тому
батько
коміт
1bd3e71be1
3 змінених файлів з 226 додано та 2 видалено
  1. 14 2
      Makefile
  2. 1 0
      fuzz/docroot/test.txt
  3. 211 0
      fuzz/fuzzmain.c

+ 14 - 2
Makefile

@@ -45,7 +45,7 @@ USE_STACK_SIZE ?= 102400
 BUILD_DIRS = $(BUILD_DIR) $(BUILD_DIR)/src $(BUILD_DIR)/resources
 
 LIB_SOURCES = src/civetweb.c
-LIB_INLINE  = src/mod_lua.inl src/md5.inl
+LIB_INLINE  = src/*.inl
 APP_SOURCES = src/main.c
 WINDOWS_RESOURCES = resources/res.rc
 UNIT_TEST_SOURCES = test/unit_test.c
@@ -71,6 +71,18 @@ LIBS = -lpthread -lm
 
 ifdef WITH_DEBUG
   CFLAGS += -g -DDEBUG
+else ifdef TEST_ASAN
+  CFLAGS += -g -fsanitize=address
+  CC = clang
+  CXX = clang++
+else ifdef TEST_FUZZ
+  CFLAGS += -g -fsanitize=address,fuzzer
+  CC = clang
+  CXX = clang++
+  BUILD_DIRS += $(BUILD_DIR)/fuzz
+  APP_SOURCES = fuzz/fuzzmain.c
+  OBJECTS = $(LIB_SOURCES:.c=.o) $(APP_SOURCES:.c=.o) 
+  CFLAGS += -DTEST_FUZZ$(TEST_FUZZ)
 else
   CFLAGS += -O2 -DNDEBUG
 endif
@@ -239,7 +251,7 @@ help:
 	@echo "make install-lib         install the static library"
 	@echo "make slib                build a shared library"
 	@echo "make install-slib        install the shared library"
-	@echo "make unit_test           build unit tests executable"
+	@echo "make unit_test           (obsolete - unit tests use cmake now)"
 	@echo ""
 	@echo " Make Options"
 	@echo "   WITH_LUA=1            build with Lua support; include Lua as static library"

+ 1 - 0
fuzz/docroot/test.txt

@@ -0,0 +1 @@
+Response text from file

+ 211 - 0
fuzz/fuzzmain.c

@@ -0,0 +1,211 @@
+#include "civetweb.h"
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(_WIN32)
+#error "Currently not supported"
+#else
+	
+#include <unistd.h>
+#define test_sleep(x) (sleep(x))
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+typedef int SOCKET;
+#define closesocket(a) (close(a))
+
+#endif
+
+
+static uint64_t call_count = 0;
+
+static struct mg_context *ctx;
+static const char *OPTIONS[] = {
+	"listening_ports", "8080,8443s",
+#ifdef _WIN32
+	"document_root",   "fuzz\\docroot",
+	"ssl_certificate", "resources\\cert\\server.pem",
+#else
+	"document_root",   "fuzz/docroot",
+	"ssl_certificate", "resources/cert/server.pem",
+#endif
+	NULL, NULL
+};
+
+
+static void
+init_civetweb(void)
+{
+	struct mg_callbacks callbacks;
+	memset(&callbacks, 0, sizeof(callbacks));
+
+	ctx = mg_start(&callbacks, 0, OPTIONS);
+	
+	if (!ctx) {
+		fprintf(stderr, "\nCivetWeb test server failed to start\n");
+		abort();
+	}
+
+	/* Give server 5 seconds to start, before flooding with requests.
+	 * Don't know if this is required for fuzz-tests, but it was helpful
+	 * when testing starting/stopping the server multiple times in test
+	 * container environments. */
+	test_sleep(5);
+}
+
+
+static int
+test_http_request(const char *server,
+                  uint16_t port,
+                  int use_ssl,
+                  const char *uri)
+{
+	/* Client var */
+	struct mg_connection *client;
+	char client_err_buf[256];
+	char client_data_buf[4096];
+	const struct mg_response_info *client_ri;
+	int64_t data_read;
+	int r;
+
+	client = mg_connect_client(
+	    server, port, use_ssl, client_err_buf, sizeof(client_err_buf));
+
+	if ((client == NULL) || (0 != strcmp(client_err_buf, ""))) {
+		fprintf(stderr, "%s connection to server [%s] port [%u] failed: [%s]\n",
+		             use_ssl ? "HTTPS" : "HTTP",
+		             server,
+		             port,
+		             client_err_buf);
+		if (client) {
+			mg_close_connection(client);
+		}
+		
+		/* In heavy fuzz testing, sometimes we run out of available sockets.
+		 * Wait for some seconds, and retry. */
+		test_sleep(5);
+
+		/* retry once */
+		client = mg_connect_client(
+			server, port, use_ssl, client_err_buf, sizeof(client_err_buf));
+		if (!client) {
+			fprintf(stderr, "Retry: error\n");
+			return 1;
+		}
+		fprintf(stderr, "Retry: success\n");
+	}
+
+	mg_printf(client, "GET %s HTTP/1.0\r\n\r\n", uri);
+
+	r = mg_get_response(client, client_err_buf, sizeof(client_err_buf), 10000);
+
+	if ((r < 0) || (0 != strcmp(client_err_buf, ""))) {
+		mg_close_connection(client);
+		return 1;		
+	}
+
+	client_ri = mg_get_response_info(client);
+	if (client_ri == NULL) {
+		mg_close_connection(client);
+		return 1;
+	}
+
+	data_read = 0;
+	while (data_read < client_ri->content_length) {
+		/* store the first sizeof(client_data_buf) bytes
+		 * of the HTTP response. */
+		r = mg_read(client,
+		            client_data_buf + data_read,
+		            sizeof(client_data_buf) - (size_t)data_read);
+		if (r > 0) {
+			data_read += r;
+		}
+		
+		/* buffer filled? */
+		if (sizeof(client_data_buf) == (size_t)data_read) {
+			/* ignore the rest */
+			while (r > 0) {
+				char trash[1024];
+				r = mg_read(client, trash, sizeof(trash));
+			}
+			break;
+		}
+	}
+
+	/* Nothing left to read */
+	r = mg_read(client, client_data_buf, sizeof(client_data_buf));
+	if (r != 0) {
+		mg_close_connection(client);
+		return 1;
+	}
+
+	mg_close_connection(client);
+	return 0;
+}
+
+
+static int
+LLVMFuzzerTestOneInput_URI(const uint8_t *data, size_t size)
+{
+	static char URI[1024 * 64]; /* static, to avoid stack overflow */
+
+	if (call_count == 0) {
+		memset(URI, 0, sizeof(URI));
+		init_civetweb();
+	}
+	call_count++;
+
+	if (size < sizeof(URI)) {
+		memcpy(URI, data, size);
+		URI[size] = 0;
+	} else {
+		return 1;
+	}
+	
+	printf("URI: %s\n", URI);
+
+	return test_http_request("127.0.0.1", 8080, 0, URI);
+}
+
+
+static int
+LLVMFuzzerTestOneInput_REQUEST(const uint8_t *data, size_t size)
+{
+	if (call_count == 0) {
+		init_civetweb();
+	}
+	call_count++;	
+	
+	SOCKET sock = socket(AF_INET, SOCK_STREAM, 6);
+	struct sockaddr_in sin;
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(8080);
+	sin.sin_addr.s_addr = htonl(0x7F000001);
+	connect(sock, (struct sockaddr *)&sin, sizeof(sin));
+	
+	char trash[1024];
+	send(sock, data, size, 0);
+	int r, data_read = 0; 
+	while ((r = recv(sock, trash, sizeof(trash), 0)) > 0) {
+		data_read += r;
+	};
+	
+	shutdown(sock, SHUT_RDWR);
+	closesocket(sock);
+	
+	static int max_data_read = 0;
+	if (data_read>max_data_read) {
+		max_data_read = data_read;
+		printf("GOT data: %i\n", data_read);
+	}
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	return LLVMFuzzerTestOneInput_REQUEST(data, size);
+}