Skip to content

Commit

Permalink
Use const to Inform CmpLog Replacements (AFLplusplus#2528)
Browse files Browse the repository at this point in the history
* Add some knowledge of const parameters in cmplogs

* Careful with the CmpLog unions and clean macros

* Fix for macros?

---------

Co-authored-by: Dongjia "toka" Zhang <[email protected]>
  • Loading branch information
DanBlackwell and tokatoka authored Sep 24, 2024
1 parent 36a0820 commit 4e54182
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 100 deletions.
64 changes: 32 additions & 32 deletions libafl/src/mutators/token_mutations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,99 +457,99 @@ where

let mut result = MutationResult::Skipped;
match cmp_values {
CmpValues::U8(v) => {
CmpValues::U8((v1, v2, v1_is_const)) => {
for byte in bytes.iter_mut().take(len).skip(off) {
if *byte == v.0 {
*byte = v.1;
if !v1_is_const && *byte == *v1 {
*byte = *v2;
result = MutationResult::Mutated;
break;
} else if *byte == v.1 {
*byte = v.0;
} else if *byte == *v2 {
*byte = *v1;
result = MutationResult::Mutated;
break;
}
}
}
CmpValues::U16(v) => {
CmpValues::U16((v1, v2, v1_is_const)) => {
if len >= size_of::<u16>() {
for i in off..=len - size_of::<u16>() {
let val =
u16::from_ne_bytes(bytes[i..i + size_of::<u16>()].try_into().unwrap());
if val == v.0 {
let new_bytes = v.1.to_ne_bytes();
if !v1_is_const && val == *v1 {
let new_bytes = v2.to_ne_bytes();
bytes[i..i + size_of::<u16>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val.swap_bytes() == v.0 {
let new_bytes = v.1.swap_bytes().to_ne_bytes();
} else if !v1_is_const && val.swap_bytes() == *v1 {
let new_bytes = v2.swap_bytes().to_ne_bytes();
bytes[i..i + size_of::<u16>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val == v.1 {
let new_bytes = v.0.to_ne_bytes();
} else if val == *v2 {
let new_bytes = v1.to_ne_bytes();
bytes[i..i + size_of::<u16>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val.swap_bytes() == v.1 {
let new_bytes = v.0.swap_bytes().to_ne_bytes();
} else if val.swap_bytes() == *v2 {
let new_bytes = v1.swap_bytes().to_ne_bytes();
bytes[i..i + size_of::<u16>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
}
}
}
}
CmpValues::U32(v) => {
CmpValues::U32((v1, v2, v1_is_const)) => {
if len >= size_of::<u32>() {
for i in off..=len - size_of::<u32>() {
let val =
u32::from_ne_bytes(bytes[i..i + size_of::<u32>()].try_into().unwrap());
if val == v.0 {
let new_bytes = v.1.to_ne_bytes();
if !v1_is_const && val == *v1 {
let new_bytes = v2.to_ne_bytes();
bytes[i..i + size_of::<u32>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val.swap_bytes() == v.0 {
let new_bytes = v.1.swap_bytes().to_ne_bytes();
} else if !v1_is_const && val.swap_bytes() == *v1 {
let new_bytes = v2.swap_bytes().to_ne_bytes();
bytes[i..i + size_of::<u32>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val == v.1 {
let new_bytes = v.0.to_ne_bytes();
} else if val == *v2 {
let new_bytes = v1.to_ne_bytes();
bytes[i..i + size_of::<u32>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val.swap_bytes() == v.1 {
let new_bytes = v.0.swap_bytes().to_ne_bytes();
} else if val.swap_bytes() == *v2 {
let new_bytes = v1.swap_bytes().to_ne_bytes();
bytes[i..i + size_of::<u32>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
}
}
}
}
CmpValues::U64(v) => {
CmpValues::U64((v1, v2, v1_is_const)) => {
if len >= size_of::<u64>() {
for i in off..=len - size_of::<u64>() {
let val =
u64::from_ne_bytes(bytes[i..i + size_of::<u64>()].try_into().unwrap());
if val == v.0 {
let new_bytes = v.1.to_ne_bytes();
if !v1_is_const && val == *v1 {
let new_bytes = v2.to_ne_bytes();
bytes[i..i + size_of::<u64>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val.swap_bytes() == v.0 {
let new_bytes = v.1.swap_bytes().to_ne_bytes();
} else if !v1_is_const && val.swap_bytes() == *v1 {
let new_bytes = v2.swap_bytes().to_ne_bytes();
bytes[i..i + size_of::<u64>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val == v.1 {
let new_bytes = v.0.to_ne_bytes();
} else if val == *v2 {
let new_bytes = v1.to_ne_bytes();
bytes[i..i + size_of::<u64>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
} else if val.swap_bytes() == v.1 {
let new_bytes = v.0.swap_bytes().to_ne_bytes();
} else if val.swap_bytes() == *v2 {
let new_bytes = v1.swap_bytes().to_ne_bytes();
bytes[i..i + size_of::<u64>()].copy_from_slice(&new_bytes);
result = MutationResult::Mutated;
break;
Expand Down
24 changes: 12 additions & 12 deletions libafl/src/observers/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ impl HasLen for CmplogBytes {
/// Compare values collected during a run
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)]
pub enum CmpValues {
/// Two u8 values
U8((u8, u8)),
/// Two u16 values
U16((u16, u16)),
/// Two u32 values
U32((u32, u32)),
/// Two u64 values
U64((u64, u64)),
/// (side 1 of comparison, side 2 of comparison, side 1 value is const)
U8((u8, u8, bool)),
/// (side 1 of comparison, side 2 of comparison, side 1 value is const)
U16((u16, u16, bool)),
/// (side 1 of comparison, side 2 of comparison, side 1 value is const)
U32((u32, u32, bool)),
/// (side 1 of comparison, side 2 of comparison, side 1 value is const)
U64((u64, u64, bool)),
/// Two vecs of u8 values/byte
Bytes((CmplogBytes, CmplogBytes)),
}
Expand All @@ -95,11 +95,11 @@ impl CmpValues {

/// Converts the value to a u64 tuple
#[must_use]
pub fn to_u64_tuple(&self) -> Option<(u64, u64)> {
pub fn to_u64_tuple(&self) -> Option<(u64, u64, bool)> {
match self {
CmpValues::U8(t) => Some((u64::from(t.0), u64::from(t.1))),
CmpValues::U16(t) => Some((u64::from(t.0), u64::from(t.1))),
CmpValues::U32(t) => Some((u64::from(t.0), u64::from(t.1))),
CmpValues::U8(t) => Some((u64::from(t.0), u64::from(t.1), t.2)),
CmpValues::U16(t) => Some((u64::from(t.0), u64::from(t.1), t.2)),
CmpValues::U32(t) => Some((u64::from(t.0), u64::from(t.1), t.2)),
CmpValues::U64(t) => Some(*t),
CmpValues::Bytes(_) => None,
}
Expand Down
14 changes: 7 additions & 7 deletions libafl_targets/src/cmplog.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ static inline long area_is_valid(const void *ptr, size_t len) {
// Very generic cmplog instructions callback
void __libafl_targets_cmplog_instructions(uintptr_t k, uint8_t shape,
uint64_t arg1, uint64_t arg2) {
cmplog_instructions_checked(k, shape, arg1, arg2);
cmplog_instructions_checked(k, shape, arg1, arg2, 0);
}

// Very generic cmplog routines callback
Expand Down Expand Up @@ -145,7 +145,7 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) {
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;

cmplog_instructions_checked(k, 1, arg1, arg2);
cmplog_instructions_checked(k, 1, arg1, arg2, 0);
}

void __cmplog_ins_hook2_extended(uint16_t arg1, uint16_t arg2, uint8_t attr) {
Expand All @@ -160,7 +160,7 @@ void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) {
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;

cmplog_instructions_checked(k, 2, arg1, arg2);
cmplog_instructions_checked(k, 2, arg1, arg2, 0);
}

void __cmplog_ins_hook4_extended(uint32_t arg1, uint32_t arg2, uint8_t attr) {
Expand All @@ -175,7 +175,7 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) {
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;

cmplog_instructions_checked(k, 4, arg1, arg2);
cmplog_instructions_checked(k, 4, arg1, arg2, 0);
}

void __cmplog_ins_hook8_extended(uint64_t arg1, uint64_t arg2, uint8_t attr) {
Expand All @@ -190,7 +190,7 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;

cmplog_instructions_checked(k, 8, arg1, arg2);
cmplog_instructions_checked(k, 8, arg1, arg2, 0);
}

#if !defined(_WIN32) && defined(__SIZEOF_INT128__)
Expand All @@ -207,7 +207,7 @@ void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2) {
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;

cmplog_instructions_checked(k, 16, arg1, arg2);
cmplog_instructions_checked(k, 16, arg1, arg2, 0);
}

void __cmplog_ins_hookN_extended(uint128_t arg1, uint128_t arg2, uint8_t attr,
Expand All @@ -223,7 +223,7 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t size) {
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;

cmplog_instructions_checked(k, size, arg1, arg2);
cmplog_instructions_checked(k, size, arg1, arg2, 0);
}
#endif
/*
Expand Down
5 changes: 4 additions & 1 deletion libafl_targets/src/cmplog.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ typedef PACKED(struct CmpLogHeaderExtended {
typedef struct CmpLogInstruction {
uint64_t v0;
uint64_t v1;
uint8_t v0_is_const;
} CmpLogInstruction;

typedef PACKED(struct CmpLogInstructionExtended {
Expand Down Expand Up @@ -106,7 +107,8 @@ extern uint8_t libafl_cmplog_enabled;
// cmplog_routines_checked_extended

static inline void cmplog_instructions_checked(uintptr_t k, uint8_t shape,
uint64_t arg1, uint64_t arg2) {
uint64_t arg1, uint64_t arg2,
uint8_t arg1_is_const) {
if (!libafl_cmplog_enabled) { return; }
libafl_cmplog_enabled = false;

Expand All @@ -126,6 +128,7 @@ static inline void cmplog_instructions_checked(uintptr_t k, uint8_t shape,
hits &= CMPLOG_MAP_H - 1;
libafl_cmplog_map_ptr->vals.operands[k][hits].v0 = arg1;
libafl_cmplog_map_ptr->vals.operands[k][hits].v1 = arg2;
libafl_cmplog_map_ptr->vals.operands[k][hits].v0_is_const = arg1_is_const;
libafl_cmplog_enabled = true;
}

Expand Down
12 changes: 10 additions & 2 deletions libafl_targets/src/cmps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ impl AFLppCmpLogFnOperands {
/// The operands logged during `CmpLog`.
#[repr(C)]
#[derive(Default, Debug, Clone, Copy)]
pub struct CmpLogInstruction(u64, u64);
pub struct CmpLogInstruction(u64, u64, u8);

/// The routine arguments logged during `CmpLog`.
#[repr(C)]
Expand Down Expand Up @@ -371,18 +371,22 @@ impl CmpMap for CmpLogMap {
1 => Some(CmpValues::U8((
self.vals.operands[idx][execution].0 as u8,
self.vals.operands[idx][execution].1 as u8,
self.vals.operands[idx][execution].2 == 1,
))),
2 => Some(CmpValues::U16((
self.vals.operands[idx][execution].0 as u16,
self.vals.operands[idx][execution].1 as u16,
self.vals.operands[idx][execution].2 == 1,
))),
4 => Some(CmpValues::U32((
self.vals.operands[idx][execution].0 as u32,
self.vals.operands[idx][execution].1 as u32,
self.vals.operands[idx][execution].2 == 1,
))),
8 => Some(CmpValues::U64((
self.vals.operands[idx][execution].0,
self.vals.operands[idx][execution].1,
self.vals.operands[idx][execution].2 == 1,
))),
// other => panic!("Invalid CmpLog shape {}", other),
_ => None,
Expand Down Expand Up @@ -426,7 +430,7 @@ pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap {
kind: 0,
}; CMPLOG_MAP_W],
vals: CmpLogVals {
operands: [[CmpLogInstruction(0, 0); CMPLOG_MAP_H]; CMPLOG_MAP_W],
operands: [[CmpLogInstruction(0, 0, 0); CMPLOG_MAP_H]; CMPLOG_MAP_W],
},
};

Expand Down Expand Up @@ -551,18 +555,22 @@ impl CmpMap for AFLppCmpLogMap {
0 => Some(CmpValues::U8((
self.vals.operands[idx][execution].v0 as u8,
self.vals.operands[idx][execution].v1 as u8,
false,
))),
1 => Some(CmpValues::U16((
self.vals.operands[idx][execution].v0 as u16,
self.vals.operands[idx][execution].v1 as u16,
false,
))),
3 => Some(CmpValues::U32((
self.vals.operands[idx][execution].v0 as u32,
self.vals.operands[idx][execution].v1 as u32,
false,
))),
7 => Some(CmpValues::U64((
self.vals.operands[idx][execution].v0,
self.vals.operands[idx][execution].v1,
false,
))),
// TODO handle 128 bits & 256 bits cmps
// other => panic!("Invalid CmpLog shape {}", other),
Expand Down
Loading

0 comments on commit 4e54182

Please sign in to comment.