Skip to content

Commit 3a08730

Browse files
cube0x8domenukk
andauthored
Fixed infinite loop on SyncDiskStage (#2193)
* Fixed infinite loop on SyncDiskStage * cargo fmt * added debug messages * Add left to sync to metadata. Replace HashSet with Vec * added check on state metadata to not crash in case it's None (start fuzzing without files to sync) * fmt & clippy --------- Co-authored-by: Dominik Maier <[email protected]>
1 parent 6040133 commit 3a08730

File tree

1 file changed

+53
-20
lines changed

1 file changed

+53
-20
lines changed

libafl/src/stages/sync.rs

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
fs,
77
path::{Path, PathBuf},
88
time::SystemTime,
9+
vec::Vec,
910
};
1011

1112
use libafl_bolts::{current_time, shmem::ShMemProvider, Named};
@@ -33,15 +34,20 @@ use crate::{
3334
pub struct SyncFromDiskMetadata {
3435
/// The last time the sync was done
3536
pub last_time: SystemTime,
37+
/// The paths that are left to sync
38+
pub left_to_sync: Vec<PathBuf>,
3639
}
3740

3841
libafl_bolts::impl_serdeany!(SyncFromDiskMetadata);
3942

4043
impl SyncFromDiskMetadata {
4144
/// Create a new [`struct@SyncFromDiskMetadata`]
4245
#[must_use]
43-
pub fn new(last_time: SystemTime) -> Self {
44-
Self { last_time }
46+
pub fn new(last_time: SystemTime, left_to_sync: Vec<PathBuf>) -> Self {
47+
Self {
48+
last_time,
49+
left_to_sync,
50+
}
4551
}
4652
}
4753

@@ -89,24 +95,53 @@ where
8995
state: &mut Z::State,
9096
manager: &mut EM,
9197
) -> Result<(), Error> {
98+
log::debug!("Syncing from disk: {:?}", self.sync_dir);
9299
let last = state
93100
.metadata_map()
94101
.get::<SyncFromDiskMetadata>()
95102
.map(|m| m.last_time);
96-
let path = self.sync_dir.clone();
97-
if let Some(max_time) =
98-
self.load_from_directory(&path, &last, fuzzer, executor, state, manager)?
99-
{
103+
104+
if let (Some(max_time), mut new_files) = self.load_from_directory(&last)? {
100105
if last.is_none() {
101106
state
102107
.metadata_map_mut()
103-
.insert(SyncFromDiskMetadata::new(max_time));
108+
.insert(SyncFromDiskMetadata::new(max_time, new_files));
104109
} else {
105110
state
106111
.metadata_map_mut()
107112
.get_mut::<SyncFromDiskMetadata>()
108113
.unwrap()
109114
.last_time = max_time;
115+
state
116+
.metadata_map_mut()
117+
.get_mut::<SyncFromDiskMetadata>()
118+
.unwrap()
119+
.left_to_sync
120+
.append(&mut new_files);
121+
}
122+
}
123+
124+
if let Some(sync_from_disk_metadata) =
125+
state.metadata_map_mut().get_mut::<SyncFromDiskMetadata>()
126+
{
127+
// Iterate over the paths of files left to sync.
128+
// By keeping track of these files, we ensure that no file is missed during synchronization,
129+
// even in the event of a target restart.
130+
let to_sync = sync_from_disk_metadata.left_to_sync.clone();
131+
log::debug!("Number of files to sync: {:?}", to_sync.len());
132+
for path in to_sync {
133+
let input = (self.load_callback)(fuzzer, state, &path)?;
134+
// Removing each path from the `left_to_sync` Vec before evaluating
135+
// prevents duplicate processing and ensures that each file is evaluated only once. This approach helps
136+
// avoid potential infinite loops that may occur if a file is an objective.
137+
state
138+
.metadata_map_mut()
139+
.get_mut::<SyncFromDiskMetadata>()
140+
.unwrap()
141+
.left_to_sync
142+
.retain(|p| p != &path);
143+
log::debug!("Evaluating: {:?}", path);
144+
fuzzer.evaluate_input(state, executor, manager, input)?;
110145
}
111146
}
112147

@@ -149,15 +184,13 @@ where
149184
}
150185

151186
fn load_from_directory(
152-
&mut self,
153-
in_dir: &Path,
187+
&self,
154188
last: &Option<SystemTime>,
155-
fuzzer: &mut Z,
156-
executor: &mut E,
157-
state: &mut Z::State,
158-
manager: &mut EM,
159-
) -> Result<Option<SystemTime>, Error> {
189+
) -> Result<(Option<SystemTime>, Vec<PathBuf>), Error> {
160190
let mut max_time = None;
191+
let mut left_to_sync = Vec::<PathBuf>::new();
192+
let in_dir = self.sync_dir.clone();
193+
161194
for entry in fs::read_dir(in_dir)? {
162195
let entry = entry?;
163196
let path = entry.path();
@@ -172,24 +205,24 @@ where
172205
if attr.is_file() && attr.len() > 0 {
173206
if let Ok(time) = attr.modified() {
174207
if let Some(l) = last {
175-
if time.duration_since(*l).is_err() {
208+
if time.duration_since(*l).is_err() || time == *l {
176209
continue;
177210
}
178211
}
179212
max_time = Some(max_time.map_or(time, |t: SystemTime| t.max(time)));
180-
let input = (self.load_callback)(fuzzer, state, &path)?;
181-
fuzzer.evaluate_input(state, executor, manager, input)?;
213+
log::info!("Syncing file: {:?}", path);
214+
left_to_sync.push(path.clone());
182215
}
183216
} else if attr.is_dir() {
184-
let dir_max_time =
185-
self.load_from_directory(&path, last, fuzzer, executor, state, manager)?;
217+
let (dir_max_time, dir_left_to_sync) = self.load_from_directory(last)?;
186218
if let Some(time) = dir_max_time {
187219
max_time = Some(max_time.map_or(time, |t: SystemTime| t.max(time)));
188220
}
221+
left_to_sync.extend(dir_left_to_sync);
189222
}
190223
}
191224

192-
Ok(max_time)
225+
Ok((max_time, left_to_sync))
193226
}
194227
}
195228

0 commit comments

Comments
 (0)