Skip to content

Commit

Permalink
[libc] Lay out framework for fuzzing libc functions.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
PaulkaToast committed Feb 22, 2020
1 parent e29065a commit a4f45ee
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 2 deletions.
1 change: 1 addition & 0 deletions libc/CMakeLists.txt
Expand Up @@ -32,3 +32,4 @@ add_subdirectory(utils)
# of the other directories.
add_subdirectory(lib)
add_subdirectory(test)
add_subdirectory(fuzzing)
67 changes: 66 additions & 1 deletion libc/cmake/modules/LLVMLibCRules.cmake
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
15 changes: 15 additions & 0 deletions libc/docs/fuzzing.rst
@@ -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.
10 changes: 9 additions & 1 deletion libc/docs/source_layout.rst
Expand Up @@ -7,6 +7,7 @@ directories::
+ libc
- cmake
- docs
- fuzzing
- include
- lib
- loader
Expand All @@ -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
-------------------------

Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions libc/fuzzing/CMakeLists.txt
@@ -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)
7 changes: 7 additions & 0 deletions libc/fuzzing/string/CMakeLists.txt
@@ -0,0 +1,7 @@
add_libc_fuzzer(
strcpy_fuzz
SRCS
strcpy_fuzz.cpp
DEPENDS
strcpy
)
38 changes: 38 additions & 0 deletions libc/fuzzing/string/strcpy_fuzz.cpp
@@ -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;
}

0 comments on commit a4f45ee

Please sign in to comment.