From 3478494c1fdcbbee3e22895dcd6e6919d6c05430 Mon Sep 17 00:00:00 2001 From: Matt Morehouse Date: Thu, 9 May 2019 22:48:46 +0000 Subject: [PATCH] [libFuzzer] Unpoison parameters before calling user callback. Summary: Fixes an MSan false positive when compiling with -fsanitize=memory,fuzzer. See https://github.com/google/oss-fuzz/issues/2369 for more details. Reviewers: kcc Reviewed By: kcc Subscribers: llvm-commits, metzman, eugenis Tags: #llvm Differential Revision: https://reviews.llvm.org/D61753 llvm-svn: 360390 --- compiler-rt/lib/fuzzer/FuzzerExtFunctions.def | 1 + compiler-rt/lib/fuzzer/FuzzerLoop.cpp | 4 ++- compiler-rt/test/fuzzer/MsanParamUnpoison.cpp | 28 +++++++++++++++++++ .../test/fuzzer/msan-param-unpoison.test | 5 ++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 compiler-rt/test/fuzzer/MsanParamUnpoison.cpp create mode 100644 compiler-rt/test/fuzzer/msan-param-unpoison.test diff --git a/compiler-rt/lib/fuzzer/FuzzerExtFunctions.def b/compiler-rt/lib/fuzzer/FuzzerExtFunctions.def index 288a59ce39e5..41fa0fd2b748 100644 --- a/compiler-rt/lib/fuzzer/FuzzerExtFunctions.def +++ b/compiler-rt/lib/fuzzer/FuzzerExtFunctions.def @@ -46,3 +46,4 @@ EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false); EXT_FUNC(__msan_scoped_disable_interceptor_checks, void, (), false); EXT_FUNC(__msan_scoped_enable_interceptor_checks, void, (), false); EXT_FUNC(__msan_unpoison, void, (const volatile void *, size_t size), false); +EXT_FUNC(__msan_unpoison_param, void, (size_t n), false); diff --git a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp index d1ad3e37efad..cb3d8214c0c3 100644 --- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp @@ -542,6 +542,8 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { memcpy(DataCopy, Data, Size); if (EF->__msan_unpoison) EF->__msan_unpoison(DataCopy, Size); + if (EF->__msan_unpoison_param) + EF->__msan_unpoison_param(2); if (CurrentUnitData && CurrentUnitData != Data) memcpy(CurrentUnitData, Data, Size); CurrentUnitSize = Size; @@ -702,7 +704,7 @@ void Fuzzer::MutateAndTestOne() { break; // We will mutate this input more in the next rounds. } if (Options.ReduceDepth && !FoundUniqFeatures) - break; + break; } } diff --git a/compiler-rt/test/fuzzer/MsanParamUnpoison.cpp b/compiler-rt/test/fuzzer/MsanParamUnpoison.cpp new file mode 100644 index 000000000000..bcf50804d738 --- /dev/null +++ b/compiler-rt/test/fuzzer/MsanParamUnpoison.cpp @@ -0,0 +1,28 @@ +// 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 + +// Triggers the bug described here: +// https://github.com/google/oss-fuzz/issues/2369#issuecomment-490240627 +// +// In a nutshell, MSan's parameter shadow does not get unpoisoned before calls +// to LLVMFuzzerTestOneInput. This test case causes the parameter shadow to be +// poisoned by the call to foo(), which will trigger an MSan false positive on +// the Size == 0 check if the parameter shadow is still poisoned. +#include +#include +#include +#include + +volatile int zero = 0; +__attribute__((noinline)) int foo(int arg1, int arg2) { return zero; } + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + if (Size == 0) + return 0; + + // Pass uninitialized values to foo(). Since foo doesn't do anything with + // them, MSan should not report an error here. + int a, b; + return foo(a, b); +} diff --git a/compiler-rt/test/fuzzer/msan-param-unpoison.test b/compiler-rt/test/fuzzer/msan-param-unpoison.test new file mode 100644 index 000000000000..f32f8511dd8f --- /dev/null +++ b/compiler-rt/test/fuzzer/msan-param-unpoison.test @@ -0,0 +1,5 @@ +REQUIRES: msan +RUN: %msan_compiler %S/MsanParamUnpoison.cpp -o %t +RUN: %run %t -seed=1 -runs=1000 2>&1 | FileCheck %s + +CHECK-NOT: MemorySanitizer: use-of-uninitialized-value