blob: 1b77f172bf0681b2480cf78a2bcb3b1ede42b3fe [file] [log] [blame]
Kostya Serebryany22526252015-05-11 21:16:27 +00001//===- FuzzerTraceState.cpp - Trace-based fuzzer mutator ------------------===//
Kostya Serebryany16d03bd2015-03-30 22:09:51 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Kostya Serebryany4820cc92016-10-04 06:08:46 +00009// Data tracing.
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000010//===----------------------------------------------------------------------===//
11
Kostya Serebryany6f5a8042016-09-21 01:50:50 +000012#include "FuzzerDictionary.h"
Zachary Turner24a148b2016-11-30 19:06:14 +000013#include "FuzzerInternal.h"
14#include "FuzzerIO.h"
Kostya Serebryany6f5a8042016-09-21 01:50:50 +000015#include "FuzzerMutate.h"
Kostya Serebryanyab73c692016-09-23 00:46:18 +000016#include "FuzzerTracePC.h"
Kostya Serebryanybeb24c32015-05-07 21:02:11 +000017#include <algorithm>
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000018#include <cstring>
Kostya Serebryany859e86d2016-01-12 02:08:37 +000019#include <map>
Kostya Serebryanyc135b552016-07-15 23:27:19 +000020#include <set>
Zachary Turner24a148b2016-11-30 19:06:14 +000021#include <thread>
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000022
Kostya Serebryany5a99ecb2015-05-11 20:51:19 +000023namespace fuzzer {
24
Kostya Serebryanyae5b9562016-01-15 06:24:05 +000025// Declared as static globals for faster checks inside the hooks.
Kostya Serebryanyc135b552016-07-15 23:27:19 +000026static bool RecordingMemmem = false;
Kostya Serebryany6b08be92016-07-19 18:29:06 +000027static bool DoingMyOwnMemmem = false;
28
Kostya Serebryanya5f94fb2016-10-14 20:20:33 +000029ScopedDoingMyOwnMemmem::ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
30ScopedDoingMyOwnMemmem::~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
Kostya Serebryanyae5b9562016-01-15 06:24:05 +000031
Kostya Serebryany22526252015-05-11 21:16:27 +000032class TraceState {
Mike Aizatskyf0b3e852016-06-23 20:44:48 +000033public:
34 TraceState(MutationDispatcher &MD, const FuzzingOptions &Options,
Richard Smithb62e7e32016-05-27 21:05:35 +000035 const Fuzzer *F)
Kostya Serebryanyf26017b2016-05-26 21:32:30 +000036 : MD(MD), Options(Options), F(F) {}
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000037
Kostya Serebryanybeb24c32015-05-07 21:02:11 +000038 void StartTraceRecording() {
Kostya Serebryanybb911702017-01-18 01:10:18 +000039 if (!Options.UseMemmem)
Kostya Serebryanyf26017b2016-05-26 21:32:30 +000040 return;
Kostya Serebryanybb911702017-01-18 01:10:18 +000041 RecordingMemmem = true;
Kostya Serebryanyc135b552016-07-15 23:27:19 +000042 InterestingWords.clear();
Kostya Serebryany7ec0c562016-02-13 03:25:16 +000043 MD.ClearAutoDictionary();
Kostya Serebryanybeb24c32015-05-07 21:02:11 +000044 }
45
Kostya Serebryanyb65805a2016-01-09 03:08:58 +000046 void StopTraceRecording() {
Kostya Serebryanybb911702017-01-18 01:10:18 +000047 if (!RecordingMemmem)
Mike Aizatskyf0b3e852016-06-23 20:44:48 +000048 return;
Kostya Serebryanyc135b552016-07-15 23:27:19 +000049 for (auto &W : InterestingWords)
50 MD.AddWordToAutoDictionary({W});
Kostya Serebryanybeb24c32015-05-07 21:02:11 +000051 }
52
Kostya Serebryanyc135b552016-07-15 23:27:19 +000053 void AddInterestingWord(const uint8_t *Data, size_t Size) {
54 if (!RecordingMemmem || !F->InFuzzingThread()) return;
55 if (Size <= 1) return;
56 Size = std::min(Size, Word::GetMaxSize());
57 Word W(Data, Size);
58 InterestingWords.insert(W);
59 }
60
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000061 private:
Kostya Serebryanyd88d1302016-02-02 23:17:45 +000062
Kostya Serebryanyc135b552016-07-15 23:27:19 +000063 // TODO: std::set is too inefficient, need to have a custom DS here.
64 std::set<Word> InterestingWords;
Kostya Serebryany7ec0c562016-02-13 03:25:16 +000065 MutationDispatcher &MD;
Mike Aizatskyf0b3e852016-06-23 20:44:48 +000066 const FuzzingOptions Options;
Kostya Serebryanyf26017b2016-05-26 21:32:30 +000067 const Fuzzer *F;
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000068};
69
Kostya Serebryany22526252015-05-11 21:16:27 +000070static TraceState *TS;
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000071
Kostya Serebryanybeb24c32015-05-07 21:02:11 +000072void Fuzzer::StartTraceRecording() {
Kostya Serebryany22526252015-05-11 21:16:27 +000073 if (!TS) return;
74 TS->StartTraceRecording();
Kostya Serebryanybeb24c32015-05-07 21:02:11 +000075}
76
Kostya Serebryanyb65805a2016-01-09 03:08:58 +000077void Fuzzer::StopTraceRecording() {
78 if (!TS) return;
79 TS->StopTraceRecording();
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000080}
81
Kostya Serebryany22526252015-05-11 21:16:27 +000082void Fuzzer::InitializeTraceState() {
Kostya Serebryanybb911702017-01-18 01:10:18 +000083 if (!Options.UseMemmem) return;
Kostya Serebryanyf26017b2016-05-26 21:32:30 +000084 TS = new TraceState(MD, Options, this);
Kostya Serebryany16d03bd2015-03-30 22:09:51 +000085}
86
Kostya Serebryanyc9dc96b2015-07-30 21:22:22 +000087static size_t InternalStrnlen(const char *S, size_t MaxLen) {
88 size_t Len = 0;
89 for (; Len < MaxLen && S[Len]; Len++) {}
90 return Len;
91}
92
Kostya Serebryanyc58982d2017-03-24 22:19:52 +000093// Finds min of (strlen(S1), strlen(S2)).
94// Needed bacause one of these strings may actually be non-zero terminated.
95static size_t InternalStrnlen2(const char *S1, const char *S2) {
96 size_t Len = 0;
97 for (; S1[Len] && S2[Len]; Len++) {}
98 return Len;
99}
100
Kostya Serebryany16d03bd2015-03-30 22:09:51 +0000101} // namespace fuzzer
102
Kostya Serebryany22526252015-05-11 21:16:27 +0000103using fuzzer::TS;
Kostya Serebryany5a99ecb2015-05-11 20:51:19 +0000104
Kostya Serebryany16d03bd2015-03-30 22:09:51 +0000105extern "C" {
Kostya Serebryany7f4227d2015-08-05 18:23:01 +0000106
Kostya Serebryany4b83a4f2016-01-12 16:50:18 +0000107// We may need to avoid defining weak hooks to stay compatible with older clang.
108#ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
109# define LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS 1
110#endif
111
112#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
Kostya Serebryany3344f352017-01-17 23:50:21 +0000113
Mike Aizatsky1b658122017-02-03 20:26:44 +0000114ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
Kostya Serebryany0e776a22015-07-30 01:34:58 +0000115void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
Kostya Serebryanye3580952016-01-12 00:43:42 +0000116 const void *s2, size_t n, int result) {
Kostya Serebryanye3580952016-01-12 00:43:42 +0000117 if (result == 0) return; // No reason to mutate.
Kostya Serebryanyc5733162016-01-09 01:39:55 +0000118 if (n <= 1) return; // Not interesting.
Kostya Serebryany1d8c2ce2017-01-17 23:09:05 +0000119 fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/false);
Kostya Serebryanyb74ba422015-07-30 02:33:45 +0000120}
121
Mike Aizatsky1b658122017-02-03 20:26:44 +0000122ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
Kostya Serebryanyb74ba422015-07-30 02:33:45 +0000123void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
Kostya Serebryanye3580952016-01-12 00:43:42 +0000124 const char *s2, size_t n, int result) {
Kostya Serebryanye3580952016-01-12 00:43:42 +0000125 if (result == 0) return; // No reason to mutate.
Kostya Serebryanycd6a4662015-07-31 17:05:05 +0000126 size_t Len1 = fuzzer::InternalStrnlen(s1, n);
127 size_t Len2 = fuzzer::InternalStrnlen(s2, n);
128 n = std::min(n, Len1);
129 n = std::min(n, Len2);
130 if (n <= 1) return; // Not interesting.
Kostya Serebryany1d8c2ce2017-01-17 23:09:05 +0000131 fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n, /*StopAtZero*/true);
Kostya Serebryany0e776a22015-07-30 01:34:58 +0000132}
133
Kostya Serebryany3344f352017-01-17 23:50:21 +0000134
Mike Aizatsky1b658122017-02-03 20:26:44 +0000135ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
Kostya Serebryany7f4227d2015-08-05 18:23:01 +0000136void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
Kostya Serebryanye3580952016-01-12 00:43:42 +0000137 const char *s2, int result) {
Kostya Serebryanye3580952016-01-12 00:43:42 +0000138 if (result == 0) return; // No reason to mutate.
Kostya Serebryanyc58982d2017-03-24 22:19:52 +0000139 size_t N = fuzzer::InternalStrnlen2(s1, s2);
Kostya Serebryany7f4227d2015-08-05 18:23:01 +0000140 if (N <= 1) return; // Not interesting.
Kostya Serebryany1d8c2ce2017-01-17 23:09:05 +0000141 fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, N, /*StopAtZero*/true);
Kostya Serebryany7f4227d2015-08-05 18:23:01 +0000142}
143
Mike Aizatsky1b658122017-02-03 20:26:44 +0000144ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
Kostya Serebryanyc135b552016-07-15 23:27:19 +0000145void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
146 const char *s2, size_t n, int result) {
147 return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
148}
Kostya Serebryany3344f352017-01-17 23:50:21 +0000149
Mike Aizatsky1b658122017-02-03 20:26:44 +0000150ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
Kostya Serebryanyc135b552016-07-15 23:27:19 +0000151void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
152 const char *s2, int result) {
153 return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
154}
Kostya Serebryany3344f352017-01-17 23:50:21 +0000155
Mike Aizatsky1b658122017-02-03 20:26:44 +0000156ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
Kostya Serebryanyc135b552016-07-15 23:27:19 +0000157void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
158 const char *s2, char *result) {
159 TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
160}
Kostya Serebryany3344f352017-01-17 23:50:21 +0000161
Mike Aizatsky1b658122017-02-03 20:26:44 +0000162ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
Kostya Serebryanyc135b552016-07-15 23:27:19 +0000163void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
164 const char *s2, char *result) {
165 TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
166}
Kostya Serebryany3344f352017-01-17 23:50:21 +0000167
Mike Aizatsky1b658122017-02-03 20:26:44 +0000168ATTRIBUTE_INTERFACE ATTRIBUTE_NO_SANITIZE_MEMORY
Kostya Serebryanyc135b552016-07-15 23:27:19 +0000169void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
170 const void *s2, size_t len2, void *result) {
Kostya Serebryany6b08be92016-07-19 18:29:06 +0000171 if (fuzzer::DoingMyOwnMemmem) return;
172 TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), len2);
Kostya Serebryanyc135b552016-07-15 23:27:19 +0000173}
174
Kostya Serebryany4b83a4f2016-01-12 16:50:18 +0000175#endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
Kostya Serebryany16d03bd2015-03-30 22:09:51 +0000176} // extern "C"