Compare commits

1 Commits

Author SHA1 Message Date
alnyan 93a0584605 fuzzy: simple syscall fuzzing tool 2025-08-08 03:47:43 +03:00
7 changed files with 205 additions and 1 deletions
+1 -1
View File
@@ -243,7 +243,7 @@ fn validate_user_align_size(addr: usize, layout: &Layout) -> Result<(), Error> {
return Err(Error::InvalidArgument);
}
if addr + layout.size() > KERNEL_VIRT_OFFSET {
todo!();
return Err(Error::InvalidArgument);
}
Ok(())
+2
View File
@@ -75,8 +75,10 @@ cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
extern crate ygg_driver_net_igbe;
} else if #[cfg(target_arch = "aarch64")] {
extern crate ygg_driver_bsp_arm;
extern crate ygg_driver_bsp_bcm283x;
} else if #[cfg(target_arch = "riscv64")] {
extern crate ygg_driver_bsp_riscv;
extern crate ygg_driver_bsp_jh7110;
extern crate ygg_driver_net_stmmac;
+24
View File
@@ -901,6 +901,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "elf"
version = "0.7.4"
@@ -1089,6 +1095,15 @@ dependencies = [
"slab",
]
[[package]]
name = "fuzzy"
version = "0.1.0"
dependencies = [
"itertools",
"rand",
"runtime",
]
[[package]]
name = "generic-array"
version = "0.14.7"
@@ -1410,6 +1425,15 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.15"
+1
View File
@@ -17,6 +17,7 @@ members = [
"netutils",
"sysutils",
"tools/crypt",
"tools/fuzzy",
"tools/init",
"tools/md2txt",
"tools/ntpc",
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "fuzzy"
version = "0.1.0"
edition = "2021"
[dependencies]
itertools = "0.14.0"
rand.workspace = true
runtime.workspace = true
[lints]
workspace = true
+164
View File
@@ -0,0 +1,164 @@
#![feature(rustc_private)]
use itertools::Itertools;
use rand::Rng;
use runtime::abi::SyscallFunction;
enum Argument {
Fd,
OptionFd,
Path,
AccessMode,
BytesRef,
BytesMut,
FileSize,
Enum(usize),
Number(usize, usize),
}
struct Definition {
name: &'static str,
number: usize,
args: &'static [Argument],
}
const fn syscall(
func: SyscallFunction,
name: &'static str,
args: &'static [Argument],
) -> Definition {
Definition {
name,
number: func as _,
args,
}
}
const DEFS: &[Definition] = const {
use Argument::*;
&[
// syscall get_random(buffer: &mut [u8]);
syscall(SyscallFunction::GetRandom, "get_random", &[BytesMut]),
// syscall get_clock(clock: ClockType, out: &mut MaybeUninit<SystemTime>) -> Result<()>;
// syscall set_clock(clock: ClockType, value: &SystemTime) -> Result<()>;
// syscall mount(opts: &MountOptions<'_>) -> Result<()>;
// syscall unmount(opts: &UnmountOptions) -> Result<()>;
// syscall load_module(path: &str) -> Result<()>;
// syscall filesystem_control(fd: Option<RawFd>, option: u32, value: &mut [u8], len: usize) -> Result<usize>;
// syscall get_system_info(option: u32, value: &mut [u8]) -> Result<usize>;
// syscall open(at: Option<RawFd>, path: &str, opts: OpenOptions, mode: FileMode) -> Result<RawFd>;
syscall(SyscallFunction::Open, "open", &[OptionFd, Path, AccessMode]),
// syscall check_access(at: Option<RawFd>, path: &str, access: AccessMode) -> Result<()>;
syscall(
SyscallFunction::CheckAccess,
"check_access",
&[OptionFd, Path, AccessMode],
),
// syscall close(fd: RawFd) -> Result<()>;
syscall(SyscallFunction::Close, "close", &[Fd]),
// syscall write(fd: RawFd, data: &[u8]) -> Result<usize>;
syscall(SyscallFunction::Write, "write", &[Fd, BytesRef]),
// syscall read(fd: RawFd, data: &mut [u8]) -> Result<usize>;
syscall(SyscallFunction::Read, "read", &[Fd, BytesMut]),
// syscall seek(fd: RawFd, pos: SeekFrom, output: &mut u64) -> Result<()>; TODO
// syscall truncate(fd: RawFd, size: u64) -> Result<()>;
syscall(SyscallFunction::Truncate, "truncate", &[Fd, FileSize]),
// syscall fsync(fd: RawFd, what: FileSync) -> Result<()>;
// syscall(SyscallFunction::Fsync, "fsync", &[Fd, Enum(123)]), TODO not implemented
// syscall read_at(fd: RawFd, pos: u64, data: &mut [u8]) -> Result<usize>;
syscall(
SyscallFunction::ReadAt,
"read_at",
&[Fd, FileSize, BytesMut],
),
// syscall write_at(fd: RawFd, pos: u64, data: &[u8]) -> Result<usize>;
syscall(
SyscallFunction::WriteAt,
"write_at",
&[Fd, FileSize, BytesRef],
),
// syscall get_file_option(fd: RawFd, option: u32, data: &mut [u8]) -> Result<usize>;
syscall(
SyscallFunction::GetFileOption,
"get_file_option",
&[Fd, Number(usize::MIN, usize::MAX), BytesMut],
),
// syscall set_file_option(fd: RawFd, option: u32, data: &[u8]) -> Result<()>;
syscall(
SyscallFunction::SetFileOption,
"set_file_option",
&[Fd, Number(usize::MIN, usize::MAX), BytesRef],
),
]
};
fn generate_argument_variants(arg: &Argument) -> Vec<Vec<usize>> {
match arg {
Argument::Path | Argument::BytesRef => {
vec![vec![0, 0], vec![0, 123], vec![0xFFFFFF8012345678, 123]]
}
Argument::BytesMut => {
vec![
vec![0, 0],
vec![0, 123],
vec![0xFFFFFF8012345678, 123],
vec!["abcdef".as_ptr().addr(), 123],
]
}
Argument::OptionFd | Argument::Fd => {
vec![vec![1234], vec![usize::MAX]]
}
Argument::AccessMode => {
vec![vec![0], vec![usize::MAX]]
}
Argument::FileSize => {
vec![vec![usize::MAX]]
}
&Argument::Enum(lower_bound) => {
vec![vec![lower_bound + 1], vec![usize::MAX]]
}
&Argument::Number(a, b) => (0..100)
.map(|_| rand::thread_rng().gen_range(a..b))
.map(|a| vec![a])
.collect(),
}
}
fn fuzz(def: &Definition) {
let argument_variants = def
.args
.iter()
.map(generate_argument_variants)
.multi_cartesian_product()
.map(|combo| combo.into_iter().flatten());
for variant in argument_variants {
let variant = variant.collect::<Vec<_>>();
println!("{}: {:x?}", def.name, variant);
let result = unsafe {
match variant.len() {
1 => runtime::rt::syscall!(def.number, variant[0]),
2 => runtime::rt::syscall!(def.number, variant[0], variant[1]),
3 => runtime::rt::syscall!(def.number, variant[0], variant[1], variant[2]),
4 => runtime::rt::syscall!(
def.number, variant[0], variant[1], variant[2], variant[3]
),
5 => runtime::rt::syscall!(
def.number, variant[0], variant[1], variant[2], variant[3], variant[4]
),
_ => unimplemented!(),
}
};
println!(" -> {:#x} ({})", result, result as isize);
}
}
fn main() {
for def in DEFS {
fuzz(def);
}
}
+1
View File
@@ -81,6 +81,7 @@ const PROGRAMS: &[(&str, &str)] = &[
// crypt
("crypt", "bin/crypt"),
("dyn-loader", "libexec/dyn-loader"),
("fuzzy", "sbin/fuzzy"),
// TODO: proper process for C program builds
];