From 825bb3ad2044e186f873acbbb0a53de8d2b6e6cc Mon Sep 17 00:00:00 2001 From: Dave Tucker Date: Tue, 18 Jan 2022 21:09:53 +0000 Subject: [PATCH] btf: Replace / in DATASEC before load to kernel This replaces the / character with a . which is allowed in the kernel names. Not allowing a forward slash is perhaps a kernel bug, but lets fix it up here as it's commonly used for Aya Signed-off-by: Dave Tucker --- aya/src/obj/btf/btf.rs | 104 ++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/aya/src/obj/btf/btf.rs b/aya/src/obj/btf/btf.rs index 0caf6006..f60c9d7d 100644 --- a/aya/src/obj/btf/btf.rs +++ b/aya/src/obj/btf/btf.rs @@ -453,57 +453,64 @@ impl Btf { // Start DataSec Fixups let sec_name = self.string_at(ty.name_off)?; let name = sec_name.to_string(); - // There are some cases when the compiler does indeed populate the - // size - if unsafe { ty.__bindgen_anon_1.size > 0 } { - debug!("{} {}: fixup not required", kind, name); - continue; - } let mut fixed_ty = *ty; let mut fixed_data = data.clone(); - // We need to get the size of the section from the ELF file - // Fortunately, we cached these when parsing it initially - // and we can this up by name in section_sizes - let size = - section_sizes - .get(&name) - .ok_or_else(|| BtfError::UnknownSectionSize { + + // Handle any "/" characters in section names + // Example: "maps/hashmap" + let fixed_name = name.replace('/', "."); + if fixed_name != name { + fixed_ty.name_off = self.add_string(fixed_name); + } + + // There are some cases when the compiler does indeed populate the + // size + if unsafe { ty.__bindgen_anon_1.size > 0 } { + debug!("{} {}: size fixup not required", kind, name); + } else { + // We need to get the size of the section from the ELF file + // Fortunately, we cached these when parsing it initially + // and we can this up by name in section_sizes + let size = section_sizes.get(&name).ok_or_else(|| { + BtfError::UnknownSectionSize { section_name: name.clone(), - })?; - debug!("{} {}: fixup size to {}", kind, name, size); - fixed_ty.__bindgen_anon_1.size = *size as u32; - - // The Vec contains BTF_KIND_VAR sections - // that need to have their offsets adjusted. To do this, - // we need to get the offset from the ELF file. - // This was also cached during initial parsing and - // we can query by name in symbol_offsets - for d in &mut fixed_data { - let var_type = types.type_by_id(d.type_)?; - let var_kind = var_type.kind()?.unwrap(); - if let BtfType::Var(vty, var) = var_type { - let var_name = self.string_at(vty.name_off)?.to_string(); - if var.linkage == btf_func_linkage::BTF_FUNC_STATIC as u32 { + } + })?; + debug!("{} {}: fixup size to {}", kind, name, size); + fixed_ty.__bindgen_anon_1.size = *size as u32; + + // The Vec contains BTF_KIND_VAR sections + // that need to have their offsets adjusted. To do this, + // we need to get the offset from the ELF file. + // This was also cached during initial parsing and + // we can query by name in symbol_offsets + for d in &mut fixed_data { + let var_type = types.type_by_id(d.type_)?; + let var_kind = var_type.kind()?.unwrap(); + if let BtfType::Var(vty, var) = var_type { + let var_name = self.string_at(vty.name_off)?.to_string(); + if var.linkage == btf_func_linkage::BTF_FUNC_STATIC as u32 { + debug!( + "{} {}: {} {}: fixup not required", + kind, name, var_kind, var_name + ); + continue; + } + + let offset = symbol_offsets.get(&var_name).ok_or( + BtfError::SymbolOffsetNotFound { + symbol_name: var_name.clone(), + }, + )?; + d.offset = *offset as u32; debug!( - "{} {}: {} {}: fixup not required", - kind, name, var_kind, var_name + "{} {}: {} {}: fixup offset {}", + kind, name, var_kind, var_name, offset ); - continue; + } else { + return Err(BtfError::InvalidDatasec); } - - let offset = symbol_offsets.get(&var_name).ok_or( - BtfError::SymbolOffsetNotFound { - symbol_name: var_name.clone(), - }, - )?; - d.offset = *offset as u32; - debug!( - "{} {}: {} {}: fixup offset {}", - kind, name, var_kind, var_name, offset - ); - } else { - return Err(BtfError::InvalidDatasec); } } types.types[i] = BtfType::DataSec(fixed_ty, fixed_data); @@ -1097,7 +1104,7 @@ mod tests { BTF_VAR_GLOBAL_EXTERN, )); - let name_offset = btf.add_string(".data".to_string()); + let name_offset = btf.add_string(".data/foo".to_string()); let variables = vec![btf_var_secinfo { type_: var_type_id, offset: 0, @@ -1111,14 +1118,14 @@ mod tests { }; btf.fixup_and_sanitize( - &HashMap::from([(".data".to_string(), 32u64)]), + &HashMap::from([(".data/foo".to_string(), 32u64)]), &HashMap::from([("foo".to_string(), 64u64)]), &features, ) .unwrap(); if let BtfType::DataSec(fixed, sec_info) = btf.type_by_id(datasec_type_id).unwrap() { - assert!(fixed.name_off == name_offset); + assert!(fixed.name_off != name_offset); assert!(unsafe { fixed.__bindgen_anon_1.size } == 32); assert!(sec_info.len() == 1); assert!(sec_info[0].type_ == var_type_id); @@ -1126,7 +1133,8 @@ mod tests { sec_info[0].offset == 64, "expected 64, got {}", sec_info[0].offset - ) + ); + assert!(btf.string_at(fixed.name_off).unwrap() == ".data.foo") } else { panic!("not a datasec") }