From 791dd24d079aa43f3ddf1aaaecb209860e7ca239 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Thu, 20 Jul 2017 10:38:29 -0700 Subject: [PATCH] [fuzz] add support to build fuzzing targets (#2014) This enables adding OpenThread to OSS-Fuzz. --- configure.ac | 25 +++ tests/Makefile.am | 21 +- tests/fuzz/Makefile.am | 49 +++++ tests/fuzz/fuzzer_platform.c | 326 ++++++++++++++++++++++++++++++ tests/fuzz/radio_receive_done.cpp | 73 +++++++ 5 files changed, 488 insertions(+), 6 deletions(-) create mode 100644 tests/fuzz/Makefile.am create mode 100644 tests/fuzz/fuzzer_platform.c create mode 100644 tests/fuzz/radio_receive_done.cpp diff --git a/configure.ac b/configure.ac index 92407ef78..a324c3b31 100644 --- a/configure.ac +++ b/configure.ac @@ -297,6 +297,29 @@ NL_ENABLE_OPTIMIZATION([yes]) AM_CONDITIONAL([OPENTHREAD_BUILD_OPTIMIZED], [test "${nl_cv_build_optimized}" = "yes"]) +# Fuzz Targets + +AC_MSG_CHECKING([whether to build fuzz targets]) +AC_ARG_ENABLE(fuzz-targets, + [AS_HELP_STRING([--enable-fuzz-targets],[Enable building of fuzz targets @<:@default=no@:>@.])], + [ + case "${enableval}" in + + no|yes) + enable_fuzz_targets=${enableval} + ;; + + *) + AC_MSG_ERROR([Invalid value ${enableval} for --enable-fuzz-targets]) + ;; + + esac + ], + [enable_fuzz_targets=no]) +AC_MSG_RESULT(${enable_fuzz_targets}) + +AM_CONDITIONAL([OPENTHREAD_ENABLE_FUZZ_TARGETS], [test "${enable_fuzz_targets}" = "yes"]) + # Address Sanitizer AC_MSG_CHECKING([whether to build with Address Sanitizer support]) @@ -1376,6 +1399,7 @@ tools/harness-automation/Makefile tools/harness-thci/Makefile tools/spi-hdlc-adapter/Makefile tests/Makefile +tests/fuzz/Makefile tests/scripts/Makefile tests/scripts/thread-cert/Makefile tests/unit/Makefile @@ -1413,6 +1437,7 @@ AC_MSG_NOTICE([ Lcov : ${LCOV:--} Genhtml : ${GENHTML:--} Build tests : ${nl_cv_build_tests} + Build fuzz targets : ${enable_fuzz_targets} Build tools : ${build_tools} OpenThread tests : ${with_tests} Prefix : ${prefix} diff --git a/tests/Makefile.am b/tests/Makefile.am index b94e4be31..f00547a2a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -33,24 +33,33 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am DIST_SUBDIRS = \ unit \ scripts \ + fuzz \ $(NULL) # Always build (e.g. for 'make all') these subdirectories. +SUBDIRS = \ + $(NULL) + +# Always pretty (e.g. for 'make pretty') these subdirectories. + +PRETTY_SUBDIRS = \ + fuzz \ + unit \ + $(NULL) + if OPENTHREAD_EXAMPLES_POSIX if OPENTHREAD_ENABLE_CLI -SUBDIRS = \ +SUBDIRS += \ unit \ scripts \ $(NULL) endif endif -# Always pretty (e.g. for 'make pretty') these subdirectories. - -PRETTY_SUBDIRS = \ - unit \ - $(NULL) +if OPENTHREAD_ENABLE_FUZZ_TARGETS +SUBDIRS += fuzz +endif if OPENTHREAD_BUILD_TESTS if OPENTHREAD_BUILD_COVERAGE diff --git a/tests/fuzz/Makefile.am b/tests/fuzz/Makefile.am new file mode 100644 index 000000000..578108035 --- /dev/null +++ b/tests/fuzz/Makefile.am @@ -0,0 +1,49 @@ +# +# Copyright (c) 2017, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +include $(abs_top_nlbuild_autotools_dir)/automake/pre.am + +bin_PROGRAMS = \ + radio-receive-done-fuzzer \ + $(NULL) + +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/core \ + $(NULL) + +COMMON_LDADD = \ + $(top_builddir)/src/core/libopenthread-ftd.a \ + $(top_builddir)/third_party/mbedtls/libmbedcrypto.a \ + $(LIB_FUZZING_ENGINE) \ + $(NULL) + +radio_receive_done_fuzzer_LDADD = $(COMMON_LDADD) +radio_receive_done_fuzzer_SOURCES = radio_receive_done.cpp fuzzer_platform.c + +include $(abs_top_nlbuild_autotools_dir)/automake/post.am diff --git a/tests/fuzz/fuzzer_platform.c b/tests/fuzz/fuzzer_platform.c new file mode 100644 index 000000000..a52cb3837 --- /dev/null +++ b/tests/fuzz/fuzzer_platform.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +static uint32_t sRandomState = 1; + +uint32_t otPlatAlarmMilliGetNow(void) +{ + return 0; +} + +void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt) +{ + (void)aInstance; + (void)aT0; + (void)aDt; +} + +void otPlatAlarmMilliStop(otInstance *aInstance) +{ + (void)aInstance; +} + +void otPlatReset(otInstance *aInstance) +{ + (void)aInstance; +} + +otPlatResetReason otPlatGetResetReason(otInstance *aInstance) +{ + (void)aInstance; + return OT_PLAT_RESET_REASON_POWER_ON; +} + +void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...) +{ + (void)aLogLevel; + (void)aLogRegion; + (void)aFormat; +} + +void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) +{ + (void)aInstance; + (void)aIeeeEui64; +} + +void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId) +{ + (void)aInstance; + (void)aPanId; +} + +void otPlatRadioSetExtendedAddress(otInstance *aInstance, uint8_t *aExtAddr) +{ + (void)aInstance; + (void)aExtAddr; +} + +void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddr) +{ + (void)aInstance; + (void)aShortAddr; +} + +void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnabled) +{ + (void)aInstance; + (void)aEnabled; +} + +bool otPlatRadioIsEnabled(otInstance *aInstance) +{ + (void)aInstance; + return true; +} + +otError otPlatRadioEnable(otInstance *aInstance) +{ + (void)aInstance; + return OT_ERROR_NONE; +} + +otError otPlatRadioDisable(otInstance *aInstance) +{ + (void)aInstance; + return OT_ERROR_NONE; +} + +otError otPlatRadioSleep(otInstance *aInstance) +{ + (void)aInstance; + return OT_ERROR_NONE; +} + +otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) +{ + (void)aInstance; + (void)aChannel; + return OT_ERROR_NONE; +} + +otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) +{ + (void)aInstance; + (void)aFrame; + return OT_ERROR_NONE; +} + +otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) +{ + (void)aInstance; + return NULL; +} + +int8_t otPlatRadioGetRssi(otInstance *aInstance) +{ + (void)aInstance; + return 0; +} + +otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) +{ + (void)aInstance; + return OT_RADIO_CAPS_NONE; +} + +bool otPlatRadioGetPromiscuous(otInstance *aInstance) +{ + (void)aInstance; + return false; +} + +void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) +{ + (void)aInstance; + (void)aEnable; +} + +otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) +{ + (void)aInstance; + (void)aShortAddress; + return OT_ERROR_NONE; +} + +otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) +{ + (void)aInstance; + (void)aExtAddress; + return OT_ERROR_NONE; +} + +otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) +{ + (void)aInstance; + (void)aShortAddress; + return OT_ERROR_NONE; +} + +otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress) +{ + (void)aInstance; + (void)aExtAddress; + return OT_ERROR_NONE; +} + +void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) +{ + (void)aInstance; +} + +void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) +{ + (void)aInstance; +} + +otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) +{ + (void)aInstance; + (void)aScanChannel; + (void)aScanDuration; + return OT_ERROR_NOT_IMPLEMENTED; +} + +void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower) +{ + (void)aInstance; + (void)aPower; +} + +int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) +{ + (void)aInstance; + return 0; +} + +uint32_t otPlatRandomGet(void) +{ + uint32_t mlcg, p, q; + uint64_t tmpstate; + + tmpstate = (uint64_t)33614 * (uint64_t)sRandomState; + q = tmpstate & 0xffffffff; + q = q >> 1; + p = tmpstate >> 32; + mlcg = p + q; + + if (mlcg & 0x80000000) + { + mlcg &= 0x7fffffff; + mlcg++; + } + + sRandomState = mlcg; + + return mlcg; +} + +otError otPlatRandomGetTrue(uint8_t *aOutput, uint16_t aOutputLength) +{ + for (uint16_t length = 0; length < aOutputLength; length++) + { + aOutput[length] = (uint8_t)otPlatRandomGet(); + } + + return OT_ERROR_NONE; +} + +void otPlatSettingsInit(otInstance *aInstance) +{ + (void)aInstance; +} + +otError otPlatSettingsBeginChange(otInstance *aInstance) +{ + (void)aInstance; + return OT_ERROR_NONE; +} + +otError otPlatSettingsCommitChange(otInstance *aInstance) +{ + (void)aInstance; + return OT_ERROR_NONE; +} + +otError otPlatSettingsAbandonChange(otInstance *aInstance) +{ + (void)aInstance; + return OT_ERROR_NONE; +} + +otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, + uint16_t *aValueLength) +{ + (void)aInstance; + (void)aKey; + (void)aIndex; + (void)aValue; + (void)aValueLength; + return OT_ERROR_NOT_FOUND; +} + +otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength) +{ + (void)aInstance; + (void)aKey; + (void)aValue; + (void)aValueLength; + return OT_ERROR_NONE; +} + +otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength) +{ + (void)aInstance; + (void)aKey; + (void)aValue; + (void)aValueLength; + return OT_ERROR_NONE; +} + +otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex) +{ + (void)aInstance; + (void)aKey; + (void)aIndex; + return OT_ERROR_NONE; +} + +void otPlatSettingsWipe(otInstance *aInstance) +{ + (void)aInstance; +} diff --git a/tests/fuzz/radio_receive_done.cpp b/tests/fuzz/radio_receive_done.cpp new file mode 100644 index 000000000..9e83b0eb2 --- /dev/null +++ b/tests/fuzz/radio_receive_done.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +#include "common/code_utils.hpp" + +static otInstance *sInstance; + +extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) +{ + (void)argc; + (void)argv; + + sInstance = otInstanceInitSingle(); + otLinkSetPanId(sInstance, (otPanId)0xdead); + otIp6SetEnabled(sInstance, true); + + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + otRadioFrame frame; + uint8_t *buf; + + VerifyOrExit(size <= OT_RADIO_FRAME_MAX_SIZE); + + buf = static_cast(malloc(size)); + + memset(&frame, 0, sizeof(frame)); + frame.mPsdu = buf; + frame.mChannel = 11; + frame.mLength = static_cast(size); + + memcpy(buf, data, frame.mLength); + + otPlatRadioReceiveDone(sInstance, &frame, OT_ERROR_NONE); + + free(buf); + +exit: + return 0; +}