Skip to content

Commit

Permalink
fix: Wrap uc_hook to not expose ffi types in public api
Browse files Browse the repository at this point in the history
  • Loading branch information
mlgiraud committed Aug 14, 2023
1 parent 19a794b commit bb7df65
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 56 deletions.
1 change: 1 addition & 0 deletions bindings/rust/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use core::ffi::c_void;
use libc::{c_char, c_int};

pub type uc_handle = *mut c_void;
// TODO: Use c_size_t as soon as it is stable. The c api exposes uc_hook as size_t
pub type uc_hook = *mut c_void;
pub type uc_context = *mut c_void;

Expand Down
124 changes: 68 additions & 56 deletions bindings/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub use crate::{

use alloc::{boxed::Box, rc::Rc, vec::Vec};
use core::{cell::UnsafeCell, ptr};
use bitflags::Flags;
use ffi::uc_handle;
use libc::c_void;

Expand Down Expand Up @@ -130,12 +131,15 @@ impl<'a> MmioCallbackScope<'a> {
}
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct UcHookId(ffi::uc_hook);

pub struct UnicornInner<'a, D> {
pub handle: uc_handle,
pub ffi: bool,
pub arch: Arch,
/// to keep ownership over the hook for this uc instance's lifetime
pub hooks: Vec<(ffi::uc_hook, Box<dyn ffi::IsUcHook<'a> + 'a>)>,
pub hooks: Vec<(UcHookId, Box<dyn ffi::IsUcHook<'a> + 'a>)>,
/// To keep ownership over the mmio callbacks for this uc instance's lifetime
pub mmio_callbacks: Vec<MmioCallbackScope<'a>>,
pub data: D,
Expand Down Expand Up @@ -620,11 +624,11 @@ impl<'a, D> Unicorn<'a, D> {
begin: u64,
end: u64,
callback: F,
) -> Result<ffi::uc_hook, uc_error>
) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut crate::Unicorn<D>, u64, u32) + 'a,
{
let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
Expand All @@ -633,28 +637,29 @@ impl<'a, D> Unicorn<'a, D> {
let err = unsafe {
ffi::uc_hook_add(
self.get_handle(),
&mut hook_ptr,
&mut hook_id,
HookType::CODE,
ffi::code_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
begin,
end,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
self.inner_mut().hooks.push((hook_id, user_data));
Ok(hook_id)
} else {
Err(err)
}
}

/// Add a block hook.
pub fn add_block_hook<F: 'a>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
pub fn add_block_hook<F: 'a>(&mut self, callback: F) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut Unicorn<D>, u64, u32),
{
let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
Expand All @@ -663,18 +668,19 @@ impl<'a, D> Unicorn<'a, D> {
let err = unsafe {
ffi::uc_hook_add(
self.get_handle(),
&mut hook_ptr,
&mut hook_id,
HookType::BLOCK,
ffi::block_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
1,
0,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_id, user_data));

Ok(hook_ptr)
Ok(hook_id)
} else {
Err(err)
}
Expand All @@ -687,15 +693,15 @@ impl<'a, D> Unicorn<'a, D> {
begin: u64,
end: u64,
callback: F,
) -> Result<ffi::uc_hook, uc_error>
) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut Unicorn<D>, MemType, u64, usize, i64) -> bool,
{
if !(HookType::MEM_ALL | HookType::MEM_READ_AFTER).contains(hook_type) {
return Err(uc_error::ARG);
}

let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
Expand All @@ -704,29 +710,30 @@ impl<'a, D> Unicorn<'a, D> {
let err = unsafe {
ffi::uc_hook_add(
self.get_handle(),
&mut hook_ptr,
&mut hook_id,
hook_type,
ffi::mem_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
begin,
end,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_id, user_data));

Ok(hook_ptr)
Ok(hook_id)
} else {
Err(err)
}
}

/// Add an interrupt hook.
pub fn add_intr_hook<F: 'a>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
pub fn add_intr_hook<F: 'a>(&mut self, callback: F) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut Unicorn<D>, u32),
{
let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
Expand All @@ -735,29 +742,30 @@ impl<'a, D> Unicorn<'a, D> {
let err = unsafe {
ffi::uc_hook_add(
self.get_handle(),
&mut hook_ptr,
&mut hook_id,
HookType::INTR,
ffi::intr_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
0,
0,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_id, user_data));

Ok(hook_ptr)
Ok(hook_id)
} else {
Err(err)
}
}

/// Add hook for invalid instructions
pub fn add_insn_invalid_hook<F: 'a>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
pub fn add_insn_invalid_hook<F: 'a>(&mut self, callback: F) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut Unicorn<D>) -> bool,
{
let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
Expand All @@ -766,29 +774,30 @@ impl<'a, D> Unicorn<'a, D> {
let err = unsafe {
ffi::uc_hook_add(
self.get_handle(),
&mut hook_ptr,
&mut hook_id,
HookType::INSN_INVALID,
ffi::insn_invalid_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
0,
0,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_id, user_data));

Ok(hook_ptr)
Ok(hook_id)
} else {
Err(err)
}
}

/// Add hook for x86 IN instruction.
pub fn add_insn_in_hook<F: 'a>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
pub fn add_insn_in_hook<F: 'a>(&mut self, callback: F) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut Unicorn<D>, u32, usize) -> u32,
{
let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
Expand All @@ -797,7 +806,7 @@ impl<'a, D> Unicorn<'a, D> {
let err = unsafe {
ffi::uc_hook_add(
self.get_handle(),
&mut hook_ptr,
&mut hook_id,
HookType::INSN,
ffi::insn_in_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
Expand All @@ -806,21 +815,22 @@ impl<'a, D> Unicorn<'a, D> {
x86::InsnX86::IN,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_id, user_data));

Ok(hook_ptr)
Ok(hook_id)
} else {
Err(err)
}
}

/// Add hook for x86 OUT instruction.
pub fn add_insn_out_hook<F: 'a>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
pub fn add_insn_out_hook<F: 'a>(&mut self, callback: F) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut Unicorn<D>, u32, usize, u32),
{
let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
Expand All @@ -829,7 +839,7 @@ impl<'a, D> Unicorn<'a, D> {
let err = unsafe {
ffi::uc_hook_add(
self.get_handle(),
&mut hook_ptr,
&mut hook_id,
HookType::INSN,
ffi::insn_out_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
Expand All @@ -838,10 +848,11 @@ impl<'a, D> Unicorn<'a, D> {
x86::InsnX86::OUT,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_id, user_data));

Ok(hook_ptr)
Ok(hook_id)
} else {
Err(err)
}
Expand All @@ -854,11 +865,11 @@ impl<'a, D> Unicorn<'a, D> {
begin: u64,
end: u64,
callback: F,
) -> Result<ffi::uc_hook, uc_error>
) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut Unicorn<D>) + 'a,
{
let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
Expand All @@ -867,7 +878,7 @@ impl<'a, D> Unicorn<'a, D> {
let err = unsafe {
ffi::uc_hook_add(
self.get_handle(),
&mut hook_ptr,
&mut hook_id,
HookType::INSN,
ffi::insn_sys_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
Expand All @@ -876,54 +887,55 @@ impl<'a, D> Unicorn<'a, D> {
insn_type,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_id, user_data));

Ok(hook_ptr)
Ok(hook_id)
} else {
Err(err)
}
}

pub fn add_tlb_hook<F>(&mut self, begin: u64, end: u64, callback: F) -> Result<ffi::uc_hook, uc_error>
pub fn add_tlb_hook<F>(&mut self, begin: u64, end: u64, callback: F) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut crate::Unicorn<D>, u64, MemType) -> Option<TlbEntry> + 'a,
{
let mut hook_ptr = core::ptr::null_mut();
let mut hook_id = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {
ffi::uc_hook_add(self.get_handle(),
&mut hook_ptr,
HookType::TLB,
ffi::tlb_lookup_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
begin,
end,
&mut hook_id,
HookType::TLB,
ffi::tlb_lookup_hook_proxy::<D, F> as _,
user_data.as_mut() as *mut _ as _,
begin,
end,
)
};
let hook_id = UcHookId(hook_id);
if err == uc_error::OK {
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
self.inner_mut().hooks.push((hook_id, user_data));
Ok(hook_id)
} else {
Err(err)
}
}

/// Remove a hook.
///
/// `hook` is the value returned by `add_*_hook` functions.
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn remove_hook(&mut self, hook: ffi::uc_hook) -> Result<(), uc_error> {
/// `hook_id` is the value returned by `add_*_hook` functions.
pub fn remove_hook(&mut self, hook_id: UcHookId) -> Result<(), uc_error> {
// drop the hook
let inner = self.inner_mut();
inner
.hooks
.retain(|(hook_ptr, _hook_impl)| hook_ptr != &hook);
.retain(|(id, _)| id != &hook_id);

let err: uc_error = unsafe { ffi::uc_hook_del(inner.handle, hook) };
let err: uc_error = unsafe { ffi::uc_hook_del(inner.handle, hook_id.0) };

if err == uc_error::OK {
Ok(())
Expand Down

0 comments on commit bb7df65

Please sign in to comment.