From e2646f93cc8f034e58dc7798469af1abbf5200c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A1ta=20Hodov=C3=A1n?= Date: Fri, 7 Jun 2019 14:43:20 +0200 Subject: [PATCH] Integrate LLVM's libfuzzer engine with JerryScript (#2898) JerryScript-DCO-1.0-Signed-off-by: Renata Hodovan reni@inf.u-szeged.hu --- CMakeLists.txt | 34 +++++++++++++++++++++++++++------ docs/01.GETTING-STARTED.md | 9 +++++++++ jerry-main/CMakeLists.txt | 6 ++++++ jerry-main/libfuzzer.c | 39 ++++++++++++++++++++++++++++++++++++++ tools/build.py | 3 +++ 5 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 jerry-main/libfuzzer.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0fea9d8c8..480900981 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ endif() set(JERRY_CMDLINE ON CACHE BOOL "Build jerry command line tool?") set(JERRY_CMDLINE_TEST OFF CACHE BOOL "Build jerry test command line tool?") set(JERRY_CMDLINE_SNAPSHOT OFF CACHE BOOL "Build jerry snapshot command line tool?") +set(JERRY_LIBFUZZER OFF CACHE BOOL "Build jerry with libfuzzer support?") set(JERRY_PORT_DEFAULT ON CACHE BOOL "Build default jerry port implementation?") set(JERRY_EXT ON CACHE BOOL "Build jerry-ext?") set(JERRY_LIBM ON CACHE BOOL "Build and use jerry-libm?") @@ -57,10 +58,26 @@ set(ENABLE_LTO ON CACHE BOOL "Enable LTO build?") set(ENABLE_STRIP ON CACHE BOOL "Enable stripping all symbols from release binary?") # Option overrides -if(JERRY_CMDLINE OR JERRY_CMDLINE_TEST OR JERRY_CMDLINE_SNAPSHOT OR UNITTESTS OR DOCTESTS) +if(NOT USING_CLANG) + set(JERRY_LIBFUZZER OFF) + + set(JERRY_LIBFUZZER_MESSAGE " (FORCED BY COMPILER)") +endif() + +if(JERRY_LIBFUZZER) + set(JERRY_CMDLINE OFF) + set(JERRY_CMDLINE_TEST OFF) + set(JERRY_CMDLINE_SNAPSHOT OFF) + + set(JERRY_CMDLINE_MESSAGE " (FORCED BY LIBFUZZER)") + set(JERRY_CMDLINE_TEST_MESSAGE " (FORCED BY LIBFUZZER)") + set(JERRY_CMDLINE_SNAPSHOT_MESSAGE " (FORCED BY LIBFUZZER)") +endif() + +if(JERRY_CMDLINE OR JERRY_CMDLINE_TEST OR JERRY_CMDLINE_SNAPSHOT OR JERRY_LIBFUZZER OR UNITTESTS OR DOCTESTS) set(JERRY_PORT_DEFAULT ON) - set(JERRY_PORT_DEFAULT_MESSAGE " (FORCED BY CMDLINE OR TESTS)") + set(JERRY_PORT_DEFAULT_MESSAGE " (FORCED BY CMDLINE OR LIBFUZZER OR TESTS)") endif() if(JERRY_CMDLINE OR DOCTESTS) @@ -101,9 +118,10 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR " ${CMAKE_SYSTEM_PROCESSOR}) message(STATUS "BUILD_SHARED_LIBS " ${BUILD_SHARED_LIBS}) message(STATUS "ENABLE_LTO " ${ENABLE_LTO} ${ENABLE_LTO_MESSAGE}) message(STATUS "ENABLE_STRIP " ${ENABLE_STRIP} ${ENABLE_STRIP_MESSAGE}) -message(STATUS "JERRY_CMDLINE " ${JERRY_CMDLINE}) -message(STATUS "JERRY_CMDLINE_TEST " ${JERRY_CMDLINE_TEST}) -message(STATUS "JERRY_CMDLINE_SNAPSHOT " ${JERRY_CMDLINE_SNAPSHOT}) +message(STATUS "JERRY_CMDLINE " ${JERRY_CMDLINE} ${JERRY_CMDLINE_MESSAGE}) +message(STATUS "JERRY_CMDLINE_TEST " ${JERRY_CMDLINE_TEST} ${JERRY_CMDLINE_TEST_MESSAGE}) +message(STATUS "JERRY_CMDLINE_SNAPSHOT " ${JERRY_CMDLINE_SNAPSHOT} ${JERRY_CMDLINE_SNAPSHOT_MESSAGE}) +message(STATUS "JERRY_LIBFUZZER " ${JERRY_LIBFUZZER} ${JERRY_LIBFUZZER_MESSAGE}) message(STATUS "JERRY_PORT_DEFAULT " ${JERRY_PORT_DEFAULT} ${JERRY_PORT_DEFAULT_MESSAGE}) message(STATUS "JERRY_EXT " ${JERRY_EXT} ${JERRY_EXT_MESSAGE}) message(STATUS "JERRY_LIBM " ${JERRY_LIBM} ${JERRY_LIBM_MESSAGE}) @@ -205,6 +223,10 @@ if(USING_MSVC) jerry_add_compile_flags(/wd4996) endif() +if(JERRY_LIBFUZZER) + jerry_add_compile_flags(-fsanitize=address,fuzzer) +endif() + # Strip binary if(ENABLE_STRIP AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug") jerry_add_link_flags(-s) @@ -238,7 +260,7 @@ if(JERRY_PORT_DEFAULT) endif() # Jerry command line tool -if(JERRY_CMDLINE OR JERRY_CMDLINE_TEST OR JERRY_CMDLINE_SNAPSHOT) +if(JERRY_CMDLINE OR JERRY_CMDLINE_TEST OR JERRY_CMDLINE_SNAPSHOT OR JERRY_LIBFUZZER) add_subdirectory(jerry-main) endif() diff --git a/docs/01.GETTING-STARTED.md b/docs/01.GETTING-STARTED.md index 3e9943ef7..067858a46 100644 --- a/docs/01.GETTING-STARTED.md +++ b/docs/01.GETTING-STARTED.md @@ -120,6 +120,15 @@ python tools/build.py --cpointer-32bit=on --mem-heap=1024 *Note*: The heap size will be allocated statically at compile time, when JerryScript memory allocator is used. +**To build with libfuzzer support** + +```bash +CC=clang python tools/build.py --libfuzzer=on --lto=off +``` + +Check the documentation of libfuzzer to get the runtime settings of the created fuzzer +binary: https://llvm.org/docs/LibFuzzer.html. + **To get a list of all the available buildoptions for Linux** ```bash diff --git a/jerry-main/CMakeLists.txt b/jerry-main/CMakeLists.txt index 4b24ef587..e3d81b36a 100644 --- a/jerry-main/CMakeLists.txt +++ b/jerry-main/CMakeLists.txt @@ -54,6 +54,12 @@ macro(jerry_create_executable JERRY_NAME) install(TARGETS ${JERRY_NAME} DESTINATION bin) endmacro() +# Jerry with libfuzzer support +if(JERRY_LIBFUZZER) + jerry_create_executable("jerry-libfuzzer" "libfuzzer.c") + target_link_libraries("jerry-libfuzzer" jerry-port-default) +endif() + # Jerry standalones if(JERRY_CMDLINE) jerry_create_executable("jerry" "main-unix.c" "cli.c") diff --git a/jerry-main/libfuzzer.c b/jerry-main/libfuzzer.c new file mode 100644 index 000000000..d0f7618a1 --- /dev/null +++ b/jerry-main/libfuzzer.c @@ -0,0 +1,39 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * 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. + */ + +#include "jerryscript.h" + + +int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) +{ + jerry_init (JERRY_INIT_EMPTY); + + if (jerry_is_valid_utf8_string ((jerry_char_t *) data, (jerry_size_t) size)) + { + jerry_value_t parse_value = jerry_parse (NULL, 0, (jerry_char_t *) data, size, JERRY_PARSE_NO_OPTS); + + if (!jerry_value_is_error (parse_value)) + { + jerry_value_t run_value = jerry_run (parse_value); + jerry_release_value (run_value); + } + + jerry_release_value (parse_value); + } + + jerry_cleanup (); + + return 0; +} /* LLVMFuzzerTestOneInput */ diff --git a/tools/build.py b/tools/build.py index 60106c071..74461df0d 100755 --- a/tools/build.py +++ b/tools/build.py @@ -90,6 +90,8 @@ def get_arguments(): help='build snapshot command line tool (%(choices)s)') compgrp.add_argument('--jerry-cmdline-test', metavar='X', choices=['ON', 'OFF'], type=str.upper, help=devhelp('build test version of the jerry command line tool (%(choices)s)')) + compgrp.add_argument('--libfuzzer', metavar='X', choices=['ON', 'OFF'], type=str.upper, + help='build jerry with libfuzzer support (%(choices)s)') compgrp.add_argument('--jerry-ext', metavar='X', choices=['ON', 'OFF'], type=str.upper, help='build jerry-ext (%(choices)s)') compgrp.add_argument('--jerry-libm', metavar='X', choices=['ON', 'OFF'], type=str.upper, @@ -184,6 +186,7 @@ def generate_build_options(arguments): build_options_append('JERRY_CMDLINE', arguments.jerry_cmdline) build_options_append('JERRY_CMDLINE_SNAPSHOT', arguments.jerry_cmdline_snapshot) build_options_append('JERRY_CMDLINE_TEST', arguments.jerry_cmdline_test) + build_options_append('JERRY_LIBFUZZER', arguments.libfuzzer) build_options_append('JERRY_EXT', arguments.jerry_ext) build_options_append('JERRY_LIBM', arguments.jerry_libm) build_options_append('JERRY_PORT_DEFAULT', arguments.jerry_port_default)