@@ -5,10 +5,99 @@ use libafl::{
55 corpus:: Corpus ,
66 inputs:: { BytesInput , HasMutatorBytes } ,
77 mutators:: { MutationResult , Mutator } ,
8- observers:: { CmpValues , CmpValuesMetadata } ,
98 state:: { HasCorpus , HasMaxSize , HasRand } ,
109} ;
11- use libafl_bolts:: { AsSlice , HasLen , Named , rands:: Rand } ;
10+ use libafl_bolts:: { HasLen , Named , rands:: Rand } ;
11+
12+ use speedy:: { Readable , Writable } ;
13+ use std:: io:: { Cursor , Seek , SeekFrom } ;
14+ #[ derive( Debug , Clone , Hash , PartialEq , Eq , speedy:: Readable , speedy:: Writable ) ]
15+ #[ repr( u8 ) ]
16+ pub ( crate ) enum CmpLog {
17+ U16 ( u16 , u16 ) ,
18+ U32 ( u32 , u32 ) ,
19+ U64 ( u64 , u64 ) ,
20+ Memcmp ( Vec < u8 > , Vec < u8 > ) ,
21+ }
22+
23+ impl CmpLog {
24+ pub fn test_input ( & self , input : & [ u8 ] ) -> bool {
25+ enum V < ' a > {
26+ U16 ( u16 ) ,
27+ U32 ( u32 ) ,
28+ U64 ( u64 ) ,
29+ Bytes ( & ' a [ u8 ] ) ,
30+ }
31+ impl V < ' _ > {
32+ fn to_needles ( & self ) -> Vec < Vec < u8 > > {
33+ match self {
34+ V :: U16 ( v) => vec ! [ v. to_le_bytes( ) . to_vec( ) , v. to_be_bytes( ) . to_vec( ) ] ,
35+ V :: U32 ( v) => vec ! [ v. to_le_bytes( ) . to_vec( ) , v. to_be_bytes( ) . to_vec( ) ] ,
36+ V :: U64 ( v) => vec ! [ v. to_le_bytes( ) . to_vec( ) , v. to_be_bytes( ) . to_vec( ) ] ,
37+ V :: Bytes ( v) => vec ! [ v. to_vec( ) ] ,
38+ }
39+ }
40+ }
41+ let mut needles = Vec :: new ( ) ;
42+ match self {
43+ CmpLog :: U16 ( a, b) => {
44+ needles. push ( V :: U16 ( * a) ) ;
45+ needles. push ( V :: U16 ( * b) ) ;
46+ }
47+ CmpLog :: U32 ( a, b) => {
48+ needles. push ( V :: U32 ( * a) ) ;
49+ needles. push ( V :: U32 ( * b) ) ;
50+ }
51+ CmpLog :: U64 ( a, b) => {
52+ needles. push ( V :: U64 ( * a) ) ;
53+ needles. push ( V :: U64 ( * b) ) ;
54+ }
55+ CmpLog :: Memcmp ( a, b) => {
56+ needles. push ( V :: Bytes ( a) ) ;
57+ needles. push ( V :: Bytes ( b) ) ;
58+ }
59+ }
60+ let needles = needles
61+ . into_iter ( )
62+ . flat_map ( |x| x. to_needles ( ) )
63+ . collect :: < Vec < _ > > ( ) ;
64+ needles
65+ . iter ( )
66+ . any ( |needle| memchr:: memmem:: find ( input, needle) . is_some ( ) )
67+ }
68+ }
69+
70+ /// A state metadata holding a list of values logged from comparisons
71+ #[ derive( Debug , Default , serde:: Serialize , serde:: Deserialize ) ]
72+ pub struct CmplogStore {
73+ offsets : Vec < u32 > ,
74+ data : Vec < u8 > ,
75+ }
76+ libafl_bolts:: impl_serdeany!( CmplogStore ) ;
77+
78+ impl CmplogStore {
79+ pub fn new ( values : impl Iterator < Item = CmpLog > ) -> Self {
80+ let mut data = Vec :: new ( ) ;
81+ let mut offsets = Vec :: new ( ) ;
82+ for value in values {
83+ offsets. push ( data. len ( ) . try_into ( ) . unwrap ( ) ) ;
84+ let mut cursor = Cursor :: new ( & mut data) ;
85+ cursor. seek ( SeekFrom :: End ( 0 ) ) . unwrap ( ) ;
86+ value. write_to_stream ( cursor) . unwrap ( ) ;
87+ }
88+ Self { offsets, data }
89+ }
90+ pub fn get ( & self , idx : usize ) -> CmpLog {
91+ let pos = self . offsets [ idx] as usize ;
92+ CmpLog :: read_from_buffer ( & self . data [ pos..] ) . unwrap ( )
93+ }
94+ pub fn is_empty ( & self ) -> bool {
95+ self . offsets . is_empty ( )
96+ }
97+ pub fn len ( & self ) -> usize {
98+ self . offsets . len ( )
99+ }
100+ }
12101
13102/// A `I2SRandReplace` [`Mutator`] replaces a random matching input-2-state comparison operand with the other.
14103/// It needs a valid [`CmpValuesMetadata`] in the state.
@@ -33,15 +122,15 @@ where
33122 } ;
34123 let inp_testcase = state. corpus ( ) . get ( id) . unwrap ( ) ;
35124 let _meta = inp_testcase. borrow ( ) ;
36- let meta: & CmpValuesMetadata = match _meta. metadata :: < CmpValuesMetadata > ( ) . ok ( ) {
125+ let meta: & CmplogStore = match _meta. metadata :: < CmplogStore > ( ) . ok ( ) {
37126 Some ( meta) => meta,
38127 None => return Ok ( MutationResult :: Skipped ) ,
39128 } ;
40129
41- if meta. list . is_empty ( ) {
130+ if meta. is_empty ( ) {
42131 return Ok ( MutationResult :: Skipped ) ;
43132 }
44- meta. list . len ( ) . try_into ( ) . unwrap ( )
133+ meta. len ( ) . try_into ( ) . unwrap ( )
45134 } ;
46135 let idx = state. rand_mut ( ) . below ( cmps_len) ;
47136
@@ -54,136 +143,117 @@ where
54143 } ;
55144 let inp_testcase = state. corpus ( ) . get ( id) . unwrap ( ) ;
56145 let _meta = inp_testcase. borrow ( ) ;
57- let meta = match _meta. metadata :: < CmpValuesMetadata > ( ) . ok ( ) {
146+ let meta = match _meta. metadata :: < CmplogStore > ( ) . ok ( ) {
58147 Some ( meta) => meta,
59148 None => return Ok ( MutationResult :: Skipped ) ,
60149 } ;
61150
62- if meta. list . is_empty ( ) {
63- return Ok ( MutationResult :: Skipped ) ;
64- }
65-
66- let cmp_values = & meta. list [ idx] ;
151+ let cmp_values = & meta. get ( idx) ;
67152
68153 let mut result = MutationResult :: Skipped ;
69154 match cmp_values {
70- CmpValues :: U8 ( v) => {
71- for byte in bytes. iter_mut ( ) . take ( len) . skip ( off) {
72- if * byte == v. 0 {
73- * byte = v. 1 ;
74- result = MutationResult :: Mutated ;
75- break ;
76- } else if * byte == v. 1 {
77- * byte = v. 0 ;
78- result = MutationResult :: Mutated ;
79- break ;
80- }
81- }
82- }
83- CmpValues :: U16 ( v) => {
155+ & CmpLog :: U16 ( a, b) => {
84156 if len >= size_of :: < u16 > ( ) {
85157 for i in off..len - ( size_of :: < u16 > ( ) - 1 ) {
86158 let val =
87159 u16:: from_ne_bytes ( bytes[ i..i + size_of :: < u16 > ( ) ] . try_into ( ) . unwrap ( ) ) ;
88- if val == v . 0 {
89- let new_bytes = v . 1 . to_ne_bytes ( ) ;
160+ if val == a {
161+ let new_bytes = b . to_ne_bytes ( ) ;
90162 bytes[ i..i + size_of :: < u16 > ( ) ] . copy_from_slice ( & new_bytes) ;
91163 result = MutationResult :: Mutated ;
92164 break ;
93- } else if val. swap_bytes ( ) == v . 0 {
94- let new_bytes = v . 1 . swap_bytes ( ) . to_ne_bytes ( ) ;
165+ } else if val. swap_bytes ( ) == a {
166+ let new_bytes = b . swap_bytes ( ) . to_ne_bytes ( ) ;
95167 bytes[ i..i + size_of :: < u16 > ( ) ] . copy_from_slice ( & new_bytes) ;
96168 result = MutationResult :: Mutated ;
97169 break ;
98- } else if val == v . 1 {
99- let new_bytes = v . 0 . to_ne_bytes ( ) ;
170+ } else if val == b {
171+ let new_bytes = a . to_ne_bytes ( ) ;
100172 bytes[ i..i + size_of :: < u16 > ( ) ] . copy_from_slice ( & new_bytes) ;
101173 result = MutationResult :: Mutated ;
102174 break ;
103- } else if val. swap_bytes ( ) == v . 1 {
104- let new_bytes = v . 0 . swap_bytes ( ) . to_ne_bytes ( ) ;
175+ } else if val. swap_bytes ( ) == b {
176+ let new_bytes = a . swap_bytes ( ) . to_ne_bytes ( ) ;
105177 bytes[ i..i + size_of :: < u16 > ( ) ] . copy_from_slice ( & new_bytes) ;
106178 result = MutationResult :: Mutated ;
107179 break ;
108180 }
109181 }
110182 }
111183 }
112- CmpValues :: U32 ( v ) => {
184+ & CmpLog :: U32 ( a , b ) => {
113185 if len >= size_of :: < u32 > ( ) {
114186 for i in off..len - ( size_of :: < u32 > ( ) - 1 ) {
115187 let val =
116188 u32:: from_ne_bytes ( bytes[ i..i + size_of :: < u32 > ( ) ] . try_into ( ) . unwrap ( ) ) ;
117- if val == v . 0 {
118- let new_bytes = v . 1 . to_ne_bytes ( ) ;
189+ if val == a {
190+ let new_bytes = b . to_ne_bytes ( ) ;
119191 bytes[ i..i + size_of :: < u32 > ( ) ] . copy_from_slice ( & new_bytes) ;
120192 result = MutationResult :: Mutated ;
121193 break ;
122- } else if val. swap_bytes ( ) == v . 0 {
123- let new_bytes = v . 1 . swap_bytes ( ) . to_ne_bytes ( ) ;
194+ } else if val. swap_bytes ( ) == a {
195+ let new_bytes = b . swap_bytes ( ) . to_ne_bytes ( ) ;
124196 bytes[ i..i + size_of :: < u32 > ( ) ] . copy_from_slice ( & new_bytes) ;
125197 result = MutationResult :: Mutated ;
126198 break ;
127- } else if val == v . 1 {
128- let new_bytes = v . 0 . to_ne_bytes ( ) ;
199+ } else if val == b {
200+ let new_bytes = a . to_ne_bytes ( ) ;
129201 bytes[ i..i + size_of :: < u32 > ( ) ] . copy_from_slice ( & new_bytes) ;
130202 result = MutationResult :: Mutated ;
131203 break ;
132- } else if val. swap_bytes ( ) == v . 1 {
133- let new_bytes = v . 0 . swap_bytes ( ) . to_ne_bytes ( ) ;
204+ } else if val. swap_bytes ( ) == b {
205+ let new_bytes = a . swap_bytes ( ) . to_ne_bytes ( ) ;
134206 bytes[ i..i + size_of :: < u32 > ( ) ] . copy_from_slice ( & new_bytes) ;
135207 result = MutationResult :: Mutated ;
136208 break ;
137209 }
138210 }
139211 }
140212 }
141- CmpValues :: U64 ( v ) => {
213+ & CmpLog :: U64 ( a , b ) => {
142214 if len >= size_of :: < u64 > ( ) {
143215 for i in off..len - ( size_of :: < u64 > ( ) - 1 ) {
144216 let val =
145217 u64:: from_ne_bytes ( bytes[ i..i + size_of :: < u64 > ( ) ] . try_into ( ) . unwrap ( ) ) ;
146- if val == v . 0 {
147- let new_bytes = v . 1 . to_ne_bytes ( ) ;
218+ if val == a {
219+ let new_bytes = b . to_ne_bytes ( ) ;
148220 bytes[ i..i + size_of :: < u64 > ( ) ] . copy_from_slice ( & new_bytes) ;
149221 result = MutationResult :: Mutated ;
150222 break ;
151- } else if val. swap_bytes ( ) == v . 0 {
152- let new_bytes = v . 1 . swap_bytes ( ) . to_ne_bytes ( ) ;
223+ } else if val. swap_bytes ( ) == a {
224+ let new_bytes = b . swap_bytes ( ) . to_ne_bytes ( ) ;
153225 bytes[ i..i + size_of :: < u64 > ( ) ] . copy_from_slice ( & new_bytes) ;
154226 result = MutationResult :: Mutated ;
155227 break ;
156- } else if val == v . 1 {
157- let new_bytes = v . 0 . to_ne_bytes ( ) ;
228+ } else if val == b {
229+ let new_bytes = a . to_ne_bytes ( ) ;
158230 bytes[ i..i + size_of :: < u64 > ( ) ] . copy_from_slice ( & new_bytes) ;
159231 result = MutationResult :: Mutated ;
160232 break ;
161- } else if val. swap_bytes ( ) == v . 1 {
162- let new_bytes = v . 0 . swap_bytes ( ) . to_ne_bytes ( ) ;
233+ } else if val. swap_bytes ( ) == b {
234+ let new_bytes = a . swap_bytes ( ) . to_ne_bytes ( ) ;
163235 bytes[ i..i + size_of :: < u64 > ( ) ] . copy_from_slice ( & new_bytes) ;
164236 result = MutationResult :: Mutated ;
165237 break ;
166238 }
167239 }
168240 }
169241 }
170- CmpValues :: Bytes ( v ) => {
242+ CmpLog :: Memcmp ( a , b ) => {
171243 ' outer: for i in off..len {
172- let mut size = core:: cmp:: min ( v . 0 . len ( ) , len - i) ;
244+ let mut size = core:: cmp:: min ( a . len ( ) , len - i) ;
173245 while size != 0 {
174- if v. 0 . as_slice ( ) [ 0 ..size] == input. mutator_bytes ( ) [ i..i + size] {
175- input. mutator_bytes_mut ( ) [ i..i + size]
176- . copy_from_slice ( & v. 1 . as_slice ( ) [ 0 ..size] ) ;
246+ if & a[ 0 ..size] == & input. mutator_bytes ( ) [ i..i + size] {
247+ input. mutator_bytes_mut ( ) [ i..i + size] . copy_from_slice ( & b[ 0 ..size] ) ;
177248 result = MutationResult :: Mutated ;
178249 break ' outer;
179250 }
180251 size -= 1 ;
181252 }
182- size = core:: cmp:: min ( v . 1 . len ( ) , len - i) ;
253+ size = core:: cmp:: min ( b . len ( ) , len - i) ;
183254 while size != 0 {
184- if v. 1 . as_slice ( ) [ 0 ..size] == input. mutator_bytes ( ) [ i..i + size] {
185- input. mutator_bytes_mut ( ) [ i..i + size]
186- . copy_from_slice ( & v. 1 . as_slice ( ) [ 0 ..size] ) ;
255+ if & b[ 0 ..size] == & input. mutator_bytes ( ) [ i..i + size] {
256+ input. mutator_bytes_mut ( ) [ i..i + size] . copy_from_slice ( & b[ 0 ..size] ) ;
187257 result = MutationResult :: Mutated ;
188258 break ' outer;
189259 }
0 commit comments