From: Timo Sirainen Date: Mon, 23 Mar 2020 16:29:16 +0000 (+0200) Subject: lib-test: Add fuzzing framework X-Git-Tag: 2.3.14.rc1~181 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=48114f39d81a690e3f18e69a3a658fc75d5f3b88;p=thirdparty%2Fdovecot%2Fcore.git lib-test: Add fuzzing framework --- diff --git a/src/lib-test/Makefile.am b/src/lib-test/Makefile.am index 6c472fcbf1..ce7417d642 100644 --- a/src/lib-test/Makefile.am +++ b/src/lib-test/Makefile.am @@ -5,12 +5,14 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib-charset libtest_la_SOURCES = \ + fuzzer.c \ test-common.c \ test-istream.c \ test-ostream.c \ test-subprocess.c headers = \ + fuzzer.h \ test-common.h \ test-subprocess.h diff --git a/src/lib-test/fuzzer.c b/src/lib-test/fuzzer.c new file mode 100644 index 0000000000..52790177cf --- /dev/null +++ b/src/lib-test/fuzzer.c @@ -0,0 +1,79 @@ +/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "lib-signals.h" +#include "net.h" +#include "istream.h" +#include "ostream.h" +#include "iostream-pump.h" +#include "fuzzer.h" + +#include +#include + +void fuzzer_init(struct fuzzer_context *fuzz_ctx) +{ + i_zero(fuzz_ctx); + if (!lib_is_initialized()) { + lib_init(); + lib_signals_init(); + lib_signals_ignore(SIGPIPE, TRUE); + } + fuzz_ctx->fd = -1; +} + +void fuzzer_deinit(struct fuzzer_context *fuzz_ctx) +{ + iostream_pump_destroy(&fuzz_ctx->pump); + /* ensure fd gets closed, we don't care + if this fails. */ + if (fuzz_ctx->fd > -1) + (void)close(fuzz_ctx->fd); + io_loop_destroy(&fuzz_ctx->ioloop); +} + +static void pump_finished(enum iostream_pump_status status ATTR_UNUSED, + struct fuzzer_context *fuzz_ctx) +{ + struct istream *input = iostream_pump_get_input(fuzz_ctx->pump); + struct ostream *output = iostream_pump_get_output(fuzz_ctx->pump); + + switch (status) { + case IOSTREAM_PUMP_STATUS_INPUT_EOF: + break; + case IOSTREAM_PUMP_STATUS_INPUT_ERROR: + i_error("read(%s) failed: %s", i_stream_get_name(input), + i_stream_get_error(input)); + break; + case IOSTREAM_PUMP_STATUS_OUTPUT_ERROR: + i_error("write(%s) failed: %s", o_stream_get_name(output), + o_stream_get_error(output)); + break; + }; + + if (shutdown(o_stream_get_fd(output), SHUT_RDWR) < 0) + i_fatal("shutdown() failed: %m"); + iostream_pump_destroy(&fuzz_ctx->pump); +} + +int fuzzer_io_as_fd(struct fuzzer_context *fuzz_ctx, + const uint8_t *data, size_t size) +{ + int sfd[2]; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) < 0) + i_fatal("socketpair() failed: %m"); + net_set_nonblock(sfd[0], TRUE); + net_set_nonblock(sfd[1], TRUE); + + struct istream *input = i_stream_create_from_data(data, size); + struct ostream *output = o_stream_create_fd_autoclose(&sfd[0], IO_BLOCK_SIZE); + fuzz_ctx->pump = iostream_pump_create(input, output); + fuzz_ctx->fd = sfd[1]; + iostream_pump_set_completion_callback(fuzz_ctx->pump, pump_finished, + fuzz_ctx); + i_stream_unref(&input); + o_stream_unref(&output); + iostream_pump_start(fuzz_ctx->pump); + return sfd[1]; +} diff --git a/src/lib-test/fuzzer.h b/src/lib-test/fuzzer.h new file mode 100644 index 0000000000..85d83c4d5e --- /dev/null +++ b/src/lib-test/fuzzer.h @@ -0,0 +1,37 @@ +#ifndef FUZZER_H +#define FUZZER_H + +struct iostream_pump; +struct ioloop; + +struct fuzzer_context { + int fd; + struct iostream_pump *pump; + struct ioloop *ioloop; +}; + +#define FUZZ_BEGIN_DATA(data_arg, size_arg) \ + int LLVMFuzzerTestOneInput(data_arg, size_arg); \ + int LLVMFuzzerTestOneInput(data_arg, size_arg) { \ + struct fuzzer_context fuzz_ctx; \ + fuzzer_init(&fuzz_ctx); T_BEGIN { + +#define FUZZ_BEGIN_STR(str_arg) \ + FUZZ_BEGIN_DATA(const uint8_t *_param_data, size_t _param_size) \ + str_arg = t_strndup(_param_data, _param_size); + +#define FUZZ_BEGIN_FD \ + FUZZ_BEGIN_DATA(const uint8_t *_param_data, size_t _param_size) \ + fuzz_ctx.ioloop = io_loop_create(); \ + (void)fuzzer_io_as_fd(&fuzz_ctx, _param_data, _param_size); + +#define FUZZ_END \ + } T_END; fuzzer_deinit(&fuzz_ctx); return 0; } + +void fuzzer_init(struct fuzzer_context *fuzz_ctx); +void fuzzer_deinit(struct fuzzer_context *fuzz_ctx); + +int fuzzer_io_as_fd(struct fuzzer_context *fuzz_ctx, + const uint8_t *data, size_t size); + +#endif