From c102034870df7a8d5f6fe2379b52b53cc3c3a043 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Sun, 16 Jun 2019 12:53:19 +0200 Subject: [PATCH] Add MockedEchoServer fuzz target, fix App capture of moving this --- fuzzing/Makefile | 5 +- fuzzing/MockedEchoServer.cpp | 58 +++++++++++++++++++++++ fuzzing/uSocketsMock.c | 89 +++++++++++++++++++++++++++--------- src/App.h | 3 +- 4 files changed, 131 insertions(+), 24 deletions(-) create mode 100644 fuzzing/MockedEchoServer.cpp diff --git a/fuzzing/Makefile b/fuzzing/Makefile index 37f7620..1b963a4 100644 --- a/fuzzing/Makefile +++ b/fuzzing/Makefile @@ -1,10 +1,11 @@ default: # Fuzzing is only available with clang++ clang -DLIBUS_NO_SSL -c -O3 uSocketsMock.c - clang++ -DUWS_NO_ZLIB -DLIBUS_NO_SSL -std=c++17 -fsanitize=undefined,fuzzer -O3 -I../src -I../uSockets/src uSocketsMock.o MockedHelloWorld.cpp -o MockedHelloWorld + clang++ -DUWS_NO_ZLIB -DLIBUS_NO_SSL -std=c++17 -fsanitize=address,fuzzer -O3 -I../src -I../uSockets/src uSocketsMock.o MockedHelloWorld.cpp -o MockedHelloWorld + clang++ -DUWS_NO_ZLIB -DLIBUS_NO_SSL -std=c++17 -fsanitize=address,fuzzer -O3 -I../src -I../uSockets/src uSocketsMock.o MockedEchoServer.cpp -o MockedEchoServer # Purely "unit tests" clang++ -std=c++17 -fsanitize=address,fuzzer -O3 WebSocket.cpp -o WebSocket clang++ -std=c++17 -fsanitize=address,fuzzer -O3 Http.cpp -o Http clang++ -std=c++17 -fsanitize=address,fuzzer -O3 Extensions.cpp -o Extensions clang++ -std=c++17 -fsanitize=address,fuzzer -O3 Handshake.cpp -o Handshake - clang++ -std=c++17 -fsanitize=address,fuzzer -O3 PerMessageDeflate.cpp -o PerMessageDeflate -lz \ No newline at end of file + clang++ -std=c++17 -fsanitize=address,fuzzer -O3 PerMessageDeflate.cpp -o PerMessageDeflate -lz diff --git a/fuzzing/MockedEchoServer.cpp b/fuzzing/MockedEchoServer.cpp new file mode 100644 index 0000000..c7cd5d7 --- /dev/null +++ b/fuzzing/MockedEchoServer.cpp @@ -0,0 +1,58 @@ +#include "App.h" + +#include "helpers.h" + +/* This function pushes data to the uSockets mock */ +extern "C" void us_loop_read_mocked_data(struct us_loop *loop, char *data, unsigned int size); + +uWS::TemplatedApp *app; +us_listen_socket_t *listenSocket; + +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { + + /* ws->getUserData returns one of these */ + struct PerSocketData { + int nothing; + }; + + /* Very simple WebSocket echo server */ + app = new uWS::TemplatedApp(uWS::App().ws("/*", { + /* Settings */ + .compression = uWS::SHARED_COMPRESSOR, + .maxPayloadLength = 16 * 1024, + .idleTimeout = 10, + /* Handlers */ + .open = [](auto *ws, auto *req) { + + }, + .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) { + ws->send(message, opCode); + }, + .drain = [](auto *ws) { + /* Check getBufferedAmount here */ + }, + .ping = [](auto *ws) { + + }, + .pong = [](auto *ws) { + + }, + .close = [](auto *ws, int code, std::string_view message) { + + } + }).listen(9001, [](us_listen_socket_t *listenSocket) { + if (listenSocket) { + std::cout << "Listening on port " << 9001 << std::endl; + ::listenSocket = listenSocket; + } + })); + + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + + us_loop_read_mocked_data((struct us_loop *) uWS::Loop::get(), (char *) makePadded(data, size), size); + + return 0; +} diff --git a/fuzzing/uSocketsMock.c b/fuzzing/uSocketsMock.c index dc15c73..c06510e 100644 --- a/fuzzing/uSocketsMock.c +++ b/fuzzing/uSocketsMock.c @@ -3,15 +3,24 @@ #include #include +#include struct us_loop_t { /* We only support one listen socket */ - struct us_listen_socket_t *listen_socket; + alignas(16) struct us_listen_socket_t *listen_socket; + + /* The list of closed sockets */ + struct us_socket_t *close_list; }; struct us_loop_t *us_create_loop(void *hint, void (*wakeup_cb)(struct us_loop_t *loop), void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop), unsigned int ext_size) { - return (struct us_loop_t *) malloc(sizeof(struct us_loop_t) + ext_size); + struct us_loop_t *loop = (struct us_loop_t *) malloc(sizeof(struct us_loop_t) + ext_size); + + loop->listen_socket = 0; + loop->close_list = 0; + + return loop; } void us_loop_free(struct us_loop_t *loop) { @@ -27,7 +36,7 @@ void us_loop_run(struct us_loop_t *loop) { } struct us_socket_context_t { - struct us_loop_t *loop; + alignas(16) struct us_loop_t *loop; struct us_socket_t *(*on_open)(struct us_socket_t *s, int is_client, char *ip, int ip_length); struct us_socket_t *(*on_close)(struct us_socket_t *s); @@ -42,10 +51,13 @@ struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t * socket_context->loop = loop; + //printf("us_create_socket_context: %p\n", socket_context); + return socket_context; } void us_socket_context_free(int ssl, struct us_socket_context_t *context) { + //printf("us_socket_context_free: %p\n", context); free(context); } @@ -98,16 +110,18 @@ void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) { } struct us_socket_t { - struct us_socket_context_t *context; -}; + alignas(16) struct us_socket_context_t *context; -/* For ubsan? */ -struct us_new_socket_t { - struct us_socket_context_t *context; + int closed; + int shutdown; + + //struct us_socket_t *next; }; struct us_socket_t *us_socket_context_connect(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size) { - printf("us_socket_context_connect\n"); + //printf("us_socket_context_connect\n"); + + return 0; } struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *context) { @@ -115,11 +129,23 @@ struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *co } struct us_socket_t *us_socket_context_adopt_socket(int ssl, struct us_socket_context_t *context, struct us_socket_t *s, int ext_size) { - printf("us_socket_context_adopt_socket\n"); + struct us_socket_t *new_s = (struct us_socket_t *) realloc(s, sizeof(struct us_socket_t) + ext_size); + new_s->context = context; + + //printf("us_socket_context_adopt_socket: %p till %p\n", s, new_s); + //printf("new context is: %p\n", new_s->context); + + return new_s; } struct us_socket_context_t *us_create_child_socket_context(int ssl, struct us_socket_context_t *context, int context_ext_size) { - printf("us_create_child_socket_context\n"); + /* We simply create a new context in this mock */ + struct us_socket_context_options_t options = {}; + struct us_socket_context_t *child_context = us_create_socket_context(ssl, context->loop, context_ext_size, options); + + //printf("us_create_child_socket_context: %p\n", child_context); + + return child_context; } int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more) { @@ -143,18 +169,30 @@ void us_socket_flush(int ssl, struct us_socket_t *s) { } void us_socket_shutdown(int ssl, struct us_socket_t *s) { - + s->shutdown = 1; } int us_socket_is_shut_down(int ssl, struct us_socket_t *s) { - return 0; + + //printf("us_socket_is_shut_down: %d\n", s->shutdown); + + return s->shutdown; } int us_socket_is_closed(int ssl, struct us_socket_t *s) { - return 0; + + //printf("us_socket_is_closed: %d\n", s->closed); + + return s->closed; } struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s) { + s->closed = 1; + + //printf("us_socket_close\n"); + + /* Add us to the close list */ + return s; } @@ -165,21 +203,30 @@ void us_socket_remote_address(int ssl, struct us_socket_t *s, char *buf, int *le /* We expose this function to let fuzz targets push data to uSockets */ void us_loop_read_mocked_data(struct us_loop_t *loop, char *data, unsigned int size) { + //printf("us_loop_read_mocked_data\n"); + + /* We are unwound so let's free all closed polls here */ + + /* We have one listen socket */ int socket_ext_size = loop->listen_socket->socket_ext_size; /* Create a socket with information from the listen socket */ struct us_socket_t *s = (struct us_socket_t *) malloc(sizeof(struct us_socket_t) + socket_ext_size); s->context = loop->listen_socket->context; + s->closed = 0; + s->shutdown = 0; /* Emit open event */ - s->context->on_open(s, 0, 0, 0); - - /* Emit a bunch of data events here */ - s->context->on_data(s, data, size); - - /* Emit close event */ - s->context->on_close(s); + s = s->context->on_open(s, 0, 0, 0); + if (!us_socket_is_closed(0, s)) { + /* Emit a bunch of data events here */ + s = s->context->on_data(s, data, size); + if (!us_socket_is_closed(0, s)) { + /* Emit close event */ + s = s->context->on_close(s); + } + } /* Free the socket */ free(s); diff --git a/src/App.h b/src/App.h index e8fa4df..e1399a3 100644 --- a/src/App.h +++ b/src/App.h @@ -135,7 +135,8 @@ public: webSocketContext->getExt()->maxPayloadLength = behavior.maxPayloadLength; webSocketContext->getExt()->idleTimeout = behavior.idleTimeout; - return std::move(get(pattern, [webSocketContext, this, behavior = std::move(behavior)](auto *res, auto *req) mutable { + return std::move(get(pattern, [webSocketContext, httpContext = this->httpContext, behavior = std::move(behavior)](auto *res, auto *req) mutable { + /* If we have this header set, it's a websocket */ std::string_view secWebSocketKey = req->getHeader("sec-websocket-key"); if (secWebSocketKey.length() == 24) {