diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 0463ebd0f2d3bebed1978430d857d79e84b629d4..76932f05ff40f07215ad855b129df2633f3c4aea 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -20,3 +20,10 @@ path = "fuzz_targets/fuzz_target_1.rs" test = false doc = false bench = false + +[[bin]] +name = "fuse_1" +path = "fuzz_targets/fuse_1.rs" +test = false +doc = false +bench = false diff --git a/fuzz/fuzz_targets/fuse_1.rs b/fuzz/fuzz_targets/fuse_1.rs new file mode 100644 index 0000000000000000000000000000000000000000..8ac147afd6c009fe752509b28e3ad5758ab7a613 --- /dev/null +++ b/fuzz/fuzz_targets/fuse_1.rs @@ -0,0 +1,170 @@ +#![no_main] + +use std::collections::HashMap; +use std::ops::DerefMut; +use std::path::{Component, Path, PathBuf}; +use std::process::Command; +use std::{fs, sync, thread, time}; + +use redoxfs::{unmount_path, DiskSparse, FileSystem}; + +use libfuzzer_sys::fuzz_target; +use libfuzzer_sys::arbitrary; +use libfuzzer_sys::arbitrary::Arbitrary; + +#[derive(Arbitrary, Debug, Clone)] +enum FilesystemAction { + CreateFile { + path: String, + contents: String, + }, + WriteFile { + index: u32, + contents: String, + }, + ReadFile { // and verify + index: u32, + }, + DeleteFile { + index: u32 + }, + + + //read/delete/rename file that doesn't exist +} +// VERY slow +fuzz_target!(|actions: Vec<FilesystemAction>| { + with_redoxfs(move |real_path| { + let mut paths = vec![]; + let mut hashmap = HashMap::new(); + for action in &actions { + match action { + FilesystemAction::CreateFile { path, contents } => { + if path.is_empty() { + continue; + } + if path.len() >= 252 { + continue; + } + if PathBuf::from(path).components().any(| x | x == Component::ParentDir) { + continue; + } + if !path.is_ascii() || path.contains(| ch: char | !ch.is_alphanumeric() ) { // || path.contains(&['\0', '\n', '\t']) + continue; + } + + if contents.contains('\0') { + continue; + } + let path = real_path.join(path); + if paths.contains(&path) { + continue; + } + + fs::write(&path, contents).unwrap(); + hashmap.insert(path.clone(), contents); + paths.push(path); + }, + FilesystemAction::WriteFile { index, contents } => { + if paths.len() == 0 { + continue; + } + if contents.contains('\0') { + continue; + } + + + let path = &paths[*index as usize % paths.len()]; + hashmap.insert(path.clone(), contents); + fs::write(path, contents).unwrap(); + + }, + FilesystemAction::ReadFile { index } => { + if paths.len() == 0 { + continue; + } + + let path = &paths[*index as usize % paths.len()]; + let contets = fs::read_to_string(path).unwrap(); + let real_contets = hashmap.get(path).unwrap().to_string(); + + assert_eq!(contets, real_contets); + + }, + FilesystemAction::DeleteFile { index } => { + if paths.len() == 0 { + continue; + } + + let path = &paths[*index as usize % paths.len()].clone(); + paths.remove(*index as usize % paths.len()); + fs::remove_file(path).unwrap(); + hashmap.remove(path); + }, + //_ => () + } + } + }) +}); + + +fn with_redoxfs<T, F>(callback: F) -> T +where + T: Send + Sync + 'static, + F: FnMut(&Path) -> T + Send + Sync + 'static, +{ + let disk_path = "/tmp/fuzzer-image.img"; + let mount_path = "/tmp/image"; + + let res = { + let disk = DiskSparse::create(disk_path, 1024 * 1024 * 5).unwrap(); + + if cfg!(not(target_os = "redox")) { + if !Path::new(mount_path).exists() { + (fs::create_dir(mount_path)).unwrap(); + } + } + + let ctime = (time::SystemTime::now().duration_since(time::UNIX_EPOCH)).unwrap(); + let fs = FileSystem::create(disk, None, ctime.as_secs(), ctime.subsec_nanos()).unwrap(); + + let callback_mutex = sync::Arc::new(sync::Mutex::new(callback)); + let join_handle = redoxfs::mount(fs, mount_path, move |real_path| { + let callback_mutex = callback_mutex.clone(); + let real_path = real_path.to_owned(); + thread::spawn(move || { + let res = { + let mut callback_guard = callback_mutex.lock().unwrap(); + let callback = callback_guard.deref_mut(); + callback(&real_path) + }; + + if cfg!(target_os = "redox") { + fs::remove_file(format!(":{}", mount_path)).unwrap(); + } else { + while !(Command::new("sync").status()).unwrap().success() { + + } + + while !unmount_path(mount_path).is_ok() { + + } + } + + res + }) + }) + .unwrap(); + + join_handle.join().unwrap() + }; + + fs::remove_file(disk_path).unwrap(); + + if cfg!(not(target_os = "redox")) { + fs::remove_dir(mount_path).unwrap(); + } + + res +} + diff --git a/fuzz/fuzz_targets/fuzz_target_1.rs b/fuzz/fuzz_targets/fuzz_target_1.rs index bbe2fab36ab807e234ca81e64300bbe1ffbf7cbc..28105318733fc39d99bd1c09105265de64c59c46 100644 --- a/fuzz/fuzz_targets/fuzz_target_1.rs +++ b/fuzz/fuzz_targets/fuzz_target_1.rs @@ -46,6 +46,9 @@ impl FilesystemAction { if !path.is_ascii() || path.contains(| ch: char | !ch.is_alphanumeric() ) { // || path.contains(&['\0', '\n', '\t']) return Ok(None); } + if path.len() >= 252 { + return Ok(None); + } if contents.contains('\0') { return Ok(None); @@ -55,6 +58,9 @@ impl FilesystemAction { if path.file_name().is_none() { return Ok(None); } + if paths.contains(&path) { + return Ok(None) + } paths.push(path); @@ -68,7 +74,7 @@ impl FilesystemAction { &data, metadata.mtime, metadata.mtime_nsec, - )?; + ).unwrap(); if count != data.len() { panic!("file write count {} != {}", count, data.len()); @@ -94,7 +100,7 @@ impl FilesystemAction { }.to_str().unwrap(); let mut children = vec![]; - tx.child_nodes(TreePtr::root(), &mut children)?; + tx.child_nodes(TreePtr::root(), &mut children).unwrap(); let child = children.into_iter().find(| x | x.name().unwrap() == name).unwrap(); @@ -106,7 +112,7 @@ impl FilesystemAction { &data, metadata.mtime, metadata.mtime_nsec, - )?; + ).unwrap(); if count != data.len() { panic!("file write count {} != {}", count, data.len()); @@ -142,16 +148,16 @@ impl FilesystemAction { }.to_str().unwrap(); let mut children = vec![]; - tx.child_nodes(TreePtr::root(), &mut children)?; + tx.child_nodes(TreePtr::root(), &mut children).unwrap(); let child = children.into_iter().find(| x | x.name().unwrap() == name).unwrap(); let mut buffer: [u8; 1024] = [0; 1024]; - tx.read_node(child.node_ptr(), 0, &mut buffer, 0, 0)?; + tx.read_node(child.node_ptr(), 0, &mut buffer, 0, 0).unwrap(); /*let string = match String::from_utf8(buffer.to_vec()) { Ok(s) => s, - Err(e) => panic!("Contents are wrong {e:?}"), + Err(e) => panic!("Contents are wrong error: {e:?}"), };*/ // TODO: Validate }, @@ -180,6 +186,7 @@ impl FilesystemAction { libfuzzer_sys::fuzz_target!(|actions: Vec<FilesystemAction>| { + //panic!("{actions:#?}"); let disk_path = "/tmp/redox_fuzzer.img"; let _ = fs::remove_file(disk_path);