From: Kostya Serebryany Date: Thu, 30 Jul 2015 21:22:22 +0000 (+0000) Subject: [libFuzzer] fix the strncmp interceptor -- it should respect short strings. X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=dd6dcb6cee3ceee34522020632738e3322fb6b50 [libFuzzer] fix the strncmp interceptor -- it should respect short strings. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243691 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Fuzzer/FuzzerTraceState.cpp b/lib/Fuzzer/FuzzerTraceState.cpp index d4ccd81d21b..637030cb16f 100644 --- a/lib/Fuzzer/FuzzerTraceState.cpp +++ b/lib/Fuzzer/FuzzerTraceState.cpp @@ -366,6 +366,12 @@ void Fuzzer::InitializeTraceState() { } } +static size_t InternalStrnlen(const char *S, size_t MaxLen) { + size_t Len = 0; + for (; Len < MaxLen && S[Len]; Len++) {} + return Len; +} + } // namespace fuzzer using fuzzer::TS; @@ -399,7 +405,17 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, dfsan_label n_label) { - dfsan_weak_hook_memcmp(caller_pc, s1, s2, n, s1_label, s2_label, n_label); + if (!TS) return; + uintptr_t PC = reinterpret_cast(caller_pc); + uint64_t S1 = 0, S2 = 0; + n = std::min(n, fuzzer::InternalStrnlen(s1, n)); + n = std::min(n, fuzzer::InternalStrnlen(s2, n)); + // Simplification: handle only first 8 bytes. + memcpy(&S1, s1, std::min(n, sizeof(S1))); + memcpy(&S2, s2, std::min(n, sizeof(S2))); + dfsan_label L1 = dfsan_read_label(s1, n); + dfsan_label L2 = dfsan_read_label(s2, n); + TS->DFSanCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2, L1, L2); } void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, @@ -415,7 +431,15 @@ void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2, size_t n) { - __sanitizer_weak_hook_memcmp(caller_pc, s1, s2, n); + if (!TS) return; + uintptr_t PC = reinterpret_cast(caller_pc); + uint64_t S1 = 0, S2 = 0; + n = std::min(n, fuzzer::InternalStrnlen(s1, n)); + n = std::min(n, fuzzer::InternalStrnlen(s2, n)); + // Simplification: handle only first 8 bytes. + memcpy(&S1, s1, std::min(n, sizeof(S1))); + memcpy(&S2, s2, std::min(n, sizeof(S2))); + TS->TraceCmpCallback(PC, n, fuzzer::ICMP_EQ, S1, S2); } void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, diff --git a/lib/Fuzzer/test/StrncmpTest.cpp b/lib/Fuzzer/test/StrncmpTest.cpp index 86b02d091a6..187a2fd66ba 100644 --- a/lib/Fuzzer/test/StrncmpTest.cpp +++ b/lib/Fuzzer/test/StrncmpTest.cpp @@ -4,9 +4,13 @@ #include #include +static volatile int sink; + extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { // TODO: check other sizes. char *S = (char*)Data; + if (Size >= 8 && strncmp(S, "123", 8)) + sink = 1; if (Size >= 8 && strncmp(S, "01234567", 8) == 0) { if (Size >= 12 && strncmp(S + 8, "ABCD", 4) == 0) { if (Size >= 14 && strncmp(S + 12, "XY", 2) == 0) { diff --git a/lib/Fuzzer/test/fuzzer-dfsan.test b/lib/Fuzzer/test/fuzzer-dfsan.test index 5e41a9e2ba7..37015ef5b78 100644 --- a/lib/Fuzzer/test/fuzzer-dfsan.test +++ b/lib/Fuzzer/test/fuzzer-dfsan.test @@ -7,5 +7,5 @@ RUN: LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=100 -timeout=5 - RUN: not LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=1000 -timeout=5 2>&1 | FileCheck %s RUN: LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback -RUN: not LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=1000 -timeout=5 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s RUN: LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback