From 211809dddb6c0e53a06d69c8e9e4f2be98aa7f34 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 30 Jul 2024 13:42:48 +0200 Subject: [PATCH] Cmplog bytes without alloc (#2442) * Cmplog bytes without alloc * fixes * clippy * remove wrong % --- libafl/src/mutators/token_mutations.rs | 52 +++++++++++++++----------- libafl/src/observers/cmp.rs | 37 +++++++++++++++++- libafl_targets/src/cmps/mod.rs | 16 +++++--- 3 files changed, 77 insertions(+), 28 deletions(-) diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 95480dd09e..c0055cf8d0 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -17,7 +17,7 @@ use std::{ }; use hashbrown::HashSet; -use libafl_bolts::{rands::Rand, AsSlice}; +use libafl_bolts::{rands::Rand, AsSlice, HasLen}; use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] @@ -561,9 +561,9 @@ where 'outer: for i in off..len { let mut size = core::cmp::min(v.0.len(), len - i); while size != 0 { - if v.0[0..size] == input.bytes()[i..i + size] { + if v.0.as_slice()[0..size] == input.bytes()[i..i + size] { unsafe { - buffer_copy(input.bytes_mut(), &v.1, 0, i, size); + buffer_copy(input.bytes_mut(), v.1.as_slice(), 0, i, size); } result = MutationResult::Mutated; break 'outer; @@ -572,9 +572,9 @@ where } size = core::cmp::min(v.1.len(), len - i); while size != 0 { - if v.1[0..size] == input.bytes()[i..i + size] { + if v.1.as_slice()[0..size] == input.bytes()[i..i + size] { unsafe { - buffer_copy(input.bytes_mut(), &v.0, 0, i, size); + buffer_copy(input.bytes_mut(), v.0.as_slice(), 0, i, size); } result = MutationResult::Mutated; break 'outer; @@ -1568,10 +1568,10 @@ where let mut rtn_found = false; // Compare v0 against v1 rtn_found |= self.rtn_extend_encoding( - orig_v0, - orig_v1, - new_v0, - new_v1, + orig_v0.as_slice(), + orig_v1.as_slice(), + new_v0.as_slice(), + new_v1.as_slice(), new_bytes, orig_bytes, cmp_buf_idx, @@ -1583,10 +1583,10 @@ where // Compare v1 against v0 rtn_found |= self.rtn_extend_encoding( - orig_v1, - orig_v0, - new_v1, - new_v0, + orig_v1.as_slice(), + orig_v0.as_slice(), + new_v1.as_slice(), + new_v0.as_slice(), new_bytes, orig_bytes, cmp_buf_idx, @@ -1601,10 +1601,10 @@ where let mut v1_len = orig_v1.len(); if v0_len > 0 && (is_ascii_or_utf8 - || check_if_text(orig_v0, v0_len).size() == hshape) + || check_if_text(orig_v0.as_slice(), v0_len).size() == hshape) { // this is not utf8. - let v = strlen(orig_v0); + let v = strlen(orig_v0.as_slice()); if v > 0 { v0_len = v; } @@ -1612,10 +1612,10 @@ where if v1_len > 0 && (is_ascii_or_utf8 - || check_if_text(orig_v1, v1_len).size() == hshape) + || check_if_text(orig_v1.as_slice(), v1_len).size() == hshape) { // this is not utf8. - let v = strlen(orig_v1); + let v = strlen(orig_v1.as_slice()); if v > 0 { v1_len = v; } @@ -1623,16 +1623,26 @@ where if v0_len > 0 && orig_v0 == new_v0 - && (!rtn_found || check_if_text(orig_v0, v0_len).size() == v0_len) + && (!rtn_found + || check_if_text(orig_v0.as_slice(), v0_len).size() == v0_len) { - Self::try_add_autotokens(&mut gathered_tokens, orig_v0, v0_len); + Self::try_add_autotokens( + &mut gathered_tokens, + orig_v0.as_slice(), + v0_len, + ); } if v1_len > 0 && orig_v1 == new_v1 - && (!rtn_found || check_if_text(orig_v1, v1_len).size() == v1_len) + && (!rtn_found + || check_if_text(orig_v1.as_slice(), v1_len).size() == v1_len) { - Self::try_add_autotokens(&mut gathered_tokens, orig_v1, v1_len); + Self::try_add_autotokens( + &mut gathered_tokens, + orig_v1.as_slice(), + v1_len, + ); } } (_, _) => { diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 3c89616ac6..2d5b0298a2 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -9,7 +9,7 @@ use core::{ use c2rust_bitfields::BitfieldStruct; use hashbrown::HashMap; -use libafl_bolts::{ownedref::OwnedRefMut, serdeany::SerdeAny, Named}; +use libafl_bolts::{ownedref::OwnedRefMut, serdeany::SerdeAny, AsSlice, HasLen, Named}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{executors::ExitKind, inputs::UsesInput, observers::Observer, Error, HasMetadata}; @@ -35,6 +35,39 @@ where fn add_from(&mut self, usable_count: usize, cmp_map: &mut CM, cmp_observer_data: Self::Data); } +/// A bytes string for cmplog with up to 32 elements. +#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)] +pub struct CmplogBytes { + buf: [u8; 32], + len: u8, +} + +impl CmplogBytes { + /// Creates a new [`CmplogBytes`] object from the provided buf and length. + /// Lengths above 32 are illegal but will be ignored. + #[must_use] + pub fn from_buf_and_len(buf: [u8; 32], len: u8) -> Self { + debug_assert!(len <= 32, "Len too big: {len}, max: 32"); + CmplogBytes { buf, len } + } +} + +impl<'a> AsSlice<'a> for CmplogBytes { + type Entry = u8; + + type SliceRef = &'a [u8]; + + fn as_slice(&'a self) -> Self::SliceRef { + &self.buf[0..(self.len as usize)] + } +} + +impl HasLen for CmplogBytes { + fn len(&self) -> usize { + self.len as usize + } +} + /// Compare values collected during a run #[derive(Eq, PartialEq, Debug, Serialize, Deserialize, Clone)] pub enum CmpValues { @@ -47,7 +80,7 @@ pub enum CmpValues { /// Two u64 values U64((u64, u64)), /// Two vecs of u8 values/byte - Bytes((Vec, Vec)), + Bytes((CmplogBytes, CmplogBytes)), } impl CmpValues { diff --git a/libafl_targets/src/cmps/mod.rs b/libafl_targets/src/cmps/mod.rs index 7d6c0b8c9f..7512060031 100644 --- a/libafl_targets/src/cmps/mod.rs +++ b/libafl_targets/src/cmps/mod.rs @@ -13,7 +13,7 @@ use core::{ }; use libafl::{ - observers::{cmp::AFLppCmpLogHeader, CmpMap, CmpValues}, + observers::{cmp::AFLppCmpLogHeader, CmpMap, CmpValues, CmplogBytes}, Error, }; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -390,8 +390,14 @@ impl CmpMap for CmpLogMap { } else { unsafe { Some(CmpValues::Bytes(( - self.vals.routines[idx][execution].0.to_vec(), - self.vals.routines[idx][execution].1.to_vec(), + CmplogBytes::from_buf_and_len( + self.vals.routines[idx][execution].0, + CMPLOG_RTN_LEN as u8, + ), + CmplogBytes::from_buf_and_len( + self.vals.routines[idx][execution].1, + CMPLOG_RTN_LEN as u8, + ), ))) } } @@ -567,8 +573,8 @@ impl CmpMap for AFLppCmpLogMap { let v0_len = self.vals.fn_operands[idx][execution].v0_len & (0x80 - 1); let v1_len = self.vals.fn_operands[idx][execution].v1_len & (0x80 - 1); Some(CmpValues::Bytes(( - self.vals.fn_operands[idx][execution].v0[..(v0_len as usize)].to_vec(), - self.vals.fn_operands[idx][execution].v1[..(v1_len as usize)].to_vec(), + CmplogBytes::from_buf_and_len(self.vals.fn_operands[idx][execution].v0, v0_len), + CmplogBytes::from_buf_and_len(self.vals.fn_operands[idx][execution].v1, v1_len), ))) } }