Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unsound transmutes by making DataVariable and NameAndType into transparent representations #5301

Merged
merged 3 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions rust/examples/dwarf/dwarf_export/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,23 +551,23 @@ fn export_data_vars(
dwarf.unit.get_mut(var_die_uid).set(
gimli::DW_AT_name,
AttributeValue::String(
format!("data_{:x}", data_variable.address)
format!("data_{:x}", data_variable.address())
.as_bytes()
.to_vec(),
),
);
}

let mut variable_location = Expression::new();
variable_location.op_addr(Address::Constant(data_variable.address));
variable_location.op_addr(Address::Constant(data_variable.address()));
dwarf.unit.get_mut(var_die_uid).set(
gimli::DW_AT_location,
AttributeValue::Exprloc(variable_location),
);

if let Some(target_die_uid) = export_type(
format!("{}", data_variable.t.contents),
data_variable.t.contents.as_ref(),
format!("{}", data_variable.t()),
data_variable.t(),
bv,
defined_types,
dwarf,
Expand Down
6 changes: 3 additions & 3 deletions rust/examples/dwarf/shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ pub fn create_section_reader<'a, Endian: 'a + Endianity>(
if let Some(data_var) = view
.data_variables()
.iter()
.find(|var| var.address == symbol.address())
.find(|var| var.address() == symbol.address())
{
// TODO : This should eventually be wrapped by some DataView sorta thingy thing, like how python does it
let data_type = data_var.type_with_confidence().contents;
let data = view.read_vec(data_var.address, data_type.width() as usize);
let data_type = data_var.t();
let data = view.read_vec(data_var.address(), data_type.width() as usize);
let element_type = data_type.element_type().unwrap().contents;

if let Some(current_section_header) = data
Expand Down
10 changes: 5 additions & 5 deletions rust/src/architecture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ pub trait Intrinsic: Sized + Clone + Copy {
fn id(&self) -> u32;

/// Reeturns the list of the input names and types for this intrinsic.
fn inputs(&self) -> Vec<NameAndType<String>>;
fn inputs(&self) -> Vec<Ref<NameAndType>>;

/// Returns the list of the output types for this intrinsic.
fn outputs(&self) -> Vec<Conf<Ref<Type>>>;
Expand Down Expand Up @@ -650,7 +650,7 @@ impl Intrinsic for UnusedIntrinsic {
fn id(&self) -> u32 {
unreachable!()
}
fn inputs(&self) -> Vec<NameAndType<String>> {
fn inputs(&self) -> Vec<Ref<NameAndType>> {
unreachable!()
}
fn outputs(&self) -> Vec<Conf<Ref<Type>>> {
Expand Down Expand Up @@ -992,7 +992,7 @@ impl Intrinsic for crate::architecture::CoreIntrinsic {
self.1
}

fn inputs(&self) -> Vec<NameAndType<String>> {
fn inputs(&self) -> Vec<Ref<NameAndType>> {
let mut count: usize = 0;

unsafe {
Expand Down Expand Up @@ -1172,7 +1172,7 @@ impl Architecture for CoreArchitecture {
}
}
}

fn instruction_llil(
&self,
data: &[u8],
Expand Down Expand Up @@ -2424,7 +2424,7 @@ where
let inputs = intrinsic.inputs();
let mut res = Vec::with_capacity(inputs.len());
for input in inputs {
res.push(input.into_raw());
res.push(unsafe { Ref::into_raw(input) }.into_raw());
}

unsafe {
Expand Down
16 changes: 12 additions & 4 deletions rust/src/binaryview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,16 +574,24 @@ pub trait BinaryViewExt: BinaryViewBase {
}
}

fn define_auto_data_var(&self, dv: DataVariable) {
fn define_auto_data_var(&self, dv: &DataVariable) {
unsafe {
BNDefineDataVariable(self.as_ref().handle, dv.address, &mut dv.t.into());
BNDefineDataVariable(
self.as_ref().handle,
dv.address(),
&mut dv.type_with_confidence().into(),
);
}
}

/// You likely would also like to call [`Self::define_user_symbol`] to bind this data variable with a name
fn define_user_data_var(&self, dv: DataVariable) {
fn define_user_data_var(&self, dv: &DataVariable) {
unsafe {
BNDefineUserDataVariable(self.as_ref().handle, dv.address, &mut dv.t.into());
BNDefineUserDataVariable(
self.as_ref().handle,
dv.address(),
&mut dv.type_with_confidence().into(),
);
}
}

Expand Down
12 changes: 6 additions & 6 deletions rust/src/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ impl DebugInfo {
}

/// Returns a generator of all types provided by a named DebugInfoParser
pub fn types_by_name<S: BnStrCompatible>(&self, parser_name: S) -> Vec<NameAndType<String>> {
pub fn types_by_name<S: BnStrCompatible>(&self, parser_name: S) -> Vec<Ref<NameAndType>> {
let parser_name = parser_name.into_bytes_with_nul();

let mut count: usize = 0;
Expand All @@ -387,10 +387,10 @@ impl DebugInfo {
&mut count,
)
};
let result: Vec<NameAndType<String>> = unsafe {
let result: Vec<Ref<NameAndType>> = unsafe {
slice::from_raw_parts_mut(debug_types_ptr, count)
.iter()
.map(NameAndType::<String>::from_raw)
.map(NameAndType::from_raw)
.collect()
};

Expand All @@ -399,13 +399,13 @@ impl DebugInfo {
}

/// A generator of all types provided by DebugInfoParsers
pub fn types(&self) -> Vec<NameAndType<String>> {
pub fn types(&self) -> Vec<Ref<NameAndType>> {
let mut count: usize = 0;
let debug_types_ptr = unsafe { BNGetDebugTypes(self.handle, ptr::null_mut(), &mut count) };
let result: Vec<NameAndType<String>> = unsafe {
let result: Vec<Ref<NameAndType>> = unsafe {
slice::from_raw_parts_mut(debug_types_ptr, count)
.iter()
.map(NameAndType::<String>::from_raw)
.map(NameAndType::from_raw)
.collect()
};

Expand Down
138 changes: 100 additions & 38 deletions rust/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub type MemberScope = BNMemberScope;
////////////////
// Confidence

/// Compatible with the `BNType*WithConfidence` types
pub struct Conf<T> {
pub contents: T,
pub confidence: u8,
Expand Down Expand Up @@ -698,6 +699,7 @@ impl Drop for TypeBuilder {
//////////
// Type

#[repr(transparent)]
pub struct Type {
pub(crate) handle: *mut BNType,
}
Expand Down Expand Up @@ -2447,13 +2449,11 @@ unsafe impl<'a> CoreArrayWrapper<'a> for QualifiedNameTypeAndId {
//////////////////////////
// NameAndType

pub struct NameAndType<S: BnStrCompatible> {
pub name: S,
pub t: Conf<Ref<Type>>,
}
#[repr(transparent)]
pub struct NameAndType(pub(crate) BNNameAndType);

impl NameAndType<String> {
pub(crate) fn from_raw(raw: &BNNameAndType) -> Self {
impl NameAndType {
pub(crate) fn from_raw(raw: &BNNameAndType) -> Ref<Self> {
Self::new(
raw_to_string(raw.name).unwrap(),
unsafe { &Type::ref_from_raw(raw.type_) },
Expand All @@ -2462,43 +2462,73 @@ impl NameAndType<String> {
}
}

impl<S: BnStrCompatible> NameAndType<S> {
pub fn new(name: S, t: &Ref<Type>, confidence: u8) -> Self {
Self {
name,
t: Conf::new(t.clone(), confidence),
impl NameAndType {
pub fn new<S: BnStrCompatible>(name: S, t: &Type, confidence: u8) -> Ref<Self> {
unsafe {
Ref::new(Self(BNNameAndType {
name: BNAllocString(name.into_bytes_with_nul().as_ref().as_ptr() as *mut _),
type_: Ref::into_raw(t.to_owned()).handle,
typeConfidence: confidence,
}))
}
}

pub(crate) fn into_raw(self) -> BNNameAndType {
let t = self.t.clone();
let res = BNNameAndType {
name: BnString::new(self.name).into_raw(),
type_: t.contents.handle,
typeConfidence: self.t.confidence,
};
mem::forget(t);
res
self.0
}

pub fn type_with_confidence(&self) -> Conf<Ref<Type>> {
self.t.clone()
pub fn name(&self) -> &str {
let c_str = unsafe { CStr::from_ptr(self.0.name) };
c_str.to_str().unwrap()
}

pub fn t(&self) -> &Type {
unsafe { mem::transmute::<_, &Type>(&self.0.type_) }
}

pub fn type_with_confidence(&self) -> Conf<&Type> {
Conf::new(self.t(), self.0.typeConfidence)
}
}

impl ToOwned for NameAndType {
type Owned = Ref<Self>;

fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}

unsafe impl RefCountable for NameAndType {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
Self::new(
CStr::from_ptr(handle.0.name),
handle.t(),
handle.type_with_confidence().confidence,
)
}

unsafe fn dec_ref(handle: &Self) {
unsafe {
BNFreeString(handle.0.name);
RefCountable::dec_ref(handle.t());
}
}
}

impl<S: BnStrCompatible> CoreArrayProvider for NameAndType<S> {
impl CoreArrayProvider for NameAndType {
type Raw = BNNameAndType;
type Context = ();
}

unsafe impl<S: BnStrCompatible> CoreOwnedArrayProvider for NameAndType<S> {
unsafe impl CoreOwnedArrayProvider for NameAndType {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
BNFreeNameAndTypeList(raw, count);
}
}

unsafe impl<'a, S: 'a + BnStrCompatible> CoreArrayWrapper<'a> for NameAndType<S> {
type Wrapped = &'a NameAndType<S>;
unsafe impl<'a> CoreArrayWrapper<'a> for NameAndType {
type Wrapped = &'a NameAndType;

unsafe fn wrap_raw(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped {
mem::transmute(raw)
Expand All @@ -2508,29 +2538,61 @@ unsafe impl<'a, S: 'a + BnStrCompatible> CoreArrayWrapper<'a> for NameAndType<S>
//////////////////
// DataVariable

pub struct DataVariable {
pub address: u64,
pub t: Conf<Ref<Type>>,
pub auto_discovered: bool,
}
#[repr(transparent)]
pub struct DataVariable(pub(crate) BNDataVariable);

// impl DataVariable {
// pub(crate) fn from_raw(var: &BNDataVariable) -> Self {
// Self {
// address: var.address,
// t: Conf::new(unsafe { Type::ref_from_raw(var.type_) }, var.typeConfidence),
// auto_discovered: var.autoDiscovered,
// }
// let var = DataVariable(*var);
// Self(BNDataVariable {
// type_: unsafe { Ref::into_raw(var.t().to_owned()).handle },
// ..var.0
// })
// }
// }

impl DataVariable {
pub fn type_with_confidence(&self) -> Conf<Ref<Type>> {
Conf::new(self.t.contents.clone(), self.t.confidence)
pub fn address(&self) -> u64 {
self.0.address
}

pub fn auto_discovered(&self) -> bool {
self.0.autoDiscovered
}

pub fn t(&self) -> &Type {
unsafe { mem::transmute(&self.0.type_) }
}

pub fn type_with_confidence(&self) -> Conf<&Type> {
Conf::new(self.t(), self.0.typeConfidence)
}

pub fn symbol(&self, bv: &BinaryView) -> Option<Ref<Symbol>> {
bv.symbol_by_address(self.address).ok()
bv.symbol_by_address(self.0.address).ok()
}
}

impl ToOwned for DataVariable {
type Owned = Ref<Self>;

fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}

unsafe impl RefCountable for DataVariable {
unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
unsafe {
Ref::new(Self(BNDataVariable {
type_: Ref::into_raw(handle.t().to_owned()).handle,
..handle.0
}))
}
}

unsafe fn dec_ref(handle: &Self) {
unsafe { BNFreeType(handle.0.type_) }
}
}

Expand Down
Loading