Skip to content

Commit

Permalink
Fix: checking flags before reading union data
Browse files Browse the repository at this point in the history
  • Loading branch information
daladim committed Nov 15, 2022
1 parent e72362e commit 1a284c1
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/native/tdh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ impl<'info> PropertyIterator<'info> {
}

impl<'info> Iterator for PropertyIterator<'info> {
type Item = Property;
type Item = Result<Property, crate::native::tdh_types::PropertyError>;

fn next(&mut self) -> Option<Self::Item> {
if self.next_index == self.count {
Expand Down
42 changes: 33 additions & 9 deletions src/native/tdh_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ use num_traits::FromPrimitive;

use windows::Win32::System::Diagnostics::Etw;

#[derive(Debug)]
pub enum PropertyError{
/// Parsing complex types in properties is not supported in this crate
/// (yet? See <https://github.com/n4r1b/ferrisetw/issues/76>)
UnimplementedType
}


/// Attributes of a property
#[derive(Debug, Clone, Default)]
Expand All @@ -30,23 +37,40 @@ pub struct Property {

#[doc(hidden)]
impl Property {
pub fn new(name: String, property: &Etw::EVENT_PROPERTY_INFO) -> Self {
// Fixme: Check flags to see which values to get for the in_type
unsafe {
let out_type = FromPrimitive::from_u16(property.Anonymous1.nonStructType.OutType)
pub fn new(name: String, property: &Etw::EVENT_PROPERTY_INFO) -> Result<Self, PropertyError> {
let flags = PropertyFlags::from(property.Flags);

if flags.contains(PropertyFlags::PROPERTY_STRUCT) == false {
// The property is a non-struct type. It makes sense to access these fields of the unions
let ot = unsafe { property.Anonymous1.nonStructType.OutType };
let it = unsafe { property.Anonymous1.nonStructType.InType };

let length = if flags.contains(PropertyFlags::PROPERTY_PARAM_LENGTH) {
// TODO: support properties that point at sibling property to tell the length of the property
return Err(PropertyError::UnimplementedType);
} else {
// The property has no param for its length, it makes sense to access this field of the union
unsafe { property.Anonymous3.length }
};

let out_type = FromPrimitive::from_u16(ot)
.unwrap_or(TdhOutType::OutTypeNull);
let in_type = FromPrimitive::from_u16(property.Anonymous1.nonStructType.InType)

let in_type = FromPrimitive::from_u16(it)
.unwrap_or(TdhInType::InTypeNull);

Property {
return Ok(Property {
name,
flags: PropertyFlags::from(property.Flags),
length: property.Anonymous3.length,
flags,
length,
in_type,
out_type,
}
});
}

Err(PropertyError::UnimplementedType)
}

pub fn in_type(&self) -> TdhInType {
self.in_type
}
Expand Down
4 changes: 3 additions & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ use windows::core::GUID;
pub enum ParserError {
/// No property has this name
NotFound,
/// An invalid type...
/// An invalid type
InvalidType,
/// Some properties are not supported by this crate (yet?)
UnsupportedProperties,
/// Error parsing
ParseError,
/// Length mismatch when parsing a type
Expand Down
22 changes: 17 additions & 5 deletions src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! This module contains the means needed to interact with the Schema of an ETW event
use crate::native::etw_types::DecodingSource;
use crate::native::tdh::TraceEventInfo;
use crate::native::tdh_types::Property;
use crate::native::tdh_types::{Property, PropertyError};
use once_cell::sync::OnceCell;

/// A schema suitable for parsing a given kind of event.
Expand All @@ -14,7 +14,7 @@ use once_cell::sync::OnceCell;
/// with a few info parsed (and cached) out of it
pub struct Schema {
te_info: TraceEventInfo,
cached_properties: OnceCell<Vec<Property>>,
cached_properties: OnceCell<Result<Vec<Property>, PropertyError>>,
}

impl Schema {
Expand Down Expand Up @@ -99,9 +99,21 @@ impl Schema {
///
/// This is parsed on first call, and cached for later use
pub(crate) fn properties(&self) -> &[Property] {
self.cached_properties.get_or_init(|| {
self.te_info.properties().collect()
})
let cache = self.cached_properties.get_or_init(|| {
let mut cache = Vec::new();
for property in self.te_info.properties() {
cache.push(property?)
}
Ok(cache)
});

match cache {
Err(PropertyError::UnimplementedType) => {
log::error!("Unable to list properties: a type is not implemented");
&[]
}
Ok(cache) => cache.as_slice()
}
}
}

Expand Down

0 comments on commit 1a284c1

Please sign in to comment.