|
@@ -210,6 +210,11 @@ impl Btf {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ pub(crate) fn is_empty(&self) -> bool {
|
|
|
+ // the first one is awlays BtfType::Unknown
|
|
|
+ self.types.types.len() < 2
|
|
|
+ }
|
|
|
+
|
|
|
pub(crate) fn types(&self) -> impl Iterator<Item = &BtfType> {
|
|
|
self.types.types.iter()
|
|
|
}
|
|
@@ -628,7 +633,10 @@ impl Object {
|
|
|
&mut self,
|
|
|
features: &BtfFeatures,
|
|
|
) -> Result<Option<&Btf>, BtfError> {
|
|
|
- if let Some(ref mut obj_btf) = self.btf {
|
|
|
+ if let Some(ref mut obj_btf) = &mut self.btf {
|
|
|
+ if obj_btf.is_empty() {
|
|
|
+ return Ok(None);
|
|
|
+ }
|
|
|
// fixup btf
|
|
|
obj_btf.fixup_and_sanitize(
|
|
|
&self.section_sizes,
|
|
@@ -667,13 +675,65 @@ impl BtfExt {
|
|
|
endianness: Endianness,
|
|
|
btf: &Btf,
|
|
|
) -> Result<BtfExt, BtfError> {
|
|
|
- // Safety: btf_ext_header is POD so read_unaligned is safe
|
|
|
- let header = unsafe {
|
|
|
- ptr::read_unaligned::<btf_ext_header>(data.as_ptr() as *const btf_ext_header)
|
|
|
+ #[repr(C)]
|
|
|
+ #[derive(Debug, Copy, Clone)]
|
|
|
+ struct MinimalHeader {
|
|
|
+ pub magic: u16,
|
|
|
+ pub version: u8,
|
|
|
+ pub flags: u8,
|
|
|
+ pub hdr_len: u32,
|
|
|
+ }
|
|
|
+
|
|
|
+ if data.len() < std::mem::size_of::<MinimalHeader>() {
|
|
|
+ return Err(BtfError::InvalidHeader);
|
|
|
+ }
|
|
|
+
|
|
|
+ let header = {
|
|
|
+ // first find the actual size of the header by converting into the minimal valid header
|
|
|
+ // Safety: MinimalHeader is POD so read_unaligned is safe
|
|
|
+ let minimal_header = unsafe {
|
|
|
+ ptr::read_unaligned::<MinimalHeader>(data.as_ptr() as *const MinimalHeader)
|
|
|
+ };
|
|
|
+
|
|
|
+ let len_to_read = minimal_header.hdr_len as usize;
|
|
|
+
|
|
|
+ // prevent invalid input from causing UB
|
|
|
+ if data.len() < len_to_read {
|
|
|
+ return Err(BtfError::InvalidHeader);
|
|
|
+ }
|
|
|
+
|
|
|
+ // forwards compatibility: if newer headers are bigger
|
|
|
+ // than the pre-generated btf_ext_header we should only
|
|
|
+ // read up to btf_ext_header
|
|
|
+ let len_to_read = len_to_read.min(std::mem::size_of::<btf_ext_header>());
|
|
|
+
|
|
|
+ // now create our full-fledge header; but start with it
|
|
|
+ // zeroed out so unavailable fields stay as zero on older
|
|
|
+ // BTF.ext sections
|
|
|
+ let mut header = std::mem::MaybeUninit::<btf_ext_header>::zeroed();
|
|
|
+ // Safety: we have checked that len_to_read is less than
|
|
|
+ // size_of::<btf_ext_header> and less than
|
|
|
+ // data.len(). Additionally, we know that the header has
|
|
|
+ // been initialized so it's safe to call for assume_init.
|
|
|
+ unsafe {
|
|
|
+ std::ptr::copy(data.as_ptr(), header.as_mut_ptr() as *mut u8, len_to_read);
|
|
|
+ header.assume_init()
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
+ let btf_ext_header {
|
|
|
+ hdr_len,
|
|
|
+ func_info_off,
|
|
|
+ func_info_len,
|
|
|
+ line_info_off,
|
|
|
+ line_info_len,
|
|
|
+ core_relo_off,
|
|
|
+ core_relo_len,
|
|
|
+ ..
|
|
|
+ } = header;
|
|
|
+
|
|
|
let rec_size = |offset, len| {
|
|
|
- let offset = mem::size_of::<btf_ext_header>() + offset as usize;
|
|
|
+ let offset = hdr_len as usize + offset as usize;
|
|
|
let len = len as usize;
|
|
|
// check that there's at least enough space for the `rec_size` field
|
|
|
if (len > 0 && len < 4) || offset + len > data.len() {
|
|
@@ -695,16 +755,6 @@ impl BtfExt {
|
|
|
})
|
|
|
};
|
|
|
|
|
|
- let btf_ext_header {
|
|
|
- func_info_off,
|
|
|
- func_info_len,
|
|
|
- line_info_off,
|
|
|
- line_info_len,
|
|
|
- core_relo_off,
|
|
|
- core_relo_len,
|
|
|
- ..
|
|
|
- } = header;
|
|
|
-
|
|
|
let mut ext = BtfExt {
|
|
|
header,
|
|
|
relocations: Vec::new(),
|
|
@@ -1039,6 +1089,21 @@ mod tests {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ #[test]
|
|
|
+ fn parsing_older_ext_data() {
|
|
|
+ let btf_data = [
|
|
|
+ 159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
|
|
+ ];
|
|
|
+ let btf_ext_data = [
|
|
|
+ 159, 235, 1, 0, 24, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0,
|
|
|
+ 0, 16, 0, 0, 0,
|
|
|
+ ];
|
|
|
+ let btf = Btf::parse(&btf_data, Endianness::default()).unwrap();
|
|
|
+ let btf_ext = BtfExt::parse(&btf_ext_data, Endianness::default(), &btf).unwrap();
|
|
|
+ assert_eq!(btf_ext.func_info_rec_size(), 8);
|
|
|
+ assert_eq!(btf_ext.line_info_rec_size(), 16);
|
|
|
+ }
|
|
|
+
|
|
|
#[test]
|
|
|
fn test_write_btf() {
|
|
|
let mut btf = Btf::new();
|