commit f269bb52f63e39f175a233f1d9482b2f223bebed from: Sergey Bronnikov date: Tue Aug 22 09:48:29 2023 UTC 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) commit - 14a9269e7dd5371e152b9d2f65f9508945f73060 commit + f269bb52f63e39f175a233f1d9482b2f223bebed blob - 3bfb01d5a133cdfc7f2fae8aa7787986f342fc33 blob + 32b8cf3af6cdbf6b62b51445b212374d72848ccf --- src/box/xrow.c +++ src/box/xrow.c @@ -1249,7 +1249,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"); @@ -1595,7 +1596,8 @@ error: 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. */ blob - 183b676e76ea7e3f444712e439d15bf10b9c9179 blob + 6ad7a203be7abc858a80ddf13de7df808938c234 --- test/fuzz/CMakeLists.txt +++ 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. blob - /dev/null blob + 7468b3a635994d2dcf34cc38ee9f2bf21ce0ab53 (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + cdb597cfb2d24c2392557d24dc862f61467f77fe (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + 63330b4de810e59d1f6cf76b6f1ad6f09348ff4c (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + 4486f313702408ea2f3b11979130801d518791c5 (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + 087b76d239191b4776c409a472ae88c6fe3cc040 (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + 554abb8dbbf92ff0fed9b99dee6a95e813587c19 (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + 4cdc1e370433d78e7290191617481edf7cf4b998 (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + c76c50e8c5f10f572643341f86c853c6663b88da (mode 644) --- /dev/null +++ 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; +} blob - /dev/null blob + 88f9b619aa28b07d8896c3070b50436bcd68d721 (mode 644) --- /dev/null +++ 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; +}