Skip to content

Commit

Permalink
Add tools to use LLVM's libFuzzer (#1507)
Browse files Browse the repository at this point in the history
This is useful for reproducing bugs found by oss-fuzz (see
https://bugs.chromium.org/p/oss-fuzz/issues/list?q=wabt)
  • Loading branch information
binji committed Aug 3, 2020
1 parent ef0d378 commit 05c1aa1
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 16 deletions.
39 changes: 34 additions & 5 deletions CMakeLists.txt
Expand Up @@ -55,6 +55,7 @@ endif ()
option(BUILD_TESTS "Build GTest-based tests" ON)
option(USE_SYSTEM_GTEST "Use system GTest, instead of building" OFF)
option(BUILD_TOOLS "Build wabt commandline tools" ON)
option(BUILD_FUZZ_TOOLS "Build tools that can repro fuzz bugs" OFF)
option(BUILD_LIBWASM "Build libwasm" ON)
option(USE_ASAN "Use address sanitizer" OFF)
option(USE_MSAN "Use memory sanitizer" OFF)
Expand Down Expand Up @@ -344,6 +345,15 @@ set(WABT_LIBRARY_SRC

add_library(wabt STATIC ${WABT_LIBRARY_SRC})

if (BUILD_FUZZ_TOOLS)
set(FUZZ_FLAGS "-fsanitize=fuzzer,address")
add_library(wabt-fuzz STATIC ${WABT_LIBRARY_SRC})
set_target_properties(wabt-fuzz
PROPERTIES
COMPILE_FLAGS "${FUZZ_FLAGS}"
)
endif ()

# libwasm, which implenents the wasm C API
if (BUILD_LIBWASM)
add_library(wasm SHARED ${WABT_LIBRARY_SRC} src/interp/interp-wasm-c-api.cc)
Expand All @@ -369,10 +379,15 @@ endif ()

include(CMakeParseArguments)
function(wabt_executable)
cmake_parse_arguments(EXE "WITH_LIBM;INSTALL" "NAME" "SOURCES;LIBS" ${ARGN})
cmake_parse_arguments(EXE "WITH_LIBM;FUZZ;INSTALL" "NAME" "SOURCES;LIBS" ${ARGN})

# Always link libwabt.
set(EXE_LIBS "${EXE_LIBS};wabt")
if (EXE_FUZZ)
set(EXE_LIBS "${EXE_LIBS};wabt-fuzz")
set(EXTRA_LINK_FLAGS "${FUZZ_FLAGS}")
else ()
set(EXE_LIBS "${EXE_LIBS};wabt")
endif ()

# Optionally link libm.
if (EXE_WITH_LIBM AND (COMPILER_IS_CLANG OR COMPILER_IS_GNU))
Expand All @@ -388,12 +403,16 @@ function(wabt_executable)
if (EMSCRIPTEN)
# build to JS for now, as node.js doesn't have code caching for wasm yet,
# and wasm startup times are slower
set_target_properties(${EXE_NAME}
PROPERTIES
LINK_FLAGS "-s NODERAWFS -s SINGLE_FILE -s WASM=0 -Oz -s ALLOW_MEMORY_GROWTH=1"
set(EXTRA_LINK_FLAGS
"${EXTRA_LINK_FLAGS} -s NODERAWFS -s SINGLE_FILE -s WASM=0 -Oz -s ALLOW_MEMORY_GROWTH=1"
)
endif ()

set_target_properties(${EXE_NAME}
PROPERTIES
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
)

if (EXE_INSTALL)
list(APPEND WABT_EXECUTABLES ${EXE_NAME})
set(WABT_EXECUTABLES ${WABT_EXECUTABLES} PARENT_SCOPE)
Expand Down Expand Up @@ -502,6 +521,16 @@ if (BUILD_TOOLS)
SOURCES src/tools/wasm-decompile.cc
INSTALL
)

if(BUILD_FUZZ_TOOLS)
# wasm2wat-fuzz
wabt_executable(
NAME wasm2wat-fuzz
SOURCES src/tools/wasm2wat-fuzz.cc
FUZZ
INSTALL
)
endif ()
endif ()

# Python 3.5 is the version shipped in Ubuntu Xenial
Expand Down
14 changes: 5 additions & 9 deletions Makefile
Expand Up @@ -20,23 +20,19 @@ MAKEFILE_NAME := $(lastword $(MAKEFILE_LIST))
ROOT_DIR := $(dir $(abspath $(MAKEFILE_NAME)))

USE_NINJA ?= 0
FUZZ_BIN_DIR ?= ${ROOT_DIR}/afl-fuzz
GCC_FUZZ_CC := ${FUZZ_BIN_DIR}/afl-gcc
GCC_FUZZ_CXX := ${FUZZ_BIN_DIR}/afl-g++
EMSCRIPTEN_DIR ?= $(dir $(shell which emcc))
CMAKE_CMD ?= cmake

DEFAULT_SUFFIX = clang-debug

COMPILERS := GCC GCC_I686 GCC_FUZZ CLANG CLANG_I686 EMCC
COMPILERS := GCC GCC_I686 CLANG CLANG_I686 EMCC
BUILD_TYPES := DEBUG RELEASE
SANITIZERS := ASAN MSAN LSAN UBSAN
SANITIZERS := ASAN MSAN LSAN UBSAN FUZZ
CONFIGS := NORMAL $(SANITIZERS) COV NO_TESTS

# directory names
GCC_DIR := gcc/
GCC_I686_DIR := gcc-i686/
GCC_FUZZ_DIR := gcc-fuzz/
CLANG_DIR := clang/
CLANG_I686_DIR := clang-i686/
EMCC_DIR := emscripten/
Expand All @@ -47,17 +43,16 @@ ASAN_DIR := asan/
MSAN_DIR := msan/
LSAN_DIR := lsan/
UBSAN_DIR := ubsan/
FUZZ_DIR := fuzz/
COV_DIR := cov/
NO_TESTS_DIR := no-tests/

# CMake flags
GCC_FLAG := -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++
GCC_I686_FLAG := -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ \
-DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32
GCC_FUZZ_FLAG := -DCMAKE_C_COMPILER=${GCC_FUZZ_CC} -DCMAKE_CXX_COMPILER=${GCC_FUZZ_CXX} -DWITH_EXCEPTIONS=ON
CLANG_FLAG := -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
CLANG_I686_FLAG := -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32
EMCC_FLAG := -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN_DIR}/cmake/Modules/Platform/Emscripten.cmake
DEBUG_FLAG := -DCMAKE_BUILD_TYPE=Debug
RELEASE_FLAG := -DCMAKE_BUILD_TYPE=Release
Expand All @@ -66,13 +61,13 @@ ASAN_FLAG := -DUSE_ASAN=ON
MSAN_FLAG := -DUSE_MSAN=ON
LSAN_FLAG := -DUSE_LSAN=ON
UBSAN_FLAG := -DUSE_UBSAN=ON
FUZZ_FLAG := -DBUILD_FUZZ_TOOLS=ON
COV_FLAG := -DCODE_COVERAGE=ON
NO_TESTS_FLAG := -DBUILD_TESTS=OFF

# make target prefixes
GCC_PREFIX := gcc
GCC_I686_PREFIX := gcc-i686
GCC_FUZZ_PREFIX := gcc-fuzz
CLANG_PREFIX := clang
CLANG_I686_PREFIX := clang-i686
EMCC_PREFIX := emscripten
Expand All @@ -83,6 +78,7 @@ ASAN_PREFIX := -asan
MSAN_PREFIX := -msan
LSAN_PREFIX := -lsan
UBSAN_PREFIX := -ubsan
FUZZ_PREFIX := -fuzz
COV_PREFIX := -cov
NO_TESTS_PREFIX := -no-tests

Expand Down
24 changes: 22 additions & 2 deletions README.md
Expand Up @@ -120,9 +120,9 @@ There are many make targets available for other configurations as well. They
are generated from every combination of a compiler, build type and
configuration.

- compilers: `gcc`, `clang`, `gcc-i686`, `gcc-fuzz`
- compilers: `gcc`, `clang`, `gcc-i686`, `emcc`
- build types: `debug`, `release`
- configurations: empty, `asan`, `msan`, `lsan`, `ubsan`, `no-tests`
- configurations: empty, `asan`, `msan`, `lsan`, `ubsan`, `fuzz`, `no-tests`

They are combined with dashes, for example:

Expand Down Expand Up @@ -333,3 +333,23 @@ $ CC=gcc scripts/travis-test.sh
$ CC=clang scripts/travis-build.sh
$ CC=clang scripts/travis-test.sh
```

## Fuzzing

To build using the [LLVM fuzzer support](https://llvm.org/docs/LibFuzzer.html),
append `fuzz` to the target:

```console
$ make clang-debug-fuzz
```

This will produce a `wasm2wat_fuzz` binary. It can be used to fuzz the binary
reader, as well as reproduce fuzzer errors found by
[oss-fuzz](https://github.com/google/oss-fuzz/tree/master/projects/wabt).

```console
$ out/clang/Debug/fuzz/wasm2wat_fuzz ...
```

See the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html) for
more information about how to use this tool.
30 changes: 30 additions & 0 deletions src/tools/wasm2wat-fuzz.cc
@@ -0,0 +1,30 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is copied from the oss-fuzz project:
//
// https://github.com/google/oss-fuzz/blob/master/projects/wabt/wasm2wat_fuzzer.cc

#include "src/binary-reader-ir.h"
#include "src/binary-reader.h"
#include "src/common.h"
#include "src/ir.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
wabt::ReadBinaryOptions options;
wabt::Errors errors;
wabt::Module module;
wabt::ReadBinaryIr("dummy filename", data, size, options, &errors, &module);
return 0;
}

0 comments on commit 05c1aa1

Please sign in to comment.