Skip to content

Commit f70a16a

Browse files
authored
Fix unsoundness for misaligned map observers (#1530)
* Fix unsoundness for misaligned map observers * nits * clippy * Make sure beginning of the page is aligned
1 parent 761a77f commit f70a16a

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

libafl/src/observers/map.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use core::{
99
hash::{BuildHasher, Hasher},
1010
iter::Flatten,
1111
marker::PhantomData,
12-
slice::{from_raw_parts, Iter, IterMut},
12+
mem::size_of,
13+
slice::{self, Iter, IterMut},
1314
};
1415

1516
use ahash::RandomState;
@@ -72,9 +73,9 @@ fn init_count_class_16() {
7273
fn hash_slice<T>(slice: &[T]) -> u64 {
7374
let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher();
7475
let ptr = slice.as_ptr() as *const u8;
75-
let map_size = slice.len() / core::mem::size_of::<T>();
76+
let map_size = slice.len() / size_of::<T>();
7677
unsafe {
77-
hasher.write(from_raw_parts(ptr, map_size));
78+
hasher.write(slice::from_raw_parts(ptr, map_size));
7879
}
7980
hasher.finish()
8081
}
@@ -1234,7 +1235,23 @@ where
12341235
exit_kind: &ExitKind,
12351236
) -> Result<(), Error> {
12361237
let map = self.as_mut_slice();
1237-
let len = map.len();
1238+
let mut len = map.len();
1239+
let align_offset = map.as_ptr().align_offset(size_of::<u16>());
1240+
1241+
// if len == 1, the next branch will already do this lookup
1242+
if len > 1 && align_offset != 0 {
1243+
debug_assert_eq!(
1244+
align_offset, 1,
1245+
"Aligning u8 to u16 should always be offset of 1?"
1246+
);
1247+
unsafe {
1248+
*map.get_unchecked_mut(0) =
1249+
*COUNT_CLASS_LOOKUP.get_unchecked(*map.get_unchecked(0) as usize);
1250+
}
1251+
len -= 1;
1252+
}
1253+
1254+
// Fix the last element
12381255
if (len & 1) != 0 {
12391256
unsafe {
12401257
*map.get_unchecked_mut(len - 1) =
@@ -1243,13 +1260,17 @@ where
12431260
}
12441261

12451262
let cnt = len / 2;
1246-
let map16 = unsafe { core::slice::from_raw_parts_mut(map.as_mut_ptr() as *mut u16, cnt) };
1263+
1264+
let map16 = unsafe {
1265+
slice::from_raw_parts_mut(map.as_mut_ptr().add(align_offset) as *mut u16, cnt)
1266+
};
12471267
// 2022-07: Adding `enumerate` here increases execution speed/register allocation on x86_64.
12481268
for (_i, item) in map16[0..cnt].iter_mut().enumerate() {
12491269
unsafe {
12501270
*item = *COUNT_CLASS_LOOKUP_16.get_unchecked(*item as usize);
12511271
}
12521272
}
1273+
12531274
self.base.post_exec(state, input, exit_kind)
12541275
}
12551276
}
@@ -1776,9 +1797,9 @@ where
17761797
for map in &self.maps {
17771798
let slice = map.as_slice();
17781799
let ptr = slice.as_ptr() as *const u8;
1779-
let map_size = slice.len() / core::mem::size_of::<T>();
1800+
let map_size = slice.len() / size_of::<T>();
17801801
unsafe {
1781-
hasher.write(from_raw_parts(ptr, map_size));
1802+
hasher.write(slice::from_raw_parts(ptr, map_size));
17821803
}
17831804
}
17841805
hasher.finish()

libafl_bolts/src/staterestore.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ where
214214

215215
fn content_mut(&mut self) -> &mut StateShMemContent {
216216
let ptr = self.shmem.as_slice().as_ptr();
217+
debug_assert_eq!(
218+
ptr.align_offset(size_of::<StateShMemContent>()),
219+
0,
220+
"Beginning of the page is not aligned at {ptr:?}!"
221+
);
217222
#[allow(clippy::cast_ptr_alignment)] // Beginning of the page will always be aligned
218223
unsafe {
219224
&mut *(ptr as *mut StateShMemContent)

0 commit comments

Comments
 (0)