diff --git a/fuzzing/EpollHelloWorld.cpp b/fuzzing/EpollHelloWorld.cpp index fbe833a..0d0623d 100644 --- a/fuzzing/EpollHelloWorld.cpp +++ b/fuzzing/EpollHelloWorld.cpp @@ -65,7 +65,7 @@ void test() { client = us_socket_context_connect(0, client_context, "hostname", 5000, "localhost", 0, 0); us_socket_context_on_connect_error(0, client_context, [](struct us_socket_t *s, int code) { - client = nullptr; + client = nullptr; return s; }); diff --git a/fuzzing/Makefile b/fuzzing/Makefile index 38bd155..3e32d1d 100644 --- a/fuzzing/Makefile +++ b/fuzzing/Makefile @@ -29,12 +29,6 @@ oss-fuzz: $(CXX) $(CXXFLAGS) -DUWS_WITH_PROXY -std=c++17 -O3 Http.cpp -o $(OUT)/HttpWithProxy $(LIB_FUZZING_ENGINE) $(CXX) $(CXXFLAGS) -Izlib -std=c++17 -O3 PerMessageDeflate.cpp -o $(OUT)/PerMessageDeflate $(LIB_FUZZING_ENGINE) zlib/libz.a $(CXX) $(CXXFLAGS) -std=c++17 -O3 TopicTree.cpp -o $(OUT)/TopicTree $(LIB_FUZZING_ENGINE) -# "Integration tests" - $(CC) $(CFLAGS) -DLIBUS_NO_SSL -c -O3 uSocketsMock.c - $(CXX) $(CXXFLAGS) -Izlib -std=c++17 -O3 -DLIBUS_NO_SSL -I../src -I../uSockets/src MockedHelloWorld.cpp uSocketsMock.o zlib/libz.a -o $(OUT)/MockedHelloWorld $(LIB_FUZZING_ENGINE) - $(CXX) $(CXXFLAGS) -Izlib -std=c++17 -O3 -DLIBUS_NO_SSL -I../src -I../uSockets/src MockedEchoServer.cpp uSocketsMock.o zlib/libz.a -o $(OUT)/MockedEchoServer $(LIB_FUZZING_ENGINE) - $(CXX) $(CXXFLAGS) -Izlib -std=c++17 -O3 -DLIBUS_NO_SSL -I../src -I../uSockets/src MockedBroadcastingEchoServer.cpp uSocketsMock.o zlib/libz.a -o $(OUT)/MockedBroadcastingEchoServer $(LIB_FUZZING_ENGINE) - $(CXX) $(CXXFLAGS) -Izlib -std=c++17 -O3 -DLIBUS_NO_SSL -I../src -I../uSockets/src MockedEmptyHandlersServer.cpp uSocketsMock.o zlib/libz.a -o $(OUT)/MockedEmptyHandlersServer $(LIB_FUZZING_ENGINE) broken: # Too small tests, failing coverage test diff --git a/fuzzing/MockedBroadcastingEchoServer.cpp b/fuzzing/MockedBroadcastingEchoServer.cpp deleted file mode 100644 index 11c3620..0000000 --- a/fuzzing/MockedBroadcastingEchoServer.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#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::DEDICATED_COMPRESSOR_8KB, - /* We want this to be low so that we can hit it, yet bigger than 256 */ - .maxPayloadLength = 300, - .idleTimeout = 10, - /* Handlers */ - .open = [](auto *ws) { - /* Subscribe to anything */ - ws->subscribe(/*req->getHeader(*/"topic"/*)*/); - }, - .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) { - if (message.length() && message[0] == 'C') { - ws->close(); - } else if (message.length() && message[0] == 'E') { - ws->end(1006); - } else { - /* Publish to topic sent by message */ - ws->publish(message, message, opCode, true); - - if (message.length() && message[0] == 'U') { - ws->unsubscribe(message); - } - } - }, - .drain = [](auto *ws) { - /* Check getBufferedAmount here */ - }, - .ping = [](auto *ws) { - - }, - .pong = [](auto *ws) { - - }, - .close = [](auto *ws, int code, std::string_view message) { - /* Not necessary but we'll call it for coverage */ - ws->unsubscribeAll(); - } - }).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/MockedEchoServer.cpp b/fuzzing/MockedEchoServer.cpp deleted file mode 100644 index 3d2bfff..0000000 --- a/fuzzing/MockedEchoServer.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "App.h" - -#include "helpers.h" - -#include - -/* 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); - -us_listen_socket_t *listenSocket; - -/* ws->getUserData returns one of these */ -struct PerSocketData { - int nothing; - std::shared_ptr valid; -}; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - - /* First byte determines what compressor to use */ - if (size < 1) { - return 0; - } - - uWS::CompressOptions compressors[] = { - uWS::DISABLED, - uWS::SHARED_COMPRESSOR, - uWS::DEDICATED_COMPRESSOR_3KB, - uWS::DEDICATED_COMPRESSOR_4KB, - uWS::DEDICATED_COMPRESSOR_8KB, - uWS::DEDICATED_COMPRESSOR_16KB, - uWS::DEDICATED_COMPRESSOR_32KB, - uWS::DEDICATED_COMPRESSOR_64KB, - uWS::DEDICATED_COMPRESSOR_128KB, - uWS::DEDICATED_COMPRESSOR_256KB - }; - - uWS::CompressOptions compressor = compressors[data[0] % 10]; - data++; - size--; - - /* Very simple WebSocket echo server */ - auto app = uWS::TemplatedApp(uWS::App().ws("/*", { - /* Settings */ - .compression = compressor, - /* We want this to be low so that we can hit it, yet bigger than 256 */ - .maxPayloadLength = 300, - .idleTimeout = 10, - /* Handlers */ - .open = [](auto *ws) { - - PerSocketData *psd = (PerSocketData *) ws->getUserData(); - psd->valid.reset(new bool{true}); - - //if (req->getHeader("close_me").length()) { - // ws->close(); - //} else if (req->getHeader("end_me").length()) { - // ws->end(1006); - //} - }, - .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) { - if (message.length() > 300) { - /* Inform the sanitizer of the fault */ - fprintf(stderr, "Too long message passed\n"); - free((void *) -1); - } - - if (message.length() && message[0] == 'C') { - ws->close(); - } else if (message.length() && message[0] == 'E') { - ws->end(1006); - } else { - ws->send(message, opCode, true); - } - }, - .drain = [](auto *ws) { - /* Check getBufferedAmount here */ - }, - .ping = [](auto *ws) { - /* Here we test send and end while uncorked, by having them send from deferred */ - PerSocketData *psd = (PerSocketData *) ws->getUserData(); - - uWS::Loop::get()->defer([ws, valid = psd->valid]() { - if (valid.get()) { - /* We haven't been closed */ - ws->send("Hello!", uWS::TEXT, false); - ws->end(1000); - } - }); - }, - .pong = [](auto *ws) { - - }, - .close = [](auto *ws, int code, std::string_view message) { - - } - }).listen(9001, [](us_listen_socket_t *listenSocket) { - ::listenSocket = listenSocket; - })).run(); - - us_loop_read_mocked_data((struct us_loop *) uWS::Loop::get(), (char *) makePadded(data, size), size); - - us_listen_socket_close(0, listenSocket); - uWS::Loop::get()->free(); - - return 0; -} diff --git a/fuzzing/MockedEmptyHandlersServer.cpp b/fuzzing/MockedEmptyHandlersServer.cpp deleted file mode 100644 index 1526fe9..0000000 --- a/fuzzing/MockedEmptyHandlersServer.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#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) { - - app = new uWS::App(); - - struct PerSocketData { - int nothing; - }; - - app->ws("/*", { - /* Having no handlers here should not crash */ - }).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/MockedHelloWorld.cpp b/fuzzing/MockedHelloWorld.cpp deleted file mode 100644 index ecfc651..0000000 --- a/fuzzing/MockedHelloWorld.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#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) { - - app = new uWS::TemplatedApp(uWS::App().get("/*", [](auto *res, auto *req) { - if (req->getHeader("write").length()) { - res->writeStatus("200 OK")->writeHeader("write", "true")->write("Hello"); - res->write(" world!"); - res->end(); - } else if (req->getQuery().length()) { - res->close(); - } else { - res->end("Hello world!"); - } - }).post("/*", [](auto *res, auto *req) { - res->onAborted([]() { - /* We might as well use this opportunity to stress the loop a bit */ - uWS::Loop::get()->defer([]() { - - }); - }); - res->onData([res](std::string_view chunk, bool isEnd) { - if (isEnd) { - res->cork([res, chunk]() { - res->write("something ahead"); - res->end(chunk); - }); - } - }); - }).any("/:candy/*", [](auto *res, auto *req) { - if (req->getParameter(0).length() == 0) { - free((void *) -1); - } - /* Some invalid queries */ - req->getParameter(30000); - req->getParameter(-34234); - req->getHeader("yhello"); - req->getQuery(); - - /*req->onAborted([]() { - - });*/ - - /* As of now, this will be called immediately, but changes could make it properly deferred */ - uWS::Loop::get()->defer([res]() { - res->end("Deferred answer here"); - }); - }).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 deleted file mode 100644 index a35f9ba..0000000 --- a/fuzzing/uSocketsMock.c +++ /dev/null @@ -1,314 +0,0 @@ -/* uSockets is entierly opaque so we can use the real header straight up */ -#include "../uSockets/src/libusockets.h" - -#include -#include -#include -#include - -struct us_loop_t { - - /* We only support one listen socket */ - alignas(16) struct us_listen_socket_t *listen_socket; - - /* The list of closed sockets */ - struct us_socket_t *close_list; - - /* Post and pre callbacks */ - void (*pre_cb)(struct us_loop_t *loop); - void (*post_cb)(struct us_loop_t *loop); - - void (*wakeup_cb)(struct us_loop_t *loop); -}; - -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) { - 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; - - loop->pre_cb = pre_cb; - loop->post_cb = post_cb; - loop->wakeup_cb = wakeup_cb; - - return loop; -} - -void us_wakeup_loop(struct us_loop_t *loop) { - /* We do this immediately as of now, could be delayed to next iteration */ - loop->wakeup_cb(loop); -} - -void us_loop_free(struct us_loop_t *loop) { - free(loop); -} - -void *us_loop_ext(struct us_loop_t *loop) { - return loop + 1; -} - -void us_loop_run(struct us_loop_t *loop) { - -} - -struct us_socket_context_t { - 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, int code, void *reason); - struct us_socket_t *(*on_data)(struct us_socket_t *s, char *data, int length); - struct us_socket_t *(*on_writable)(struct us_socket_t *s); - struct us_socket_t *(*on_timeout)(struct us_socket_t *s); - struct us_socket_t *(*on_end)(struct us_socket_t *s); -}; - -struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t *loop, int ext_size, struct us_socket_context_options_t options) { - struct us_socket_context_t *socket_context = (struct us_socket_context_t *) malloc(sizeof(struct us_socket_context_t) + ext_size); - - 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); -} - -void us_socket_context_on_open(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_open)(struct us_socket_t *s, int is_client, char *ip, int ip_length)) { - context->on_open = on_open; -} - -void us_socket_context_on_close(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_close)(struct us_socket_t *s, int code, void *reason)) { - context->on_close = on_close; -} - -void us_socket_context_on_data(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_data)(struct us_socket_t *s, char *data, int length)) { - context->on_data = on_data; -} - -void us_socket_context_on_writable(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_writable)(struct us_socket_t *s)) { - context->on_writable = on_writable; -} - -void us_socket_context_on_timeout(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_timeout)(struct us_socket_t *s)) { - context->on_timeout = on_timeout; -} - -void us_socket_context_on_end(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_end)(struct us_socket_t *s)) { - context->on_end = on_end; -} - -void *us_socket_context_ext(int ssl, struct us_socket_context_t *context) { - return context + 1; -} - -struct us_listen_socket_t { - int socket_ext_size; - struct us_socket_context_t *context; -}; - -struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size) { - struct us_listen_socket_t *listen_socket = (struct us_listen_socket_t *) malloc(sizeof(struct us_listen_socket_t)); - - listen_socket->socket_ext_size = socket_ext_size; - listen_socket->context = context; - - context->loop->listen_socket = listen_socket; - - return listen_socket; -} - -void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) { - free(ls); -} - -struct us_socket_t { - alignas(16) struct us_socket_context_t *context; - - int closed; - int shutdown; - int wants_writable; - - //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, const char *interface, int options, int socket_ext_size) { - //printf("us_socket_context_connect\n"); - - return 0; -} - -struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *context) { - return context->loop; -} - -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) { - struct us_socket_t *new_s = (struct us_socket_t *) realloc(s, sizeof(struct us_socket_t) + ext_size); - new_s->context = 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) { - /* 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); - - return child_context; -} - -int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more) { - - if (!length) { - return 0; - } - - /* Last byte determines if we send everything or not, to stress the buffering mechanism */ - if (data[length - 1] % 2 == 0) { - /* Send only half, but first set our outgoing flag */ - s->wants_writable = 1; - return length / 2; - } - - /* Send everything */ - return length; -} - -void us_socket_timeout(int ssl, struct us_socket_t *s, unsigned int seconds) { - -} - -void *us_socket_ext(int ssl, struct us_socket_t *s) { - return s + 1; -} - -struct us_socket_context_t *us_socket_context(int ssl, struct us_socket_t *s) { - return s->context; -} - -void us_socket_flush(int ssl, struct us_socket_t *s) { - -} - -void us_socket_shutdown_read(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 s->shutdown; -} - -int us_socket_is_closed(int ssl, struct us_socket_t *s) { - return s->closed; -} - -struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason) { - - if (!us_socket_is_closed(0, s)) { - /* Emit close event */ - s = s->context->on_close(s, code, reason); - } - - /* We are now closed */ - s->closed = 1; - - /* Add us to the close list */ - - return s; -} - -void us_socket_remote_address(int ssl, struct us_socket_t *s, char *buf, int *length) { - printf("us_socket_remote_address\n"); -} - -/* 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) { - - /* 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; - s->wants_writable = 0; - - /* Emit open event */ - loop->pre_cb(loop); - s = s->context->on_open(s, 0, 0, 0); - loop->post_cb(loop); - - if (!us_socket_is_closed(0, s) && !us_socket_is_shut_down(0, s)) { - - /* Trigger writable event if we want it */ - if (s->wants_writable) { - s->wants_writable = 0; - loop->pre_cb(loop); - s = s->context->on_writable(s); - loop->post_cb(loop); - /* Check if we closed inside of writable */ - if (us_socket_is_closed(0, s) || us_socket_is_shut_down(0, s)) { - goto done; - } - } - - /* Loop over the data, emitting it in chunks of 0-255 bytes */ - for (int i = 0; i < size; ) { - unsigned char chunkLength = data[i++]; - if (i + chunkLength > size) { - chunkLength = size - i; - } - - /* Copy the data chunk to a properly padded buffer */ - static char *paddedBuffer; - if (!paddedBuffer) { - paddedBuffer = (char *) malloc(128 + 255 + 128); - memset(paddedBuffer, 0, 128 + 255 + 128); - } - memcpy(paddedBuffer + 128, data + i, chunkLength); - - /* Emit a bunch of data events here */ - loop->pre_cb(loop); - s = s->context->on_data(s, paddedBuffer + 128, chunkLength); - loop->post_cb(loop); - if (us_socket_is_closed(0, s) || us_socket_is_shut_down(0, s)) { - break; - } - - /* Also trigger it here */ - if (s->wants_writable) { - s->wants_writable = 0; - loop->pre_cb(loop); - s = s->context->on_writable(s); - loop->post_cb(loop); - /* Check if we closed inside of writable */ - if (us_socket_is_closed(0, s) || us_socket_is_shut_down(0, s)) { - goto done; - } - } - - i += chunkLength; - } - } - -done: - if (!us_socket_is_closed(0, s)) { - /* Emit close event */ - loop->pre_cb(loop); - s = s->context->on_close(s, 0, NULL); - loop->post_cb(loop); - } - - /* Free the socket */ - free(s); -}