Skip to content

Commit

Permalink
support cast in anywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
spinpx committed Dec 20, 2023
1 parent afdf2f4 commit ddaed1b
Show file tree
Hide file tree
Showing 25 changed files with 303 additions and 148 deletions.
3 changes: 2 additions & 1 deletion hopper-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub static TMP_DIR: &str = "misc/tmp";
pub static REVIEW_DIR: &str = "misc/review";
pub static HARNESS_WORK_DIR: &str = "working";
pub const MAX_INPUT_SZIE: usize = 5000;
pub const MAX_QUEUE_SIZE: usize = 6000;
pub const MAX_QUEUE_SIZE: usize = 8000;

// --- Mutation ---
pub const ROUND_PILOT_NUM: usize = 256;
Expand All @@ -106,6 +106,7 @@ pub const MAX_RANGE_NUM: u64 = 4096;
pub const RESERVED_FD_MIN: i32 = 3;
pub const RESERVED_FD_MAX: i32 = 32;
pub const RESERVED_FD_HUGE: i32 = 1000;
pub const REVIEW_ID_BASE: usize = 1000000;

// -----------------------------------------------------

Expand Down
3 changes: 1 addition & 2 deletions hopper-core/src/feedback/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,7 @@ impl CmpOperation {
}

pub fn log_cmp(&self) {
crate::log!(
info,
println!(
"CMP id: {}, ty: {}, size: {}, stmt: {}, operands: {:?}, {:?}, state: {:#04x}",
{ self.id },
{ self.ty },
Expand Down
6 changes: 4 additions & 2 deletions hopper-core/src/feedback/globl/variadic.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ int __hopper_open(const char* pathname, int flags, ...) {
// mot_t mode = va_arg (args, int);
int fd = open(pathname, flags, ap);
va_end(ap);
u_int32_t id = (uintptr_t)__builtin_return_address(0) % 0xFFFFFFFF;
// u_int32_t id = (uintptr_t)__builtin_return_address(0) % 0xFFFFFFFF;
u_int32_t id = 0;
__hopper_open_hook(id, pathname, flags);
return fd;
}
Expand All @@ -27,7 +28,8 @@ int __hopper_open64(const char* pathname, int flags, ...) {
// mot_t mode = va_arg (args, int);
int fd = open64(pathname, flags, ap);
va_end(ap);
u_int32_t id = (uintptr_t)__builtin_return_address(0) % 0xFFFFFFFFF;
// u_int32_t id = (uintptr_t)__builtin_return_address(0) % 0xFFFFFFFFF;
u_int32_t id = 0;
__hopper_open_hook(id, pathname, flags);
return fd;
}
Expand Down
3 changes: 2 additions & 1 deletion hopper-core/src/feedback/instr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ pub fn find_location_at_ptr(
if let Some(ret) = &call.ret {
let layout = ret.get_layout(false);
// crate::log!(trace, "layout: {:?}", layout);
if let Some(fields) = layout.find_ptr(ptr, resource_states) {
if let Some(mut fields) = layout.find_ptr(ptr, resource_states) {
let _ = fields.strip_pointer_prefix();
return Some(Location::new(index.use_index(), fields));
}
}
Expand Down
3 changes: 2 additions & 1 deletion hopper-core/src/feedback/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ impl InstrList {
if let Some(FieldKey::Index(_)) = loc.fields.list.last() {
loc.fields.list.pop();
}
crate::log_c!(trace, "find loc: {loc:?}");
let record = MemRecord {
id,
size,
Expand All @@ -183,7 +184,7 @@ impl InstrList {
mem_records.push(record);
}
}
crate::log_c!(trace, "finish associate mem");
crate::log_c!(trace, "finish associate mem, len: {}", mem_records.len());
mem_records
}

Expand Down
2 changes: 1 addition & 1 deletion hopper-core/src/feedback/res.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl ResourceStates {
let stmt_index = instrs.last_stmt_index() as u16;
for op in instrs.mem_iter() {
if op.stmt_index == stmt_index {
crate::log!(trace, "mem op: {} ", op);
crate::log!(trace, "mem op: {op:?} ");
let ty = op.get_type();
// find out freed pointer
match ty {
Expand Down
17 changes: 14 additions & 3 deletions hopper-core/src/feedback/review.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,10 @@ impl ReviewResult {
/// Add review's result into constraints
pub fn add_into_constraints(&self, program: &FuzzProgram) -> eyre::Result<()> {
for ret in &self.call_rets {
let call_is = &program.stmts[ret.call_index];
let call_is = &program
.stmts
.get(ret.call_index)
.context("fail to find index")?;
if let FuzzStmt::Call(call) = &call_is.stmt {
let call_name = call.fg.f_name;
let id = program.id;
Expand Down Expand Up @@ -387,7 +390,10 @@ fn set_program_mem_records(
// find all indices that used it.
for is in program.stmts.iter_mut() {
if let FuzzStmt::Load(load) = &mut is.stmt {
if load.state.find_any_stmt_in_state_with(|ptee| ptee.get() == stmt_i) {
if load
.state
.find_any_stmt_in_state_with(|ptee| ptee.get() == stmt_i)
{
is.freed = Some(call_index.downgrade());
}
}
Expand All @@ -413,7 +419,12 @@ fn set_program_cmp_records(
crate::log!(trace, "set cmp records..");
// cmp inst
let cmps = get_instr_list().get_cmp_ref_list();
crate::log!(trace, "store inst cmp list, program: {}, length: {}", program.id,cmps.len());
crate::log!(
trace,
"store inst cmp list, program: {}, length: {}",
program.id,
cmps.len()
);
// eyre::ensure!(!cmps.is_empty(), "should not be empty");
program.cmps = std::rc::Rc::new(cmps);
// cmp function
Expand Down
8 changes: 7 additions & 1 deletion hopper-core/src/fuzz/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ impl FuzzProgram {
_ => {}
}
}
log!(trace, "check ref done");
self.eliminate_invalidatd_operators();
self.eliminate_invalidatd_contexts();
log!(trace, "check ref done: {} -> {}", len, self.stmts.len());

Ok(())
}
Expand Down Expand Up @@ -242,6 +242,12 @@ impl FuzzProgram {
}
false
}

/// Check if the loc is mutated
pub fn is_loc_mutated(&self, loc: &Location) -> bool {
let wl = loc.to_weak_loc();
self.ops.iter().any(|l| l.key == wl)
}
}

/// get depth of current statement
Expand Down
57 changes: 56 additions & 1 deletion hopper-core/src/fuzz/infer/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,64 @@
//! the void pointer may be interpreted as a structure containing pointers.
//! Thus, We remove the CAST constraints with char* type.
use crate::{fuzz::*, fuzzer::*, runtime::*, CrashSig};
use crate::{fuzz::*, fuzzer::*, log, runtime::*, utils, CrashSig};

impl Fuzzer {
/// Infer if a void type can be casted as a char type or not.
pub fn pilot_infer_void_type(
&mut self,
program: &FuzzProgram,
stmt_index: &StmtIndex,
load_state: &ObjectState,
call_stmt: &CallStmt,
arg_pos: usize,
prefix: &LocFields,
) -> eyre::Result<()> {
// let arg_type = call_stmt.fg.arg_types[arg_pos];
// let alias_arg_type = call_stmt.fg.alias_arg_types[arg_pos];
// let is_void_pointer = utils::is_void_pointer(arg_type);
let null_fields =
load_state.find_fields_with(|s| s.is_null() && utils::is_void_pointer(s.ty), false);
for f in null_fields {
log!(
trace,
"try infer void type at {stmt_index} {f}, ty: {}",
load_state.ty
);
// (alias_type.contains("void") || alias_type.contains("Void"))
// log!(trace, "infer void type at {stmt_index}");
let op = MutateOperator::new(
Location::new(stmt_index.use_index(), f.clone()),
MutateOperation::PointerGenChar,
);
let mut suc = true;
log!(trace, "try to infer void type");
// verify with some random data,
// and verify it in other execute paths later.
for _ in 0..100 {
let status = self.execute_with_op(program, &op, false)?;
if !status.is_normal() {
log!(trace, "fail to infer void type, crash!");
suc = false;
break;
}
}
if suc {
let full_f = prefix.with_suffix(f);
add_function_constraint(
call_stmt.fg.f_name,
arg_pos,
full_f,
Constraint::CastFrom {
cast_type: utils::mut_pointer_type("i8"),
},
"try to assgin cast",
)?;
}
}
Ok(())
}

/// Infer if the void type is casted to a concrete type that contain pointers.
/// If so, we can't use a huge byte array to interpret the void object.
pub fn infer_void_cast(
Expand Down
1 change: 1 addition & 0 deletions hopper-core/src/fuzz/infer/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ impl ReviewResult {
}
found_file = true;
let call_name = call_stmt.fg.f_name;
crate::log!(trace, "prefix: {prefix:?}");
crate::add_function_constraint(
call_name,
arg_pos,
Expand Down
2 changes: 2 additions & 0 deletions hopper-core/src/fuzz/infer/length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,12 +690,14 @@ fn infer_factors(
let _ = crate::inspect_function_constraint_mut_with(f_name, |fc| {
let mut factors = vec![];
for (key_arg_pos, cs) in fc.arg_constraints.iter_mut().enumerate() {
// crate::log_trace!("dst: {arr_arg_pos} - {arr_fields}");
for c in &mut cs.list {
let val = match &mut c.constraint {
Constraint::SetVal { val } => val,
Constraint::Range { min: _, max } => max,
_ => continue,
};
crate::log_trace!("len val: {val:?}");
if let IrEntry::Length {
arg_pos,
fields,
Expand Down
10 changes: 5 additions & 5 deletions hopper-core/src/fuzz/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,10 @@ impl Fuzzer {
fn infer_by_review_program(&mut self, program: &FuzzProgram) -> eyre::Result<StatusType> {
let mut p = program.clone();
// avoid id collision in review
p.id = 1000000;
p.id = config::REVIEW_ID_BASE + rng::gen_range(1..config::REVIEW_ID_BASE);
let review_status = self.executor.review_program(&p)?;
// println!("mem_len: {}", self.observer.feedback.instrs.mem_len());
// self.observer.feedback.instrs.mem_iter().for_each(|m| println!("mem: {m:?}"));
let review = crate::feedback::ReviewResult::read_from_file(&mut p)?;
review.add_into_constraints(&p)?;
Ok(review_status)
Expand Down Expand Up @@ -193,10 +195,7 @@ impl Fuzzer {
// ----------------------------------------
// 0. Infer void pointer: try to cast it to char*
// ----------------------------------------
// only infer void pointer arguments
if prefix.is_empty() {
self.pilot_infer_void_type(program, stmt_index, call_stmt, arg_pos)?;
}
self.pilot_infer_void_type(program, stmt_index, load_state, call_stmt, arg_pos, &prefix)?;
// ----------------------------------------
// 1. Infer pointer : set the pointer to NULL
// ----------------------------------------
Expand Down Expand Up @@ -273,6 +272,7 @@ impl Fuzzer {
pub fn seed_infer(&mut self, program: &FuzzProgram) -> eyre::Result<Vec<ConstraintSig>> {
let mut new_constraints = vec![];
crate::log!(trace, "infer new seed");
let _ = self.infer_by_review_program(program)?;
if let Some(c) = self.infer_file_fd(program)? {
new_constraints.push(c);
}
Expand Down
44 changes: 0 additions & 44 deletions hopper-core/src/fuzz/infer/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,6 @@ use eyre::ContextCompat;
use crate::{fuzz::*, fuzzer::*, log, runtime::*, utils, CrashSig};

impl Fuzzer {
/// Infer if a void type can be casted as a char type or not.
pub fn pilot_infer_void_type(
&mut self,
program: &FuzzProgram,
stmt_index: &StmtIndex,
call_stmt: &CallStmt,
arg_pos: usize,
) -> eyre::Result<()> {
let arg_type = call_stmt.fg.arg_types[arg_pos];
let alias_arg_type = call_stmt.fg.alias_arg_types[arg_pos];
if utils::is_void_pointer(arg_type)
&& (alias_arg_type.contains("void") || alias_arg_type.contains("Void"))
{
log!(trace, "arg type: {arg_type} {alias_arg_type}");
let op = MutateOperator::new(
Location::stmt(stmt_index.use_index()),
MutateOperation::PointerGenChar,
);
let mut suc = true;
log!(trace, "try to infer void type");
// verify with some random data,
// and verify it in other execute paths later.
for _ in 0..100 {
let status = self.execute_with_op(program, &op, false)?;
if !status.is_normal() {
log!(trace, "fail to infer void type, crash!");
suc = false;
break;
}
}
if suc {
add_function_arg_constraint(
call_stmt.fg.f_name,
arg_pos,
Constraint::CastFrom {
cast_type: utils::mut_pointer_type("i8"),
},
"try to assgin cast",
)?;
}
}
Ok(())
}

/// If we update a call's return fails, we assume the return's type is opaque that can not be mutated.
pub fn infer_opaque_if_update_fail(
&mut self,
Expand Down
25 changes: 13 additions & 12 deletions hopper-core/src/fuzz/infer/res.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ impl Fuzzer {
prefix: &LocFields,
fields: &LocFields,
) -> eyre::Result<Option<ConstraintSig>> {
let full_f = prefix.with_suffix(fields.clone());
let f_name = call_stmt.fg.f_name;
if crate::filter_function_field_constraint_with(f_name, arg_pos, &full_f, |tc| {
tc.should_not_mutate()
}) {
return Ok(None);
}
log!(
trace,
"try to infer arg: {arg_pos}, field {fields:?} to be underflow"
Expand Down Expand Up @@ -116,9 +123,8 @@ impl Fuzzer {
}
}
}
let full_f = prefix.with_suffix(fields.clone());
add_function_constraint(
call_stmt.fg.f_name,
f_name,
arg_pos,
full_f,
Constraint::NonZero,
Expand Down Expand Up @@ -252,9 +258,10 @@ impl Fuzzer {
let mut c = Constraint::resource_related();
let _ = crate::inspect_function_constraint_with(f_name, |fc| {
if let Some(tc) = fc.arg_constraints[arg_pos]
.list
.iter()
.find(|tc| tc.key == full_f) {
.list
.iter()
.find(|tc| tc.key == full_f)
{
if matches!(&tc.constraint, Constraint::Range { min: _, max: _ }) {
c = tc.constraint.clone();
c.shrink_range();
Expand All @@ -263,13 +270,7 @@ impl Fuzzer {
Ok(())
});

return add_function_constraint(
f_name,
arg_pos,
full_f,
c,
&comment,
);
return add_function_constraint(f_name, arg_pos, full_f, c, &comment);
}
Ok(None)
}
Expand Down
2 changes: 1 addition & 1 deletion hopper-core/src/fuzz/mutate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl FuzzProgram {
if let Err(err) = ret {
crate::log!(trace, "p: {}", self.serialize().unwrap());
crate::log!(trace, "stmt: {}", stmt.serialize().unwrap());
crate::log!(trace, "fail to mutate by op, op: {:?}, err: {:?}", op, err);
crate::log!(trace, "fail to mutate by op, op: {}, err: {:?}", op, err);
}
{
let index = self.withdraw_stmt(stmt)?;
Expand Down
Loading

0 comments on commit ddaed1b

Please sign in to comment.