diff --git a/lib/monkey/FUZZ.md b/lib/monkey/FUZZ.md new file mode 100644 index 00000000000..9074cdfac60 --- /dev/null +++ b/lib/monkey/FUZZ.md @@ -0,0 +1,33 @@ +# Fuzz Monkey + +## Prepare and Build + +Set the compiler path: + +``` +$ export CC=PATH/TO/honggfuzz/hfuzz_cc/hfuzz-clang +``` + +Build Monkey Fuzz tool with the following options: + +``` +$ cd build/ +$ cmake -DMK_LOCAL=On -DMK_DEBUG=On \ + -DMK_LIB_ONLY=On -DMK_SYSTEM_MALLOC=On \ + -DMK_FUZZ_MODE=On ../ +$ make +``` + +the build process will generate two executables: + +- mk_fuzz_me: to be used with honggfuzz for the Fuzzing process +- mk_check: used to validate a crash/fix + +## Run HonggFuzz with mk-fuzz-me + +Fuzz Monkey using Apache corpus and wordlist: + +``` +$ cd /path/to/honggfuzz/examples/apache-httpd/ +$ honggfuzz -Q --logfile out.log -f corpus_http1 -w ./httpd.wordlist -- /path/to/mk-fuzz-me +``` diff --git a/lib/monkey/fuzz/CMakeLists.txt b/lib/monkey/fuzz/CMakeLists.txt new file mode 100644 index 00000000000..48100f5f386 --- /dev/null +++ b/lib/monkey/fuzz/CMakeLists.txt @@ -0,0 +1,11 @@ +set(src + mk_fuzz_me.c) + +add_executable(mk_fuzz_me ${src}) +target_link_libraries(mk_fuzz_me monkey-core-static) + +set(src + mk_check.c) + +add_executable(mk_check ${src}) +target_link_libraries(mk_check monkey-core-static) diff --git a/lib/monkey/fuzz/mk_check.c b/lib/monkey/fuzz/mk_check.c new file mode 100644 index 00000000000..acae6cba0b3 --- /dev/null +++ b/lib/monkey/fuzz/mk_check.c @@ -0,0 +1,113 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#include + +#include +#include +#include +#include + +#define API_ADDR "127.0.0.1" +#define API_PORT "8080" + +/* Main context set as global so the signal handler can use it */ +mk_ctx_t *ctx; + +void cb_main(mk_request_t *request, void *data) +{ + (void) data; + + mk_http_status(request, 200); + mk_http_header(request, "X-Monkey", 8, "OK", 2); + + mk_http_send(request, ":)\n", 3, NULL); + mk_http_done(request); +} + +void cb_test_chunks(mk_request_t *request, void *data) +{ + int i = 0; + int len; + char tmp[32]; + (void) data; + + mk_http_status(request, 200); + mk_http_header(request, "X-Monkey", 8, "OK", 2); + + for (i = 0; i < 1000; i++) { + len = snprintf(tmp, sizeof(tmp) -1, "test-chunk %6i\n ", i); + mk_http_send(request, tmp, len, NULL); + } + mk_http_done(request); +} + +void cb_test_big_chunk(mk_request_t *request, void *data) +{ + size_t chunk_size = 1024000000; + char *chunk; + (void) data; + + mk_http_status(request, 200); + mk_http_header(request, "X-Monkey", 8, "OK", 2); + + chunk = calloc(1, chunk_size); + mk_http_send(request, chunk, chunk_size, NULL); + free(chunk); + mk_http_done(request); +} + + +static void signal_handler(int signal) +{ + write(STDERR_FILENO, "[engine] caught signal\n", 23); + + switch (signal) { + case SIGTERM: + case SIGINT: + mk_stop(ctx); + mk_destroy(ctx); + _exit(EXIT_SUCCESS); + default: + break; + } +} + +static void signal_init() +{ + signal(SIGINT, &signal_handler); + signal(SIGTERM, &signal_handler); +} + +int main() +{ + int vid; + + signal_init(); + + ctx = mk_create(); + if (!ctx) { + return -1; + } + + mk_config_set(ctx, + "Listen", API_PORT, + NULL); + + vid = mk_vhost_create(ctx, NULL); + mk_vhost_set(ctx, vid, + "Name", "monotop", + NULL); + mk_vhost_handler(ctx, vid, "/test_chunks", cb_test_chunks, NULL); + mk_vhost_handler(ctx, vid, "/test_big_chunk", cb_test_big_chunk, NULL); + mk_vhost_handler(ctx, vid, "/", cb_main, NULL); + + mk_info("Service: http://%s:%s/test_chunks", API_ADDR, API_PORT); + mk_start(ctx); + + sleep(3600); + + mk_stop(ctx); + mk_destroy(ctx); + + return 0; +} diff --git a/lib/monkey/fuzz/mk_fuzz_me.c b/lib/monkey/fuzz/mk_fuzz_me.c new file mode 100644 index 00000000000..0a88d3f1f4c --- /dev/null +++ b/lib/monkey/fuzz/mk_fuzz_me.c @@ -0,0 +1,143 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#include + +#include +#include +#include +#include + +#define API_ADDR "127.0.0.1" +#define API_PORT "8080" + +/* Main context set as global so the signal handler can use it */ +mk_ctx_t *ctx; + +void cb_main(mk_request_t *request, void *data) +{ + (void) data; + + mk_http_status(request, 200); + mk_http_header(request, "X-Monkey", 8, "OK", 2); + mk_http_send(request, ":)\n", 3, NULL); + mk_http_done(request); +} + +void cb_test_chunks(mk_request_t *request, void *data) +{ + int i = 0; + int len; + char tmp[32]; + (void) data; + + mk_http_status(request, 200); + mk_http_header(request, "X-Monkey", 8, "OK", 2); + + for (i = 0; i < 1000; i++) { + len = snprintf(tmp, sizeof(tmp) -1, "test-chunk %6i\n ", i); + mk_http_send(request, tmp, len, NULL); + } + mk_http_done(request); +} + +void cb_test_big_chunk(mk_request_t *request, void *data) +{ + size_t chunk_size = 1024000000; + char *chunk; + (void) data; + + mk_http_status(request, 200); + mk_http_header(request, "X-Monkey", 8, "OK", 2); + + chunk = calloc(1, chunk_size); + mk_http_send(request, chunk, chunk_size, NULL); + free(chunk); + mk_http_done(request); +} + + +static void signal_handler(int signal) +{ + write(STDERR_FILENO, "[engine] caught signal\n", 23); + + switch (signal) { + case SIGTERM: + case SIGINT: + mk_stop(ctx); + mk_destroy(ctx); + _exit(EXIT_SUCCESS); + default: + break; + } +} + +static void signal_init() +{ + signal(SIGINT, &signal_handler); + signal(SIGTERM, &signal_handler); +} + +static void cb_queue_message(mk_mq_t *queue, void *data, size_t size, void *ctx) +{ + size_t i; + char *buf; + (void) ctx; + (void) queue; + + printf("=== cb queue message === \n"); + printf(" => %lu bytes\n", size); + printf(" => "); + + buf = data; + for (i = 0; i < size; i++) { + printf("%c", buf[i]); + } + printf("\n\n"); +} + + +HFND_FUZZING_ENTRY_FUNCTION(int argc, const char *const *argv) +{ + int i = 0; + int len; + int vid; + int qid; + char msg[800000]; + + signal_init(); + + ctx = mk_create(); + if (!ctx) { + return -1; + } + + /* Create a message queue and a callback for each message */ + qid = mk_mq_create(ctx, "/data", cb_queue_message, NULL); + + mk_config_set(ctx, + "Listen", API_PORT, + NULL); + + vid = mk_vhost_create(ctx, NULL); + mk_vhost_set(ctx, vid, + "Name", "monotop", + NULL); + mk_vhost_handler(ctx, vid, "/test_chunks", cb_test_chunks, NULL); + mk_vhost_handler(ctx, vid, "/test_big_chunk", cb_test_big_chunk, NULL); + mk_vhost_handler(ctx, vid, "/", cb_main, NULL); + + mk_info("Service: http://%s:%s/test_chunks", API_ADDR, API_PORT); + mk_start(ctx); + + for (i = 0; i < 5; i++) { + len = snprintf(msg, sizeof(msg) - 1, "[...] message ID: %i\n", i); + mk_mq_send(ctx, qid, &msg, len); + } + + sleep(3600); + + mk_stop(ctx); + mk_destroy(ctx); + + return 0; +} diff --git a/lib/monkey/mk_server/mk_http.c b/lib/monkey/mk_server/mk_http.c index ae063830c64..85855b8750e 100644 --- a/lib/monkey/mk_server/mk_http.c +++ b/lib/monkey/mk_server/mk_http.c @@ -83,6 +83,8 @@ void mk_http_request_init(struct mk_http_session *session, request->real_path.data = NULL; request->handler_data = NULL; + request->in_file.fd = -1; + /* Response Headers */ mk_header_response_reset(&request->headers); @@ -715,7 +717,6 @@ int mk_http_init(struct mk_http_session *cs, struct mk_http_request *sr, sr->method != MK_METHOD_PUT)) { sr->_content_length.data = NULL; sr->_content_length.len = 0; - //return mk_http_error(MK_CLIENT_BAD_REQUEST, cs, sr, server); } ret_file = mk_file_get_info(sr->real_path.data, &sr->file_info, MK_FILE_READ); @@ -734,6 +735,7 @@ int mk_http_init(struct mk_http_session *cs, struct mk_http_request *sr, handlers = &sr->host_conf->handlers; mk_list_foreach(head, handlers) { h_handler = mk_list_entry(head, struct mk_vhost_handler, _head); + if (regexec(h_handler->match, sr->uri_processed.data, 0, NULL, 0) != 0) { continue; @@ -1379,10 +1381,6 @@ void mk_http_session_remove(struct mk_http_session *cs, mk_list_del(&cs->request_list); cs->_sched_init = MK_FALSE; - - /* Remove any pending thread context */ - struct mk_sched_worker *sched = mk_sched_get_thread_conf(); - mk_sched_threads_destroy_all(sched); } /* FIXME: nobody is using this */ @@ -1608,15 +1606,15 @@ int mk_http_sched_done(struct mk_sched_conn *conn, struct mk_server *server) { (void) worker; - struct mk_http_session *cs; + struct mk_http_session *session; struct mk_http_request *sr; - cs = mk_http_session_get(conn); - sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head); - - mk_plugin_stage_run_40(cs, sr, server); + session = mk_http_session_get(conn); + sr = mk_list_entry_first(&session->request_list, + struct mk_http_request, _head); + mk_plugin_stage_run_40(session, sr, server); - return mk_http_request_end(cs, server); + return mk_http_request_end(session, server); } struct mk_sched_handler mk_http_handler = { diff --git a/lib/monkey/mk_server/mk_http_parser.c b/lib/monkey/mk_server/mk_http_parser.c index a98c76ce76e..372381dc1e4 100644 --- a/lib/monkey/mk_server/mk_http_parser.c +++ b/lib/monkey/mk_server/mk_http_parser.c @@ -193,10 +193,8 @@ static inline int header_lookup(struct mk_http_parser *p, char *buffer) struct row_entry *h; len = (p->header_sep - p->header_key); - - for (i = p->header_min; i <= p->header_max; i++) { + for (i = p->header_min; i <= p->header_max && i >= 0; i++) { h = &mk_headers_table[i]; - /* Check string length first */ if (h->len != len) { continue; @@ -381,7 +379,6 @@ int mk_http_parser(struct mk_http_request *req, struct mk_http_parser *p, int len; /* lazy test - printf("p->i=%i buf_len=%i\n", p->i, buf_len); diff --git a/lib/monkey/mk_server/mk_lib.c b/lib/monkey/mk_server/mk_lib.c index f085d355dd1..7e843423281 100644 --- a/lib/monkey/mk_server/mk_lib.c +++ b/lib/monkey/mk_server/mk_lib.c @@ -700,7 +700,6 @@ int mk_http_done(mk_request_t *req) if (req->session->close_now == MK_TRUE) { mk_lib_yield(req); - mk_http_session_remove(req->session, req->session->server); } return 0; diff --git a/lib/monkey/mk_server/mk_scheduler.c b/lib/monkey/mk_server/mk_scheduler.c index eb798886f5f..525de279820 100644 --- a/lib/monkey/mk_server/mk_scheduler.c +++ b/lib/monkey/mk_server/mk_scheduler.c @@ -564,6 +564,7 @@ int mk_sched_drop_connection(struct mk_sched_conn *conn, struct mk_sched_worker *sched, struct mk_server *server) { + mk_sched_threads_destroy_all(sched); return mk_sched_remove_client(conn, sched, server); } @@ -605,13 +606,10 @@ static int sched_thread_cleanup(struct mk_sched_worker *sched, struct mk_list *tmp; struct mk_list *head; struct mk_http_thread *mth; + (void) sched; mk_list_foreach_safe(head, tmp, list) { mth = mk_list_entry(head, struct mk_http_thread, _head); - if (mth->close == MK_TRUE) { - mk_sched_drop_connection(mth->session->conn, sched, - mth->session->server); - } mk_http_thread_destroy(mth); c++; }