1use libafl::{
5 events::EventFirer,
6 feedbacks::{Feedback, HasObserverName, IsNovel, MapFeedback, MapFeedbackMetadata, Reducer},
7 inputs::HasTargetBytes,
8 observers::UsesObserver,
9 prelude::{ExitKind, MapObserver, Observer, ObserversTuple, UsesInput},
10 state::{HasCorpus, HasNamedMetadata, State},
11};
12use libafl_bolts::{AsIter, AsSlice, Named};
13use serde::{de::DeserializeOwned, Deserialize, Serialize};
14use std::{
15 fmt::Debug,
16 sync::{mpsc::Sender, OnceLock},
17};
18
19use super::messages::FuzzerMessage;
20
21#[derive(Clone, Debug)]
22pub(crate) struct ReportingMapFeedback<N, O, R, S, T> {
23 base: MapFeedback<N, O, R, S, T>,
25 sender: OnceLock<Sender<FuzzerMessage>>,
27}
28
29impl<N, O, R, S, T> UsesObserver<S> for ReportingMapFeedback<N, O, R, S, T>
30where
31 S: UsesInput,
32 O: Observer<S>,
33{
34 type Observer = O;
35}
36
37impl<N, O, R, S, T> Feedback<S> for ReportingMapFeedback<N, O, R, S, T>
38where
39 N: IsNovel<T>,
40 O: MapObserver<Entry = T> + for<'it> AsIter<'it, Item = T>,
41 R: Reducer<T>,
42 S: State + HasNamedMetadata + HasCorpus,
43 S::Input: HasTargetBytes,
44 T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static,
45{
46 fn is_interesting<EM, OT>(
47 &mut self,
48 state: &mut S,
49 manager: &mut EM,
50 input: &<S>::Input,
51 observers: &OT,
52 exit_kind: &ExitKind,
53 ) -> Result<bool, libafl::Error>
54 where
55 EM: EventFirer<State = S>,
56 OT: ObserversTuple<S>,
57 {
58 let is_interesting = self
59 .base
60 .is_interesting(state, manager, input, observers, exit_kind)?;
61
62 if is_interesting {
63 let observer = observers
64 .match_name::<O>(self.observer_name())
65 .ok_or_else(|| {
66 libafl::Error::unknown("Failed to get observer from observers tuple")
67 })?;
68
69 let map_state = state
70 .named_metadata_map_mut()
71 .get_mut::<MapFeedbackMetadata<T>>(self.name())
72 .ok_or_else(|| libafl::Error::unknown("Failed to get metadata"))?;
73
74 let len = observer.len();
75
76 if map_state.history_map.len() < len {
77 map_state.history_map.resize(len, observer.initial());
78 }
79
80 let history_map = map_state.history_map.as_slice();
81
82 let initial = observer.initial();
83
84 let mut interesting_indices = vec![];
85
86 for (i, item) in observer
87 .as_iter()
88 .copied()
89 .enumerate()
90 .filter(|(_, item)| *item != initial)
91 {
92 let existing = unsafe { *history_map.get_unchecked(i) };
93 let reduced = R::reduce(existing, item);
94 if N::is_novel(existing, reduced) {
95 interesting_indices.push(i);
96 }
97 }
98
99 self.sender
100 .get_mut()
101 .and_then(|sender| {
102 sender
103 .send(FuzzerMessage::Interesting {
104 indices: interesting_indices,
105 input: input.target_bytes().as_slice().to_vec(),
106 })
107 .ok()
108 })
109 .ok_or_else(|| libafl::Error::unknown("Failed to send report"))?;
110 }
111
112 if *exit_kind == ExitKind::Crash {
113 let observer = observers
114 .match_name::<O>(self.observer_name())
115 .ok_or_else(|| {
116 libafl::Error::unknown("Failed to get observer from observers tuple")
117 })?;
118
119 let map_state = state
120 .named_metadata_map_mut()
121 .get_mut::<MapFeedbackMetadata<T>>(self.name())
122 .ok_or_else(|| libafl::Error::unknown("Failed to get metadata"))?;
123
124 let len = observer.len();
125
126 if map_state.history_map.len() < len {
127 map_state.history_map.resize(len, observer.initial());
128 }
129
130 let history_map = map_state.history_map.as_slice();
131
132 let initial = observer.initial();
133
134 let mut indices = vec![];
135
136 for (i, item) in observer
137 .as_iter()
138 .copied()
139 .enumerate()
140 .filter(|(_, item)| *item != initial)
141 {
142 let existing = unsafe { *history_map.get_unchecked(i) };
143 let reduced = R::reduce(existing, item);
144 if N::is_novel(existing, reduced) {
145 indices.push(i);
146 }
147 }
148
149 self.sender
150 .get_mut()
151 .and_then(|sender| {
152 sender
153 .send(FuzzerMessage::Crash {
154 indices,
155 input: input.target_bytes().as_slice().to_vec(),
156 })
157 .ok()
158 })
159 .ok_or_else(|| libafl::Error::unknown("Failed to send report"))?;
160 }
161
162 if *exit_kind == ExitKind::Timeout {
163 let observer = observers
164 .match_name::<O>(self.observer_name())
165 .ok_or_else(|| {
166 libafl::Error::unknown("Failed to get observer from observers tuple")
167 })?;
168
169 let map_state = state
170 .named_metadata_map_mut()
171 .get_mut::<MapFeedbackMetadata<T>>(self.name())
172 .ok_or_else(|| libafl::Error::unknown("Failed to get metadata"))?;
173
174 let len = observer.len();
175
176 if map_state.history_map.len() < len {
177 map_state.history_map.resize(len, observer.initial());
178 }
179
180 let history_map = map_state.history_map.as_slice();
181
182 let initial = observer.initial();
183
184 let mut indices = vec![];
185
186 for (i, item) in observer
187 .as_iter()
188 .copied()
189 .enumerate()
190 .filter(|(_, item)| *item != initial)
191 {
192 let existing = unsafe { *history_map.get_unchecked(i) };
193 let reduced = R::reduce(existing, item);
194 if N::is_novel(existing, reduced) {
195 indices.push(i);
196 }
197 }
198
199 self.sender
200 .get_mut()
201 .and_then(|sender| {
202 sender
203 .send(FuzzerMessage::Timeout {
204 indices,
205 input: input.target_bytes().as_slice().to_vec(),
206 })
207 .ok()
208 })
209 .ok_or_else(|| libafl::Error::unknown("Failed to send report"))?;
210 }
211
212 Ok(is_interesting)
213 }
214
215 fn init_state(&mut self, state: &mut S) -> Result<(), libafl::Error> {
216 self.base.init_state(state)
217 }
218
219 fn append_metadata<EM, OT>(
220 &mut self,
221 state: &mut S,
222 manager: &mut EM,
223 observers: &OT,
224 testcase: &mut libafl::prelude::Testcase<<S>::Input>,
225 ) -> Result<(), libafl::Error>
226 where
227 OT: ObserversTuple<S>,
228 EM: EventFirer<State = S>,
229 {
230 self.base
231 .append_metadata(state, manager, observers, testcase)
232 }
233
234 fn discard_metadata(&mut self, state: &mut S, input: &<S>::Input) -> Result<(), libafl::Error> {
235 self.base.discard_metadata(state, input)
236 }
237}
238
239impl<N, O, R, S, T> Named for ReportingMapFeedback<N, O, R, S, T> {
240 #[inline]
241 fn name(&self) -> &str {
242 self.base.name()
243 }
244}
245
246impl<N, O, R, S, T> HasObserverName for ReportingMapFeedback<N, O, R, S, T>
247where
248 T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
249 R: Reducer<T>,
250 N: IsNovel<T>,
251 O: MapObserver<Entry = T>,
252 for<'it> O: AsIter<'it, Item = T>,
253 S: HasNamedMetadata,
254{
255 #[inline]
256 fn observer_name(&self) -> &str {
257 self.base.observer_name()
258 }
259}
260
261impl<N, O, R, S, T> ReportingMapFeedback<N, O, R, S, T>
262where
263 T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
264 R: Reducer<T>,
265 O: MapObserver<Entry = T>,
266 for<'it> O: AsIter<'it, Item = T>,
267 N: IsNovel<T>,
268 S: UsesInput + HasNamedMetadata,
269{
270 #[must_use]
271 pub fn new(base: MapFeedback<N, O, R, S, T>, sender: Sender<FuzzerMessage>) -> Self {
272 let sender = {
273 let lock = OnceLock::new();
274 lock.set(sender).expect("Failed to set sender");
276 lock
277 };
278 Self { base, sender }
279 }
280}