Skip to content

Commit 824f553

Browse files
authored
Initial FreeBSD x86 (32-bit) support with Frida instrumentation (#3372)
* fix(libafl): add cfg_attr for check in freebsd case * feat(frida): add FreeBSD to cfg's conditions * feat(bolts): add write_crash for freebsd x86 * fix(bolts): convert rss.ru_maxrss to i64 for freebsd x86 * feat(frida): initial commit for freebsd x86 * fix(frida): x86_64 register's size in asan * fix(frida): set 1<<31 as default value for max_total_allocation, needed for 32bit * feat(bolts): add parse_from method for cli * fix(bolts): unaligned msg in freebsd x86 * fix(frida): use u32::MAX limit for ranges in x86 case * chore(bolts): fix typo in minibsod crash message * fix(frida): remove including of failed script.js and use without ext
1 parent 7633382 commit 824f553

File tree

16 files changed

+755
-76
lines changed

16 files changed

+755
-76
lines changed

crates/libafl/src/executors/forkserver.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ impl ConfigTarget for Command {
254254
}
255255
}
256256

257-
#[expect(trivial_numeric_casts)]
257+
// libc::rlim_t is i64 in freebsd and trivial_numeric_casts check will failed
258+
#[cfg_attr(not(target_os = "freebsd"), expect(trivial_numeric_casts))]
258259
fn setlimit(&mut self, memlimit: u64) -> &mut Self {
259260
if memlimit == 0 {
260261
return self;

crates/libafl_bolts/src/cli.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,18 @@ pub struct FuzzerOptions {
225225

226226
/// The maximum total allocation size that the `ASan` allocator should allocate
227227
#[cfg(feature = "frida_cli")]
228-
#[arg(
228+
#[cfg_attr(target_pointer_width = "64", arg(
229229
short = 'M',
230230
long,
231231
default_value = "4294967296", // 1_usize << 32
232232
help_heading = "ASan Options"
233-
)]
233+
))]
234+
#[cfg_attr(target_pointer_width = "32", arg(
235+
short = 'M',
236+
long,
237+
default_value = "2147483648", // 1_usize << 31
238+
help_heading = "ASan Options"
239+
))]
234240
pub max_total_allocation: usize,
235241

236242
/// Instruct `ASan` to panic if the max `ASan` allocation size is exceeded
@@ -382,6 +388,16 @@ pub fn parse_args() -> FuzzerOptions {
382388
FuzzerOptions::parse()
383389
}
384390

391+
/// Needed for targets, which doesn't have `std::env::args_os()` (FreeBSD for example)
392+
#[must_use]
393+
pub fn parse_from<I, T>(itr: I) -> FuzzerOptions
394+
where
395+
I: IntoIterator<Item = T>,
396+
T: Into<std::ffi::OsString> + Clone,
397+
{
398+
FuzzerOptions::parse_from(itr)
399+
}
400+
385401
#[cfg(all(
386402
test,
387403
any(feature = "cli", feature = "qemu_cli", feature = "frida_cli")

crates/libafl_bolts/src/llmp.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,8 +2778,9 @@ where
27782778
size_of::<LlmpClientExitInfo>()
27792779
)));
27802780
}
2781-
let exitinfo = (*msg).buf.as_mut_ptr() as *mut LlmpClientExitInfo;
2782-
let client_id = ClientId((*exitinfo).client_id);
2781+
let exitinfo =
2782+
((*msg).buf.as_mut_ptr() as *mut LlmpClientExitInfo).read_unaligned();
2783+
let client_id = ClientId(exitinfo.client_id);
27832784
log::info!(
27842785
"Client exit message received!, we are removing clients whose client_group_id is {client_id:#?}"
27852786
);
@@ -3191,9 +3192,9 @@ where
31913192
.alloc_next(size_of::<LlmpClientExitInfo>())
31923193
.expect("Could not allocate a new message in shared map.");
31933194
(*msg).tag = LLMP_TAG_CLIENT_EXIT;
3194-
#[expect(clippy::cast_ptr_alignment)]
3195-
let exitinfo = (*msg).buf.as_mut_ptr() as *mut LlmpClientExitInfo;
3196-
(*exitinfo).client_id = client_id;
3195+
let mut exitinfo =
3196+
((*msg).buf.as_mut_ptr() as *mut LlmpClientExitInfo).read_unaligned();
3197+
exitinfo.client_id = client_id;
31973198
sender.send(msg, true)
31983199
}
31993200
}

crates/libafl_bolts/src/minibsod.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -715,13 +715,28 @@ fn write_crash<W: Write>(
715715
) -> Result<(), std::io::Error> {
716716
writeln!(
717717
writer,
718-
"Received signal {} at{:016x}, fault address: 0x{:016x}",
718+
"Received signal {} at {:016x}, fault address: 0x{:016x}",
719719
signal, ucontext.uc_mcontext.mc_rip, ucontext.uc_mcontext.mc_fs
720720
)?;
721721

722722
Ok(())
723723
}
724724

725+
#[cfg(all(target_os = "freebsd", target_arch = "x86"))]
726+
fn write_crash<W: Write>(
727+
writer: &mut BufWriter<W>,
728+
signal: Signal,
729+
ucontext: &ucontext_t,
730+
) -> Result<(), std::io::Error> {
731+
writeln!(
732+
writer,
733+
"Received signal {} at {:016x}",
734+
signal, ucontext.uc_mcontext.mc_eip
735+
)?;
736+
737+
Ok(())
738+
}
739+
725740
#[cfg(all(target_os = "dragonfly", target_arch = "x86_64"))]
726741
fn write_crash<W: Write>(
727742
writer: &mut BufWriter<W>,
@@ -730,7 +745,7 @@ fn write_crash<W: Write>(
730745
) -> Result<(), std::io::Error> {
731746
writeln!(
732747
writer,
733-
"Received signal {} at{:016x}, fault address: 0x{:016x}",
748+
"Received signal {} at {:016x}, fault address: 0x{:016x}",
734749
signal, ucontext.uc_mcontext.mc_rip, ucontext.uc_mcontext.mc_cs
735750
)?;
736751

@@ -745,7 +760,7 @@ fn write_crash<W: Write>(
745760
) -> Result<(), std::io::Error> {
746761
writeln!(
747762
writer,
748-
"Received signal {} at{:016x}, fault address: 0x{:016x}",
763+
"Received signal {} at {:016x}, fault address: 0x{:016x}",
749764
signal, ucontext.sc_rip, ucontext.sc_fs
750765
)?;
751766

@@ -760,7 +775,7 @@ fn write_crash<W: Write>(
760775
) -> Result<(), std::io::Error> {
761776
writeln!(
762777
writer,
763-
"Received signal {} at{:016x}",
778+
"Received signal {} at {:016x}",
764779
signal, ucontext.sc_elr
765780
)?;
766781

crates/libafl_bolts/src/os/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ pub fn peak_rss_mb_child_processes() -> Result<i64, Error> {
142142
Ok(rusage.assume_init())
143143
}
144144
}?;
145-
Ok(rss.ru_maxrss >> 10)
145+
let result = rss.ru_maxrss >> 10;
146+
#[cfg(all(target_os = "freebsd", target_arch = "x86"))]
147+
let result = result.into();
148+
Ok(result)
146149
}
147150

148151
/// "Safe" wrapper around dup2

crates/libafl_frida/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ workspace = true
105105
[target.'cfg(target_arch = "aarch64")'.dependencies]
106106
yaxpeax-arm = "0.3.0"
107107

108-
[target.'cfg(target_arch = "x86_64")'.dependencies]
108+
[target.'cfg(any(target_arch = "x86_64", target_arch = "x86"))'.dependencies]
109109
yaxpeax-x86 = "2.0.0"
110110
iced-x86 = { version = "1.21.0", features = ["code_asm"], optional = true }
111111

crates/libafl_frida/src/allocator.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[cfg(any(
22
windows,
33
target_os = "linux",
4+
target_os = "freebsd",
45
target_vendor = "apple",
56
all(
67
any(target_arch = "aarch64", target_arch = "x86_64"),
@@ -11,6 +12,7 @@ use alloc::collections::BTreeMap;
1112
#[cfg(any(
1213
windows,
1314
target_os = "linux",
15+
target_os = "freebsd",
1416
target_vendor = "apple",
1517
all(
1618
any(target_arch = "aarch64", target_arch = "x86_64"),
@@ -35,6 +37,7 @@ use mach_sys::{
3537
#[cfg(any(
3638
windows,
3739
target_os = "linux",
40+
target_os = "freebsd",
3841
target_vendor = "apple",
3942
all(
4043
any(target_arch = "aarch64", target_arch = "x86_64"),
@@ -115,6 +118,7 @@ impl Allocator {
115118
#[cfg(not(any(
116119
windows,
117120
target_os = "linux",
121+
target_os = "freebsd",
118122
target_vendor = "apple",
119123
all(
120124
any(target_arch = "aarch64", target_arch = "x86_64"),
@@ -130,6 +134,7 @@ impl Allocator {
130134
#[cfg(any(
131135
windows,
132136
target_os = "linux",
137+
target_os = "freebsd",
133138
target_vendor = "apple",
134139
all(
135140
any(target_arch = "aarch64", target_arch = "x86_64"),
@@ -710,8 +715,10 @@ impl Allocator {
710715

711716
let mut occupied_ranges: Vec<(usize, usize)> = vec![];
712717
// max(userspace address) this is usually 0x8_0000_0000_0000 - 1 on x64 linux.
713-
#[cfg(unix)]
718+
#[cfg(all(unix, not(target_arch = "x86")))]
714719
let mut userspace_max: usize = 0;
720+
#[cfg(all(unix, target_arch = "x86"))]
721+
let userspace_max: usize = 0;
715722

716723
// Enumerate memory ranges that are already occupied.
717724

@@ -836,6 +843,7 @@ impl Default for Allocator {
836843
#[cfg(not(any(
837844
windows,
838845
target_os = "linux",
846+
target_os = "freebsd",
839847
target_vendor = "apple",
840848
all(
841849
any(target_arch = "aarch64", target_arch = "x86_64"),
@@ -849,7 +857,8 @@ impl Default for Allocator {
849857
fn default() -> Self {
850858
let page_size = MmapOptions::page_size();
851859

852-
Self {
860+
#[cfg(target_pointer_width = "64")]
861+
return Self {
853862
max_allocation: 1 << 30,
854863
max_allocation_panics: false,
855864
max_total_allocation: 1 << 32,
@@ -867,7 +876,27 @@ impl Default for Allocator {
867876
total_allocation_size: 0,
868877
base_mapping_addr: 0,
869878
current_mapping_addr: 0,
870-
}
879+
};
880+
#[cfg(target_pointer_width = "32")]
881+
return Self {
882+
max_allocation: 1 << 30,
883+
max_allocation_panics: false,
884+
max_total_allocation: 1 << 31,
885+
allocation_backtraces: false,
886+
page_size,
887+
pre_allocated_shadow_mappings: Vec::new(),
888+
using_pre_allocated_shadow_mapping: false,
889+
mappings: BTreeMap::new(),
890+
shadow_offset: 0,
891+
shadow_bit: 0,
892+
allocations: BTreeMap::new(),
893+
shadow_pages: RangeSet::new(),
894+
allocation_queue: BTreeMap::new(),
895+
largest_allocation: 0,
896+
total_allocation_size: 0,
897+
base_mapping_addr: 0,
898+
current_mapping_addr: 0,
899+
};
871900
}
872901
}
873902

0 commit comments

Comments
 (0)