Skip to content

Commit

Permalink
test/fuzz: add fuzzing tests for IPROTO decoders
Browse files Browse the repository at this point in the history
Examples of IPROTO decoding issues: tarantool#3900, tarantool#1928, tarantool#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 46cacf3)
  • Loading branch information
ligurio committed Aug 16, 2023
1 parent 248af52 commit 11cc4e6
Show file tree
Hide file tree
Showing 11 changed files with 443 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/box/xrow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -1595,7 +1596,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. */
Expand Down
40 changes: 40 additions & 0 deletions test/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
45 changes: 45 additions & 0 deletions test/fuzz/xrow_decode_auth_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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;
}
46 changes: 46 additions & 0 deletions test/fuzz/xrow_decode_begin_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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;
}
46 changes: 46 additions & 0 deletions test/fuzz/xrow_decode_call_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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;
}
46 changes: 46 additions & 0 deletions test/fuzz/xrow_decode_dml_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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;
}
46 changes: 46 additions & 0 deletions test/fuzz/xrow_decode_id_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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;
}
46 changes: 46 additions & 0 deletions test/fuzz/xrow_decode_raft_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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;
}
46 changes: 46 additions & 0 deletions test/fuzz/xrow_decode_sql_fuzzer.c
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit 11cc4e6

Please sign in to comment.