[libc] Lay out framework for fuzzing libc functions.

Summary:
Added fuzzing test for strcpy and some documentation related to fuzzing.
This will be the first step in integrating this with oss-fuzz.

Reviewers: sivachandra, abrachet

Reviewed By: sivachandra, abrachet

Subscribers: gchatelet, abrachet, mgorny, MaskRay, tschuett, libc-commits

Tags: #libc-project

Differential Revision: https://reviews.llvm.org/D74091
This commit is contained in:
Paula Toth 2020-02-21 19:14:51 -08:00
parent e29065a105
commit a4f45ee73a
7 changed files with 141 additions and 2 deletions

View File

@ -32,3 +32,4 @@ add_subdirectory(utils)
# of the other directories.
add_subdirectory(lib)
add_subdirectory(test)
add_subdirectory(fuzzing)

View File

@ -300,7 +300,7 @@ function(add_libc_unittest target_name)
if(NOT LLVM_INCLUDE_TESTS)
return()
endif()
cmake_parse_arguments(
"LIBC_UNITTEST"
"" # No optional arguments
@ -375,6 +375,71 @@ function(add_libc_testsuite suite_name)
add_dependencies(check-libc ${suite_name})
endfunction(add_libc_testsuite)
# Rule to add a fuzzer test.
# Usage
# add_libc_fuzzer(
# <target name>
# SRCS <list of .cpp files for the test>
# HDRS <list of .h files for the test>
# DEPENDS <list of dependencies>
# )
function(add_libc_fuzzer target_name)
cmake_parse_arguments(
"LIBC_FUZZER"
"" # No optional arguments
"" # Single value arguments
"SRCS;HDRS;DEPENDS" # Multi-value arguments
${ARGN}
)
if(NOT LIBC_FUZZER_SRCS)
message(FATAL_ERROR "'add_libc_fuzzer' target requires a SRCS list of .cpp files.")
endif()
if(NOT LIBC_FUZZER_DEPENDS)
message(FATAL_ERROR "'add_libc_fuzzer' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
endif()
set(library_deps "")
foreach(dep IN LISTS LIBC_FUZZER_DEPENDS)
get_target_property(dep_type ${dep} "TARGET_TYPE")
if (dep_type)
string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
if(dep_is_entrypoint)
get_target_property(obj_file ${dep} "OBJECT_FILE_RAW")
list(APPEND library_deps ${obj_file})
continue()
endif()
endif()
# TODO: Check if the dep is a normal CMake library target. If yes, then add it
# to the list of library_deps.
endforeach(dep)
add_executable(
${target_name}
EXCLUDE_FROM_ALL
${LIBC_FUZZER_SRCS}
${LIBC_FUZZER_HDRS}
)
target_include_directories(
${target_name}
PRIVATE
${LIBC_SOURCE_DIR}
${LIBC_BUILD_DIR}
${LIBC_BUILD_DIR}/include
)
if(library_deps)
target_link_libraries(${target_name} PRIVATE ${library_deps})
endif()
set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_dependencies(
${target_name}
${LIBC_FUZZER_DEPENDS}
)
add_dependencies(libc-fuzzer ${target_name})
endfunction(add_libc_fuzzer)
# Rule to add header only libraries.
# Usage
# add_header_library(

15
libc/docs/fuzzing.rst Normal file
View File

@ -0,0 +1,15 @@
Fuzzing for LLVM-libc
---------------------
Fuzzing tests are used to ensure quality and security of LLVM-libc
implementations.
Each fuzzing test lives under the fuzzing directory in a subdirectory
corresponding with the src layout.
Currently we use system libc for functions that have yet to be implemented,
however as they are implemented the fuzzers will be changed to use our
implementation to increase coverage for testing.
Fuzzers will be run on `oss-fuzz <https://github.com/google/oss-fuzz>`_ and the
check-libc target will ensure that they build correctly.

View File

@ -7,6 +7,7 @@ directories::
+ libc
- cmake
- docs
- fuzzing
- include
- lib
- loader
@ -31,6 +32,13 @@ The ``docs`` directory
The ``docs`` directory contains design docs and also informative documents like
this document on source layout.
The ``fuzzing`` directory
----------------------
This directory contains fuzzing tests for the various components of llvm-libc. The
directory structure within this directory mirrors the directory structure of the
top-level ``libc`` directory itself. For more details, see :doc:`fuzzing`.
The ``include`` directory
-------------------------
@ -62,7 +70,7 @@ The ``src`` directory
This directory contains the implementations of the llvm-libc entrypoints. It is
further organized as follows:
1. There is a toplevel CMakeLists.txt file.
1. There is a top-level CMakeLists.txt file.
2. For every public header file provided by llvm-libc, there exists a
corresponding directory in the ``src`` directory. The name of the directory
is same as the base name of the header file. For example, the directory

View File

@ -0,0 +1,5 @@
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer")
add_custom_target(libc-fuzzer)
add_dependencies(check-libc libc-fuzzer)
add_subdirectory(string)

View File

@ -0,0 +1,7 @@
add_libc_fuzzer(
strcpy_fuzz
SRCS
strcpy_fuzz.cpp
DEPENDS
strcpy
)

View File

@ -0,0 +1,38 @@
//===--------------------- strcpy_fuzz.cpp --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// Fuzzing test for llvm-libc strcpy implementation.
///
//===----------------------------------------------------------------------===//
#include "src/string/strcpy.h"
#include <stdint.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Validate input
if (!size) return 0;
if (data[size - 1] != '\0') return 0;
const char *src = (const char *)data;
char *dest = new char[size];
if (!dest) __builtin_trap();
__llvm_libc::strcpy(dest, src);
size_t i;
for (i = 0; src[i] != '\0'; i++) {
// Ensure correctness of strcpy
if (dest[i] != src[i]) __builtin_trap();
}
// Ensure strcpy null terminates dest
if (dest[i] != src[i]) __builtin_trap();
delete[] dest;
return 0;
}