From 28ac9328ca8cb78f4287ae9a770be602847f0743 Mon Sep 17 00:00:00 2001 From: Sergey Bronnikov Date: Wed, 12 Jan 2022 15:06:23 +0300 Subject: [PATCH] test/fuzz: add fuzzing tests for IPROTO decoders Examples of IPROTO decoding issues: #3900, #1928, #6781. Patch adds a number of fuzzing tests that covers IPROTO decoding: - xrow_decode_auth - xrow_decode_begin - xrow_decode_call - xrow_decode_dml - xrow_decode_id - xrow_decode_raft - xrow_decode_sql - xrow_decode_watch - xrow_greeting_decode NO_DOC=testing NO_CHANGELOG=testing (cherry picked from commit 46cacf35bd6454102a6f8e3e47281f66cc3fdd8c) --- src/box/xrow.c | 6 ++-- test/fuzz/CMakeLists.txt | 40 +++++++++++++++++++++ test/fuzz/xrow_decode_auth_fuzzer.c | 45 ++++++++++++++++++++++++ test/fuzz/xrow_decode_begin_fuzzer.c | 46 +++++++++++++++++++++++++ test/fuzz/xrow_decode_call_fuzzer.c | 46 +++++++++++++++++++++++++ test/fuzz/xrow_decode_dml_fuzzer.c | 46 +++++++++++++++++++++++++ test/fuzz/xrow_decode_id_fuzzer.c | 46 +++++++++++++++++++++++++ test/fuzz/xrow_decode_raft_fuzzer.c | 46 +++++++++++++++++++++++++ test/fuzz/xrow_decode_sql_fuzzer.c | 46 +++++++++++++++++++++++++ test/fuzz/xrow_decode_watch_fuzzer.c | 45 ++++++++++++++++++++++++ test/fuzz/xrow_greeting_decode_fuzzer.c | 33 ++++++++++++++++++ 11 files changed, 443 insertions(+), 2 deletions(-) create mode 100644 test/fuzz/xrow_decode_auth_fuzzer.c create mode 100644 test/fuzz/xrow_decode_begin_fuzzer.c create mode 100644 test/fuzz/xrow_decode_call_fuzzer.c create mode 100644 test/fuzz/xrow_decode_dml_fuzzer.c create mode 100644 test/fuzz/xrow_decode_id_fuzzer.c create mode 100644 test/fuzz/xrow_decode_raft_fuzzer.c create mode 100644 test/fuzz/xrow_decode_sql_fuzzer.c create mode 100644 test/fuzz/xrow_decode_watch_fuzzer.c create mode 100644 test/fuzz/xrow_greeting_decode_fuzzer.c diff --git a/src/box/xrow.c b/src/box/xrow.c index 6e75892314fe..e8d5dd4462ae 100644 --- a/src/box/xrow.c +++ b/src/box/xrow.c @@ -1403,7 +1403,8 @@ int xrow_decode_raft(const struct xrow_header *row, struct raft_request *r, struct vclock *vclock) { - assert(row->type == IPROTO_RAFT); + if (row->type != IPROTO_RAFT) + goto bad_msgpack; if (row->bodycnt != 1 || row->group_id != GROUP_LOCAL) { diag_set(ClientError, ER_INVALID_MSGPACK, "malformed raft request"); @@ -1753,7 +1754,8 @@ xrow_decode_error(const struct xrow_header *row) int xrow_decode_begin(const struct xrow_header *row, struct begin_request *request) { - assert(row->type == IPROTO_BEGIN); + if (row->type != IPROTO_BEGIN) + goto bad_msgpack; memset(request, 0, sizeof(*request)); /** Request without extra options. */ diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt index 183b676e76ea..6ad7a203be7a 100644 --- a/test/fuzz/CMakeLists.txt +++ b/test/fuzz/CMakeLists.txt @@ -93,6 +93,46 @@ create_fuzz_test(PREFIX mp_datetime LIBRARIES core fuzzer_config ) +# Building xrow library triggers building LuaJIT that doesn't support UBSan. +# See https://github.com/tarantool/tarantool/issues/8473. +if (NOT ENABLE_UB_SANITIZER) + create_fuzz_test(PREFIX xrow_greeting_decode + SOURCES xrow_greeting_decode_fuzzer.c + LIBRARIES xrow fuzzer_config) + + create_fuzz_test(PREFIX xrow_decode_id + SOURCES xrow_decode_id_fuzzer.c + LIBRARIES xrow fuzzer_config) + + create_fuzz_test(PREFIX xrow_decode_auth + SOURCES xrow_decode_auth_fuzzer.c + LIBRARIES xrow fuzzer_config) + + create_fuzz_test(PREFIX xrow_decode_begin + SOURCES xrow_decode_begin_fuzzer.c + LIBRARIES xrow fuzzer_config) + + create_fuzz_test(PREFIX xrow_decode_call + SOURCES xrow_decode_call_fuzzer.c + LIBRARIES xrow fuzzer_config) + + create_fuzz_test(PREFIX xrow_decode_dml + SOURCES xrow_decode_dml_fuzzer.c + LIBRARIES xrow fuzzer_config) + + create_fuzz_test(PREFIX xrow_decode_raft + SOURCES xrow_decode_raft_fuzzer.c + LIBRARIES xrow fuzzer_config) + + create_fuzz_test(PREFIX xrow_decode_sql + SOURCES xrow_decode_sql_fuzzer.c + LIBRARIES xrow fuzzer_config) + + create_fuzz_test(PREFIX xrow_decode_watch + SOURCES xrow_decode_watch_fuzzer.c + LIBRARIES xrow fuzzer_config) +endif () + include(ProtobufMutator) # UndefinedBehaviorSanitizer is not supported in LuaJIT. diff --git a/test/fuzz/xrow_decode_auth_fuzzer.c b/test/fuzz/xrow_decode_auth_fuzzer.c new file mode 100644 index 000000000000..7468b3a63599 --- /dev/null +++ b/test/fuzz/xrow_decode_auth_fuzzer.c @@ -0,0 +1,45 @@ +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "fiber.h" +#include "memory.h" + +void +cord_on_yield(void) {} + +__attribute__((constructor)) +static void +setup(void) +{ + memory_init(); + fiber_init(fiber_c_invoke); +} + +__attribute__((destructor)) +static void +teardown(void) +{ + fiber_free(); + memory_free(); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + struct iovec body = {0}; + body.iov_base = (void *)data; + body.iov_len = size; + struct xrow_header row = {0}; + row.body[0] = body; + row.bodycnt = 1; + row.type = IPROTO_OK; + + struct auth_request request = {0}; + xrow_decode_auth(&row, &request); + + return 0; +} diff --git a/test/fuzz/xrow_decode_begin_fuzzer.c b/test/fuzz/xrow_decode_begin_fuzzer.c new file mode 100644 index 000000000000..cdb597cfb2d2 --- /dev/null +++ b/test/fuzz/xrow_decode_begin_fuzzer.c @@ -0,0 +1,46 @@ +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "fiber.h" +#include "memory.h" + +void +cord_on_yield(void) {} + +__attribute__((constructor)) +static void +setup(void) +{ + memory_init(); + fiber_init(fiber_c_invoke); +} + +__attribute__((destructor)) +static void +teardown(void) +{ + fiber_free(); + memory_free(); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + struct iovec body = {0}; + body.iov_base = (void *)data; + body.iov_len = size; + struct xrow_header row = {0}; + row.body[0] = body; + row.bodycnt = 1; + row.type = IPROTO_BEGIN; + + struct begin_request request = {0}; + if (xrow_decode_begin(&row, &request) == -1) + return -1; + + return 0; +} diff --git a/test/fuzz/xrow_decode_call_fuzzer.c b/test/fuzz/xrow_decode_call_fuzzer.c new file mode 100644 index 000000000000..63330b4de810 --- /dev/null +++ b/test/fuzz/xrow_decode_call_fuzzer.c @@ -0,0 +1,46 @@ +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "fiber.h" +#include "memory.h" + +void +cord_on_yield(void) {} + +__attribute__((constructor)) +static void +setup(void) +{ + memory_init(); + fiber_init(fiber_c_invoke); +} + +__attribute__((destructor)) +static void +teardown(void) +{ + fiber_free(); + memory_free(); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + struct iovec body = {0}; + body.iov_base = (void *)data; + body.iov_len = size; + + struct xrow_header row = {0}; + row.type = IPROTO_CALL; /* TODO: IPROTO_CALL_16 */ + row.body[0] = body; + row.bodycnt = 1; + + struct call_request request = {0}; + xrow_decode_call(&row, &request); + + return 0; +} diff --git a/test/fuzz/xrow_decode_dml_fuzzer.c b/test/fuzz/xrow_decode_dml_fuzzer.c new file mode 100644 index 000000000000..4486f3137024 --- /dev/null +++ b/test/fuzz/xrow_decode_dml_fuzzer.c @@ -0,0 +1,46 @@ +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "fiber.h" +#include "memory.h" + +void +cord_on_yield(void) {} + +__attribute__((constructor)) +static void +setup(void) +{ + memory_init(); + fiber_init(fiber_c_invoke); +} + +__attribute__((destructor)) +static void +teardown(void) +{ + fiber_free(); + memory_free(); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + struct iovec body = {0}; + body.iov_base = (void *)data; + body.iov_len = size; + + struct xrow_header row = {0}; + row.body[0] = body; + row.bodycnt = 1; + + struct request request = {0}; + if (xrow_decode_dml(&row, &request, 0) == -1) + return -1; + + return 0; +} diff --git a/test/fuzz/xrow_decode_id_fuzzer.c b/test/fuzz/xrow_decode_id_fuzzer.c new file mode 100644 index 000000000000..087b76d23919 --- /dev/null +++ b/test/fuzz/xrow_decode_id_fuzzer.c @@ -0,0 +1,46 @@ +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "fiber.h" +#include "memory.h" + +void +cord_on_yield(void) {} + +__attribute__((constructor)) +static void +setup(void) +{ + memory_init(); + fiber_init(fiber_c_invoke); +} + +__attribute__((destructor)) +static void +teardown(void) +{ + fiber_free(); + memory_free(); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + struct iovec body = {0}; + body.iov_base = (void *)data; + body.iov_len = size; + + struct xrow_header row = {0}; + row.body[0] = body; + row.bodycnt = 1; + + struct id_request request = {0}; + if (xrow_decode_id(&row, &request) == -1) + return -1; + + return 0; +} diff --git a/test/fuzz/xrow_decode_raft_fuzzer.c b/test/fuzz/xrow_decode_raft_fuzzer.c new file mode 100644 index 000000000000..554abb8dbbf9 --- /dev/null +++ b/test/fuzz/xrow_decode_raft_fuzzer.c @@ -0,0 +1,46 @@ +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "fiber.h" +#include "memory.h" + +void +cord_on_yield(void) {} + +__attribute__((constructor)) +static void +setup(void) +{ + memory_init(); + fiber_init(fiber_c_invoke); +} + +__attribute__((destructor)) +static void +teardown(void) +{ + fiber_free(); + memory_free(); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + struct iovec body = {0}; + body.iov_base = (void *)data; + body.iov_len = size; + + struct xrow_header row = {0}; + row.body[0] = body; + row.bodycnt = 1; + + struct raft_request request = {0}; + struct vclock vclock = {0}; + xrow_decode_raft(&row, &request, &vclock); + + return 0; +} diff --git a/test/fuzz/xrow_decode_sql_fuzzer.c b/test/fuzz/xrow_decode_sql_fuzzer.c new file mode 100644 index 000000000000..4cdc1e370433 --- /dev/null +++ b/test/fuzz/xrow_decode_sql_fuzzer.c @@ -0,0 +1,46 @@ +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "fiber.h" +#include "memory.h" + +void +cord_on_yield(void) {} + +__attribute__((constructor)) +static void +setup(void) +{ + memory_init(); + fiber_init(fiber_c_invoke); +} + +__attribute__((destructor)) +static void +teardown(void) +{ + fiber_free(); + memory_free(); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + struct iovec body = {0}; + body.iov_base = (void *)data; + body.iov_len = size; + + struct xrow_header row = {0}; + row.body[0] = body; + row.bodycnt = 1; + + struct sql_request request = {0}; + if (xrow_decode_sql(&row, &request) == -1) + return -1; + + return 0; +} diff --git a/test/fuzz/xrow_decode_watch_fuzzer.c b/test/fuzz/xrow_decode_watch_fuzzer.c new file mode 100644 index 000000000000..c76c50e8c5f1 --- /dev/null +++ b/test/fuzz/xrow_decode_watch_fuzzer.c @@ -0,0 +1,45 @@ +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "fiber.h" +#include "memory.h" + +void +cord_on_yield(void) {} + +__attribute__((constructor)) +static void +setup(void) +{ + memory_init(); + fiber_init(fiber_c_invoke); +} + +__attribute__((destructor)) +static void +teardown(void) +{ + fiber_free(); + memory_free(); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + struct iovec body = {0}; + body.iov_base = (void *)data; + body.iov_len = size; + + struct xrow_header row = {0}; + row.body[0] = body; + row.bodycnt = 1; + + struct watch_request request = {0}; + xrow_decode_watch(&row, &request); + + return 0; +} diff --git a/test/fuzz/xrow_greeting_decode_fuzzer.c b/test/fuzz/xrow_greeting_decode_fuzzer.c new file mode 100644 index 000000000000..88f9b619aa28 --- /dev/null +++ b/test/fuzz/xrow_greeting_decode_fuzzer.c @@ -0,0 +1,33 @@ +#include + +#include "box/xrow.h" +#include "box/iproto_constants.h" +#include "trivia/util.h" + +void +cord_on_yield(void) {} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + const char *d = (const char *)data; + const char *end = (const char *)data + size; + if (mp_check(&d, end) != 0) + return -1; + + if (size < IPROTO_GREETING_SIZE + 1) + return -1; + + char *greetingbuf = xcalloc(size + 1, sizeof(char)); + if (greetingbuf == NULL) + return 0; + memcpy(greetingbuf, data, size); + greetingbuf[size] = '\0'; + + struct greeting greeting = {0}; + greeting_decode(greetingbuf, &greeting); + + free(greetingbuf); + + return 0; +}