From 07e9ffb97b747b22250f66a2210898db57c266c1 Mon Sep 17 00:00:00 2001 From: Petteri Aimonen Date: Thu, 11 Sep 2014 17:58:53 +0300 Subject: [PATCH 1/1] Add a fuzz testing stub for ability to use external generators also --- tests/fuzztest/SConscript | 8 ++ tests/fuzztest/fuzzstub.c | 189 ++++++++++++++++++++++++++++++++++ tests/fuzztest/run_radamsa.sh | 12 +++ tests/fuzztest/sample_data/sample1.pb | Bin 0 -> 573 bytes tests/fuzztest/sample_data/sample2.pb | Bin 0 -> 466 bytes 5 files changed, 209 insertions(+) create mode 100644 tests/fuzztest/fuzzstub.c create mode 100755 tests/fuzztest/run_radamsa.sh create mode 100644 tests/fuzztest/sample_data/sample1.pb create mode 100644 tests/fuzztest/sample_data/sample2.pb diff --git a/tests/fuzztest/SConscript b/tests/fuzztest/SConscript index 36b62c56..6499714f 100644 --- a/tests/fuzztest/SConscript +++ b/tests/fuzztest/SConscript @@ -47,4 +47,12 @@ Depends([p1, p2, fuzz], ["fuzz_syshdr.h", "malloc_wrappers.h"]) env.RunTest(fuzz) +fuzzstub = env.Program(["fuzzstub.c", + "alltypes_pointer.pb.c", + "alltypes_static.pb.c", + "pb_encode_with_malloc.o", + "pb_decode_with_malloc.o", + "pb_common_with_malloc.o", + "malloc_wrappers.c"]) + diff --git a/tests/fuzztest/fuzzstub.c b/tests/fuzztest/fuzzstub.c new file mode 100644 index 00000000..50998416 --- /dev/null +++ b/tests/fuzztest/fuzzstub.c @@ -0,0 +1,189 @@ +/* Fuzz testing for the nanopb core. + * This can be used with external fuzzers, e.g. radamsa. + * It performs most of the same checks as fuzztest, but does not feature data generation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "malloc_wrappers.h" +#include "alltypes_static.pb.h" +#include "alltypes_pointer.pb.h" + +#define BUFSIZE 4096 + +static bool do_static_decode(uint8_t *buffer, size_t msglen, bool assert_success) +{ + pb_istream_t stream; + bool status; + + alltypes_static_AllTypes *msg = malloc_with_check(sizeof(alltypes_static_AllTypes)); + stream = pb_istream_from_buffer(buffer, msglen); + status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg); + + if (!status && assert_success) + { + /* Anything that was successfully encoded, should be decodeable. + * One exception: strings without null terminator are encoded up + * to end of buffer, but refused on decode because the terminator + * would not fit. */ + if (strcmp(stream.errmsg, "string overflow") != 0) + assert(status); + } + + free_with_check(msg); + return status; +} + +static bool do_pointer_decode(uint8_t *buffer, size_t msglen, bool assert_success) +{ + pb_istream_t stream; + bool status; + alltypes_pointer_AllTypes *msg; + + msg = malloc_with_check(sizeof(alltypes_pointer_AllTypes)); + memset(msg, 0, sizeof(alltypes_pointer_AllTypes)); + stream = pb_istream_from_buffer(buffer, msglen); + + assert(get_alloc_count() == 0); + status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg); + + if (assert_success) + assert(status); + + pb_release(alltypes_pointer_AllTypes_fields, msg); + assert(get_alloc_count() == 0); + + free_with_check(msg); + + return status; +} + +/* Do a decode -> encode -> decode -> encode roundtrip */ +static void do_static_roundtrip(uint8_t *buffer, size_t msglen) +{ + bool status; + uint8_t *buf2 = malloc_with_check(BUFSIZE); + uint8_t *buf3 = malloc_with_check(BUFSIZE); + size_t msglen2, msglen3; + alltypes_static_AllTypes *msg1 = malloc_with_check(sizeof(alltypes_static_AllTypes)); + alltypes_static_AllTypes *msg2 = malloc_with_check(sizeof(alltypes_static_AllTypes)); + memset(msg1, 0, sizeof(alltypes_static_AllTypes)); + memset(msg2, 0, sizeof(alltypes_static_AllTypes)); + + { + pb_istream_t stream = pb_istream_from_buffer(buffer, msglen); + status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg1); + assert(status); + } + + { + pb_ostream_t stream = pb_ostream_from_buffer(buf2, BUFSIZE); + status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg1); + assert(status); + msglen2 = stream.bytes_written; + } + + { + pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2); + status = pb_decode(&stream, alltypes_static_AllTypes_fields, msg2); + assert(status); + } + + { + pb_ostream_t stream = pb_ostream_from_buffer(buf3, BUFSIZE); + status = pb_encode(&stream, alltypes_static_AllTypes_fields, msg2); + assert(status); + msglen3 = stream.bytes_written; + } + + assert(msglen2 == msglen3); + assert(memcmp(buf2, buf3, msglen2) == 0); + + free_with_check(msg1); + free_with_check(msg2); + free_with_check(buf2); + free_with_check(buf3); +} + +/* Do decode -> encode -> decode -> encode roundtrip */ +static void do_pointer_roundtrip(uint8_t *buffer, size_t msglen) +{ + bool status; + uint8_t *buf2 = malloc_with_check(BUFSIZE); + uint8_t *buf3 = malloc_with_check(BUFSIZE); + size_t msglen2, msglen3; + alltypes_pointer_AllTypes *msg1 = malloc_with_check(sizeof(alltypes_pointer_AllTypes)); + alltypes_pointer_AllTypes *msg2 = malloc_with_check(sizeof(alltypes_pointer_AllTypes)); + memset(msg1, 0, sizeof(alltypes_pointer_AllTypes)); + memset(msg2, 0, sizeof(alltypes_pointer_AllTypes)); + + { + pb_istream_t stream = pb_istream_from_buffer(buffer, msglen); + status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg1); + assert(status); + } + + { + pb_ostream_t stream = pb_ostream_from_buffer(buf2, BUFSIZE); + status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg1); + assert(status); + msglen2 = stream.bytes_written; + } + + { + pb_istream_t stream = pb_istream_from_buffer(buf2, msglen2); + status = pb_decode(&stream, alltypes_pointer_AllTypes_fields, msg2); + assert(status); + } + + { + pb_ostream_t stream = pb_ostream_from_buffer(buf3, BUFSIZE); + status = pb_encode(&stream, alltypes_pointer_AllTypes_fields, msg2); + assert(status); + msglen3 = stream.bytes_written; + } + + assert(msglen2 == msglen3); + assert(memcmp(buf2, buf3, msglen2) == 0); + + pb_release(alltypes_pointer_AllTypes_fields, msg1); + pb_release(alltypes_pointer_AllTypes_fields, msg2); + free_with_check(msg1); + free_with_check(msg2); + free_with_check(buf2); + free_with_check(buf3); +} + +static void run_iteration() +{ + uint8_t *buffer = malloc_with_check(BUFSIZE); + size_t msglen; + bool status; + + msglen = fread(buffer, BUFSIZE, 1, stdin); + + status = do_static_decode(buffer, msglen, false); + + if (status) + do_static_roundtrip(buffer, msglen); + + status = do_pointer_decode(buffer, msglen, false); + + if (status) + do_pointer_roundtrip(buffer, msglen); + + free_with_check(buffer); +} + +int main(int argc, char **argv) +{ + run_iteration(); + + return 0; +} + diff --git a/tests/fuzztest/run_radamsa.sh b/tests/fuzztest/run_radamsa.sh new file mode 100755 index 00000000..52cd40a8 --- /dev/null +++ b/tests/fuzztest/run_radamsa.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +TMP=`tempfile` + +echo $TMP +while true +do + radamsa sample_data/* > $TMP + $1 < $TMP + test $? -gt 127 && break +done + diff --git a/tests/fuzztest/sample_data/sample1.pb b/tests/fuzztest/sample_data/sample1.pb new file mode 100644 index 0000000000000000000000000000000000000000..07527885b1c128d45b82b1844b0634f61509a3a3 GIT binary patch literal 573 zcmd;>{^LIcFbYhAGbLWLE4*RXxXEvDo8N-b^#d~lgD?M||Nlc78fsi3KLfcSkjMiR z0)b30cSXNL5sRULp-B~pG;Lz!2U58H14P$<#!V1`b#Q@Q zjBFqkm-!Dt7+3gDK^QCLFF_cq>vg48fRViW<<$lwM$1H&s!VRfLtK4A(oIQ(|` z#i)U705Y5)%UwVle^+-z+8uBm@#NUBtw~#UQ|d zgW}@?DKZmyz%Tm%=-5?E-~iIv#KeG%Cb9W&GynnEjf?`IIAE7xPyo^V8XyTUU^D;; cfIz(kg9C&GBpE##fzlAI0U%NK8EmIH00lOoX8-^I literal 0 HcmV?d00001 diff --git a/tests/fuzztest/sample_data/sample2.pb b/tests/fuzztest/sample_data/sample2.pb new file mode 100644 index 0000000000000000000000000000000000000000..cc89f91b078df921259c34e949017cc937fcffcb GIT binary patch literal 466 zcmd;>{^S3Det~H~5)2q6Ub8E_Vb{3HZ*ZI6g3=W0x2>Rc)&0F0O;6NOyB_0n!$FO0|0neVCet= literal 0 HcmV?d00001 -- 2.16.6