[compiler-rt] f78d9fc - [libFuzzer] Link libFuzzer's own interceptors when other compiler runtimes are not linked.

Matt Morehouse via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 17 07:38:05 PDT 2020


+Dokyung Song <dokyungs at google.com>

On Thu, Jul 16, 2020 at 6:11 PM Richard Smith <richard at metafoo.co.uk> wrote:

> I reverted this and the follow-up change 12d1124 in 8ef9e2b.
>
> These interceptors will need to be protected against the possibility that
> they are re-entered during their own initialization. Calling dlsym can
> recursively invoke these functions. (The ASan interceptors already contain
> this kind of protection, at least for some of their interceptors.)
>
> On Thu, 16 Jul 2020 at 13:27, Matt Morehouse via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>>
>> Author: Dokyung Song
>> Date: 2020-07-16T20:26:35Z
>> New Revision: f78d9fceea736d431e9e3cbca291e3909e3aa46d
>>
>> URL:
>> https://github.com/llvm/llvm-project/commit/f78d9fceea736d431e9e3cbca291e3909e3aa46d
>> DIFF:
>> https://github.com/llvm/llvm-project/commit/f78d9fceea736d431e9e3cbca291e3909e3aa46d.diff
>>
>> LOG: [libFuzzer] Link libFuzzer's own interceptors when other compiler
>> runtimes are not linked.
>>
>> Summary: libFuzzer intercepts certain library functions such as
>> memcmp/strcmp by defining weak hooks. Weak hooks, however, are called only
>> when other runtimes such as ASan is linked. This patch defines libFuzzer's
>> own interceptors, which is linked into the libFuzzer executable when other
>> runtimes are not linked, i.e., when -fsanitize=fuzzer is given, but not
>> others.
>>
>> Reviewers: kcc, morehouse, hctim
>>
>> Reviewed By: morehouse, hctim
>>
>> Subscribers: krytarowski, mgorny, cfe-commits, #sanitizers
>>
>> Tags: #clang, #sanitizers
>>
>> Differential Revision: https://reviews.llvm.org/D83494
>>
>> Added:
>>     compiler-rt/lib/fuzzer/FuzzerInterceptors.cpp
>>
>> Modified:
>>     clang/include/clang/Driver/SanitizerArgs.h
>>     clang/lib/Driver/SanitizerArgs.cpp
>>     clang/lib/Driver/ToolChains/CommonArgs.cpp
>>     compiler-rt/lib/fuzzer/CMakeLists.txt
>>     compiler-rt/test/fuzzer/memcmp.test
>>     compiler-rt/test/fuzzer/memcmp64.test
>>     compiler-rt/test/fuzzer/strcmp.test
>>     compiler-rt/test/fuzzer/strncmp.test
>>     compiler-rt/test/fuzzer/strstr.test
>>
>> Removed:
>>
>>
>>
>>
>> ################################################################################
>> diff  --git a/clang/include/clang/Driver/SanitizerArgs.h
>> b/clang/include/clang/Driver/SanitizerArgs.h
>> index 934dab808e82..563d6c3ff9de 100644
>> --- a/clang/include/clang/Driver/SanitizerArgs.h
>> +++ b/clang/include/clang/Driver/SanitizerArgs.h
>> @@ -74,6 +74,7 @@ class SanitizerArgs {
>>             !Sanitizers.has(SanitizerKind::Address) &&
>>             !Sanitizers.has(SanitizerKind::HWAddress);
>>    }
>> +  bool needsFuzzerInterceptors() const;
>>    bool needsUbsanRt() const;
>>    bool requiresMinimalRuntime() const { return MinimalRuntime; }
>>    bool needsDfsanRt() const { return
>> Sanitizers.has(SanitizerKind::DataFlow); }
>>
>> diff  --git a/clang/lib/Driver/SanitizerArgs.cpp
>> b/clang/lib/Driver/SanitizerArgs.cpp
>> index bcc9ffc7ff8f..e4fda752c041 100644
>> --- a/clang/lib/Driver/SanitizerArgs.cpp
>> +++ b/clang/lib/Driver/SanitizerArgs.cpp
>> @@ -240,6 +240,10 @@ static SanitizerMask parseSanitizeTrapArgs(const
>> Driver &D,
>>    return TrappingKinds;
>>  }
>>
>> +bool SanitizerArgs::needsFuzzerInterceptors() const {
>> +  return needsFuzzer() && !needsAsanRt() && !needsTsanRt() &&
>> !needsMsanRt();
>> +}
>> +
>>  bool SanitizerArgs::needsUbsanRt() const {
>>    // All of these include ubsan.
>>    if (needsAsanRt() || needsMsanRt() || needsHwasanRt() || needsTsanRt()
>> ||
>>
>> diff  --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp
>> b/clang/lib/Driver/ToolChains/CommonArgs.cpp
>> index 6b6e276b8ce7..acde6d9e2111 100644
>> --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
>> +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
>> @@ -784,6 +784,9 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC,
>> const ArgList &Args,
>>        !Args.hasArg(options::OPT_shared)) {
>>
>>      addSanitizerRuntime(TC, Args, CmdArgs, "fuzzer", false, true);
>> +    if (SanArgs.needsFuzzerInterceptors())
>> +      addSanitizerRuntime(TC, Args, CmdArgs, "fuzzer_interceptors",
>> false,
>> +                          true);
>>      if (!Args.hasArg(clang::driver::options::OPT_nostdlibxx))
>>        TC.AddCXXStdlibLibArgs(Args, CmdArgs);
>>    }
>>
>> diff  --git a/compiler-rt/lib/fuzzer/CMakeLists.txt
>> b/compiler-rt/lib/fuzzer/CMakeLists.txt
>> index b5be6b89452e..02be89cb70a5 100644
>> --- a/compiler-rt/lib/fuzzer/CMakeLists.txt
>> +++ b/compiler-rt/lib/fuzzer/CMakeLists.txt
>> @@ -99,6 +99,13 @@ add_compiler_rt_object_libraries(RTfuzzer_main
>>    CFLAGS ${LIBFUZZER_CFLAGS}
>>    DEPS ${LIBFUZZER_DEPS})
>>
>> +add_compiler_rt_object_libraries(RTfuzzer_interceptors
>> +  OS ${FUZZER_SUPPORTED_OS}
>> +  ARCHS ${FUZZER_SUPPORTED_ARCH}
>> +  SOURCES FuzzerInterceptors.cpp
>> +  CFLAGS ${LIBFUZZER_CFLAGS}
>> +  DEPS ${LIBFUZZER_DEPS})
>> +
>>  add_compiler_rt_runtime(clang_rt.fuzzer
>>    STATIC
>>    OS ${FUZZER_SUPPORTED_OS}
>> @@ -115,6 +122,14 @@ add_compiler_rt_runtime(clang_rt.fuzzer_no_main
>>    CFLAGS ${LIBFUZZER_CFLAGS}
>>    PARENT_TARGET fuzzer)
>>
>> +add_compiler_rt_runtime(clang_rt.fuzzer_interceptors
>> +  STATIC
>> +  OS ${FUZZER_SUPPORTED_OS}
>> +  ARCHS ${FUZZER_SUPPORTED_ARCH}
>> +  OBJECT_LIBS RTfuzzer_interceptors
>> +  CFLAGS ${LIBFUZZER_CFLAGS}
>> +  PARENT_TARGET fuzzer)
>> +
>>  if(OS_NAME MATCHES "Linux|Fuchsia" AND
>>     COMPILER_RT_LIBCXX_PATH AND
>>     COMPILER_RT_LIBCXXABI_PATH)
>> @@ -148,7 +163,10 @@ if(OS_NAME MATCHES "Linux|Fuchsia" AND
>>      add_dependencies(RTfuzzer.${arch} libcxx_fuzzer_${arch}-build)
>>      target_compile_options(RTfuzzer_main.${arch} PRIVATE -isystem
>> ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
>>      add_dependencies(RTfuzzer_main.${arch} libcxx_fuzzer_${arch}-build)
>> +    target_compile_options(RTfuzzer_interceptors.${arch} PRIVATE
>> -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
>> +    add_dependencies(RTfuzzer_interceptors.${arch}
>> libcxx_fuzzer_${arch}-build)
>>      partially_link_libcxx(fuzzer_no_main ${LIBCXX_${arch}_PREFIX}
>> ${arch})
>> +    partially_link_libcxx(fuzzer_interceptors ${LIBCXX_${arch}_PREFIX}
>> ${arch})
>>      partially_link_libcxx(fuzzer ${LIBCXX_${arch}_PREFIX} ${arch})
>>    endforeach()
>>  endif()
>>
>> diff  --git a/compiler-rt/lib/fuzzer/FuzzerInterceptors.cpp
>> b/compiler-rt/lib/fuzzer/FuzzerInterceptors.cpp
>> new file mode 100644
>> index 000000000000..cb55b4af38fa
>> --- /dev/null
>> +++ b/compiler-rt/lib/fuzzer/FuzzerInterceptors.cpp
>> @@ -0,0 +1,170 @@
>> +//===-- FuzzerInterceptors.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
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +// Intercept certain libc functions to aid fuzzing.
>> +// Linked only when other RTs that define their own interceptors are not
>> linked.
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "FuzzerPlatform.h"
>> +
>> +#if LIBFUZZER_LINUX
>> +
>> +#define GET_CALLER_PC() __builtin_return_address(0)
>> +
>> +#define PTR_TO_REAL(x) real_##x
>> +#define REAL(x) __interception::PTR_TO_REAL(x)
>> +#define FUNC_TYPE(x) x##_type
>> +#define DEFINE_REAL(ret_type, func, ...)
>>        \
>> +  typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__);
>>       \
>> +  namespace __interception {
>>        \
>> +  FUNC_TYPE(func) PTR_TO_REAL(func);
>>        \
>> +  }
>> +
>> +#include <cassert>
>> +#include <cstdint>
>> +#include <dlfcn.h> // for dlsym()
>> +#include <sanitizer/common_interface_defs.h>
>> +
>> +static void *getFuncAddr(const char *name, uintptr_t wrapper_addr) {
>> +  void *addr = dlsym(RTLD_NEXT, name);
>> +  if (!addr) {
>> +    // If the lookup using RTLD_NEXT failed, the sanitizer runtime
>> library is
>> +    // later in the library search order than the DSO that we are trying
>> to
>> +    // intercept, which means that we cannot intercept this function. We
>> still
>> +    // want the address of the real definition, though, so look it up
>> using
>> +    // RTLD_DEFAULT.
>> +    addr = dlsym(RTLD_DEFAULT, name);
>> +
>> +    // In case `name' is not loaded, dlsym ends up finding the actual
>> wrapper.
>> +    // We don't want to intercept the wrapper and have it point to
>> itself.
>> +    if (reinterpret_cast<uintptr_t>(addr) == wrapper_addr)
>> +      addr = nullptr;
>> +  }
>> +  return addr;
>> +}
>> +
>> +static int FuzzerInited = 0;
>> +static bool FuzzerInitIsRunning;
>> +
>> +static void fuzzerInit();
>> +
>> +static void ensureFuzzerInited() {
>> +  assert(!FuzzerInitIsRunning);
>> +  if (!FuzzerInited) {
>> +    fuzzerInit();
>> +  }
>> +}
>> +
>> +extern "C" {
>> +
>> +DEFINE_REAL(int, memcmp, const void *, const void *, size_t)
>> +DEFINE_REAL(int, strncmp, const char *, const char *, size_t)
>> +DEFINE_REAL(int, strcmp, const char *, const char *)
>> +DEFINE_REAL(int, strncasecmp, const char *, const char *, size_t)
>> +DEFINE_REAL(int, strcasecmp, const char *, const char *)
>> +DEFINE_REAL(char *, strstr, const char *, const char *)
>> +DEFINE_REAL(char *, strcasestr, const char *, const char *)
>> +DEFINE_REAL(void *, memmem, const void *, size_t, const void *, size_t)
>> +
>> +ATTRIBUTE_INTERFACE int memcmp(const void *s1, const void *s2, size_t n)
>> {
>> +  ensureFuzzerInited();
>> +  int result = REAL(memcmp)(s1, s2, n);
>> +  __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result);
>> +
>> +  return result;
>> +}
>> +
>> +ATTRIBUTE_INTERFACE int strncmp(const char *s1, const char *s2, size_t
>> n) {
>> +  ensureFuzzerInited();
>> +  int result = REAL(strncmp)(s1, s2, n);
>> +  __sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1, s2, n, result);
>> +
>> +  return result;
>> +}
>> +
>> +ATTRIBUTE_INTERFACE int strcmp(const char *s1, const char *s2) {
>> +  ensureFuzzerInited();
>> +  int result = REAL(strcmp)(s1, s2);
>> +  __sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1, s2, result);
>> +
>> +  return result;
>> +}
>> +
>> +ATTRIBUTE_INTERFACE int strncasecmp(const char *s1, const char *s2,
>> size_t n) {
>> +  ensureFuzzerInited();
>> +  int result = REAL(strncasecmp)(s1, s2, n);
>> +  __sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1, s2, n, result);
>> +
>> +  return result;
>> +}
>> +
>> +ATTRIBUTE_INTERFACE int strcasecmp(const char *s1, const char *s2) {
>> +  ensureFuzzerInited();
>> +  int result = REAL(strcasecmp)(s1, s2);
>> +  __sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1, s2, result);
>> +
>> +  return result;
>> +}
>> +
>> +ATTRIBUTE_INTERFACE char *strstr(const char *s1, const char *s2) {
>> +  ensureFuzzerInited();
>> +  char *result = REAL(strstr)(s1, s2);
>> +  __sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1, s2, result);
>> +
>> +  return result;
>> +}
>> +
>> +ATTRIBUTE_INTERFACE char *strcasestr(const char *s1, const char *s2) {
>> +  ensureFuzzerInited();
>> +  char *result = REAL(strcasestr)(s1, s2);
>> +  __sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1, s2, result);
>> +
>> +  return result;
>> +}
>> +
>> +ATTRIBUTE_INTERFACE
>> +void *memmem(const void *s1, size_t len1, const void *s2, size_t len2) {
>> +  ensureFuzzerInited();
>> +  void *result = REAL(memmem)(s1, len1, s2, len2);
>> +  __sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1, len1, s2, len2,
>> result);
>> +
>> +  return result;
>> +}
>> +
>> +__attribute__((section(".preinit_array"),
>> +               used)) static void (*__local_fuzzer_preinit)(void) =
>> fuzzerInit;
>> +
>> +} // extern "C"
>> +
>> +static void fuzzerInit() {
>> +  assert(!FuzzerInitIsRunning);
>> +  if (FuzzerInited)
>> +    return;
>> +  FuzzerInitIsRunning = true;
>> +
>> +  REAL(memcmp) = reinterpret_cast<memcmp_type>(
>> +      getFuncAddr("memcmp", reinterpret_cast<uintptr_t>(&memcmp)));
>> +  REAL(strncmp) = reinterpret_cast<strncmp_type>(
>> +      getFuncAddr("strncmp", reinterpret_cast<uintptr_t>(&strncmp)));
>> +  REAL(strcmp) = reinterpret_cast<strcmp_type>(
>> +      getFuncAddr("strcmp", reinterpret_cast<uintptr_t>(&strcmp)));
>> +  REAL(strncasecmp) = reinterpret_cast<strncasecmp_type>(
>> +      getFuncAddr("strncasecmp",
>> reinterpret_cast<uintptr_t>(&strncasecmp)));
>> +  REAL(strcasecmp) = reinterpret_cast<strcasecmp_type>(
>> +      getFuncAddr("strcasecmp",
>> reinterpret_cast<uintptr_t>(&strcasecmp)));
>> +  REAL(strstr) = reinterpret_cast<strstr_type>(
>> +      getFuncAddr("strstr", reinterpret_cast<uintptr_t>(&strstr)));
>> +  REAL(strcasestr) = reinterpret_cast<strcasestr_type>(
>> +      getFuncAddr("strcasestr",
>> reinterpret_cast<uintptr_t>(&strcasestr)));
>> +  REAL(memmem) = reinterpret_cast<memmem_type>(
>> +      getFuncAddr("memmem", reinterpret_cast<uintptr_t>(&memmem)));
>> +
>> +  FuzzerInitIsRunning = false;
>> +  FuzzerInited = 1;
>> +}
>> +
>> +#endif
>>
>> diff  --git a/compiler-rt/test/fuzzer/memcmp.test
>> b/compiler-rt/test/fuzzer/memcmp.test
>> index 5657cab41dfc..8859afbe8a97 100644
>> --- a/compiler-rt/test/fuzzer/memcmp.test
>> +++ b/compiler-rt/test/fuzzer/memcmp.test
>> @@ -1,4 +1,8 @@
>>  UNSUPPORTED: freebsd
>>  RUN: %cpp_compiler %S/MemcmpTest.cpp -o %t-MemcmpTest
>>  RUN: not %run %t-MemcmpTest               -seed=1 -runs=10000000   2>&1
>> | FileCheck %s
>> +
>> +RUN: %cpp_compiler -fno-sanitize=address -fno-builtin-memcmp
>> %S/MemcmpTest.cpp -o %t-NoAsanMemcmpTest
>> +RUN: not %run %t-MemcmpTest               -seed=1 -runs=10000000   2>&1
>> | FileCheck %s
>> +
>>  CHECK: BINGO
>>
>> diff  --git a/compiler-rt/test/fuzzer/memcmp64.test
>> b/compiler-rt/test/fuzzer/memcmp64.test
>> index 24d14bf73bbf..fc9d02324373 100644
>> --- a/compiler-rt/test/fuzzer/memcmp64.test
>> +++ b/compiler-rt/test/fuzzer/memcmp64.test
>> @@ -1,4 +1,8 @@
>>  UNSUPPORTED: freebsd
>>  RUN: %cpp_compiler %S/Memcmp64BytesTest.cpp -o %t-Memcmp64BytesTest
>>  RUN: not %run %t-Memcmp64BytesTest        -seed=1 -runs=1000000   2>&1 |
>> FileCheck %s
>> +
>> +RUN: %cpp_compiler -fno-sanitize=address -fno-builtin-memcmp
>> %S/Memcmp64BytesTest.cpp -o %t-NoAsanMemcmp64BytesTest
>> +RUN: not %run %t-Memcmp64BytesTest        -seed=1 -runs=1000000   2>&1 |
>> FileCheck %s
>> +
>>  CHECK: BINGO
>>
>> diff  --git a/compiler-rt/test/fuzzer/strcmp.test
>> b/compiler-rt/test/fuzzer/strcmp.test
>> index bd917bba6b69..eebcf8ef5c70 100644
>> --- a/compiler-rt/test/fuzzer/strcmp.test
>> +++ b/compiler-rt/test/fuzzer/strcmp.test
>> @@ -1,5 +1,8 @@
>>  UNSUPPORTED: freebsd
>>  RUN: %cpp_compiler %S/StrcmpTest.cpp -o %t-StrcmpTest
>>  RUN: not %run %t-StrcmpTest               -seed=1 -runs=2000000   2>&1 |
>> FileCheck %s
>> -CHECK: BINGO
>>
>> +RUN: %cpp_compiler -fno-sanitize=address -fno-builtin-strcmp
>> %S/StrcmpTest.cpp -o %t-NoAsanStrcmpTest
>> +RUN: not %run %t-StrcmpTest               -seed=1 -runs=2000000   2>&1 |
>> FileCheck %s
>> +
>> +CHECK: BINGO
>>
>> diff  --git a/compiler-rt/test/fuzzer/strncmp.test
>> b/compiler-rt/test/fuzzer/strncmp.test
>> index 50189445b102..f8ff9299a1d9 100644
>> --- a/compiler-rt/test/fuzzer/strncmp.test
>> +++ b/compiler-rt/test/fuzzer/strncmp.test
>> @@ -1,5 +1,8 @@
>>  UNSUPPORTED: freebsd
>>  RUN: %cpp_compiler %S/StrncmpTest.cpp -o %t-StrncmpTest
>>  RUN: not %run %t-StrncmpTest              -seed=2 -runs=10000000   2>&1
>> | FileCheck %s
>> -CHECK: BINGO
>>
>> +RUN: %cpp_compiler -fno-sanitize=address -fno-builtin-strncmp
>> %S/StrncmpTest.cpp -o %t-NoAsanStrncmpTest
>> +RUN: not %run %t-StrncmpTest              -seed=2 -runs=10000000   2>&1
>> | FileCheck %s
>> +
>> +CHECK: BINGO
>>
>> diff  --git a/compiler-rt/test/fuzzer/strstr.test
>> b/compiler-rt/test/fuzzer/strstr.test
>> index f1fb210b47c7..54a5abe8a414 100644
>> --- a/compiler-rt/test/fuzzer/strstr.test
>> +++ b/compiler-rt/test/fuzzer/strstr.test
>> @@ -1,5 +1,8 @@
>>  UNSUPPORTED: freebsd
>>  RUN: %cpp_compiler %S/StrstrTest.cpp -o %t-StrstrTest
>>  RUN: not %run %t-StrstrTest               -seed=1 -runs=2000000   2>&1 |
>> FileCheck %s
>> -CHECK: BINGO
>>
>> +RUN: %cpp_compiler -fno-sanitize=address -fno-builtin-strstr
>> %S/StrstrTest.cpp -o %t-NoAsanStrstrTest
>> +RUN: not %run %t-StrstrTest               -seed=1 -runs=2000000   2>&1 |
>> FileCheck %s
>> +
>> +CHECK: BINGO
>>
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200717/5741615a/attachment.html>


More information about the llvm-commits mailing list