tsffs/fuzzer/feedbacks/
mod.rs

1// Copyright (C) 2024 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4use 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    /// The base map
24    base: MapFeedback<N, O, R, S, T>,
25    /// A sender to send textual reports to
26    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            // NOTE: This is ok because initializing a just-created lock is infallible
275            lock.set(sender).expect("Failed to set sender");
276            lock
277        };
278        Self { base, sender }
279    }
280}