diff --git a/aya-obj/src/maps.rs b/aya-obj/src/maps.rs index e9dbc4561..d5631f786 100644 --- a/aya-obj/src/maps.rs +++ b/aya-obj/src/maps.rs @@ -128,8 +128,12 @@ pub struct bpf_map_def { // optional features /// Id pub id: u32, - /// Pinning type + /// Pinning type. Only [`PinningType::None`] is supported for legacy maps. pub pinning: PinningType, + /// Inner map id. Map-of-maps is not supported for legacy maps. + pub inner_id: u32, + /// Inner map index. Map-of-maps is not supported for legacy maps. + pub inner_idx: u32, } /// The first five __u32 of `bpf_map_def` must be defined. diff --git a/aya-obj/src/obj.rs b/aya-obj/src/obj.rs index ccb37527e..657cdfcdc 100644 --- a/aya-obj/src/obj.rs +++ b/aya-obj/src/obj.rs @@ -1009,6 +1009,9 @@ pub enum ParseError { /// No BTF parsed for object #[error("no BTF parsed for object")] NoBTF, + + #[error("map `{name}` uses unsupported legacy pinning")] + UnsupportedLegacyPinning { name: String }, } /// Invalid bindings to the bpf type from the parsed/received value. @@ -1251,16 +1254,23 @@ fn parse_map_def(name: &str, data: &[u8]) -> Result { }); } - if data.len() < size_of::() { + let map_def = if data.len() < size_of::() { let mut map_def = bpf_map_def::default(); unsafe { let map_def_ptr = from_raw_parts_mut(ptr::from_mut(&mut map_def).cast(), data.len()); map_def_ptr.copy_from_slice(data); } - Ok(map_def) + map_def } else { - Ok(unsafe { ptr::read_unaligned(data.as_ptr().cast()) }) + unsafe { ptr::read_unaligned(data.as_ptr().cast()) } + }; + + if map_def.pinning != PinningType::None { + return Err(ParseError::UnsupportedLegacyPinning { + name: name.to_owned(), + }); } + Ok(map_def) } fn parse_btf_map_def(btf: &Btf, info: &DataSecEntry) -> Result<(String, BtfMapDef), BtfError> { @@ -1367,6 +1377,8 @@ pub const fn parse_map_info(info: bpf_map_info, pinned: PinningType) -> Map { map_flags: info.map_flags, pinning: pinned, id: info.id, + inner_id: 0, + inner_idx: 0, }, section_index: 0, symbol_index: None, @@ -1566,6 +1578,8 @@ mod tests { map_flags: 5, id: 0, pinning: PinningType::None, + inner_id: 0, + inner_idx: 0, }; assert_eq!( @@ -1574,6 +1588,25 @@ mod tests { ); } + #[test] + fn test_parse_map_def_unsupported_pinning() { + let def = bpf_map_def { + map_type: 1, + key_size: 2, + value_size: 3, + max_entries: 4, + map_flags: 5, + id: 0, + pinning: PinningType::ByName, + inner_id: 0, + inner_idx: 0, + }; + assert_matches!( + parse_map_def("foo", bytes_of(&def)), + Err(ParseError::UnsupportedLegacyPinning { .. }) + ); + } + #[test] fn test_parse_map_def() { let def = bpf_map_def { @@ -1583,7 +1616,9 @@ mod tests { max_entries: 4, map_flags: 5, id: 6, - pinning: PinningType::ByName, + pinning: PinningType::None, + inner_id: 0, + inner_idx: 0, }; assert_eq!(parse_map_def("foo", bytes_of(&def)).unwrap(), def); @@ -1598,7 +1633,9 @@ mod tests { max_entries: 4, map_flags: 5, id: 6, - pinning: PinningType::ByName, + pinning: PinningType::None, + inner_id: 0, + inner_idx: 0, }; let mut buf = [0u8; 128]; unsafe { ptr::write_unaligned(buf.as_mut_ptr().cast(), def) } @@ -1630,6 +1667,8 @@ mod tests { map_flags: 0, id: 0, pinning: PinningType::None, + inner_id: 0, + inner_idx: 0, }, data, }) if data == map_data && value_size == map_data.len() as u32 @@ -1809,17 +1848,59 @@ mod tests { } #[test] - fn test_parse_section_multiple_maps() { + fn test_parse_section_multiple_maps_v1_legacy() { + let mut obj = fake_obj(); + fake_sym(&mut obj, 0, 0, "foo", 28); + fake_sym(&mut obj, 0, 28, "bar", 28); + fake_sym(&mut obj, 0, 60, "baz", 28); + let def = &bpf_map_def { + map_type: 1, + key_size: 2, + value_size: 3, + max_entries: 4, + map_flags: 5, + ..Default::default() + }; + let map_data = bytes_of(def)[..28].to_vec(); + let mut buf = vec![]; + buf.extend(&map_data); + buf.extend(&map_data); + // throw in some padding + buf.extend([0, 0, 0, 0]); + buf.extend(&map_data); + assert_matches!( + obj.parse_section(fake_section( + EbpfSectionKind::Maps, + "maps", + buf.as_slice(), + None + )), + Ok(()) + ); + assert!(obj.maps.contains_key("foo")); + assert!(obj.maps.contains_key("bar")); + assert!(obj.maps.contains_key("baz")); + for map in obj.maps.values() { + assert_matches!(map, Map::Legacy(m) => { + assert_eq!(&m.def, def); + }) + } + } + + #[test] + fn test_parse_section_multiple_maps_v2_legacy_tc() { let mut obj = fake_obj(); fake_sym(&mut obj, 0, 0, "foo", size_of::() as u64); - fake_sym(&mut obj, 0, 28, "bar", size_of::() as u64); - fake_sym(&mut obj, 0, 60, "baz", size_of::() as u64); + fake_sym(&mut obj, 0, 36, "bar", size_of::() as u64); + fake_sym(&mut obj, 0, 76, "baz", size_of::() as u64); let def = &bpf_map_def { map_type: 1, key_size: 2, value_size: 3, max_entries: 4, map_flags: 5, + inner_id: 6, + inner_idx: 7, ..Default::default() }; let map_data = bytes_of(def).to_vec(); @@ -2628,6 +2709,8 @@ mod tests { map_flags: BPF_F_RDONLY_PROG, id: 1, pinning: PinningType::None, + inner_id: 0, + inner_idx: 0, }, section_index: 1, section_kind: EbpfSectionKind::Rodata, diff --git a/test/integration-test/bpf/tc_legacy_map.bpf.c b/test/integration-test/bpf/tc_legacy_map.bpf.c new file mode 100644 index 000000000..cabe39d4c --- /dev/null +++ b/test/integration-test/bpf/tc_legacy_map.bpf.c @@ -0,0 +1,48 @@ +// clang-format off +#include +#include +// clang-format on + +struct bpf_elf_map { + __u32 type; + __u32 size_key; + __u32 size_value; + __u32 max_elem; + __u32 flags; + __u32 id; + __u32 pinning; + __u32 inner_id; + __u32 inner_idx; +}; + +struct bpf_elf_map SEC("maps") tc_map_1 = { + .type = BPF_MAP_TYPE_ARRAY, + .size_key = sizeof(__u32), + .size_value = sizeof(__u32), + .max_elem = 1, + .id = 1, + .inner_id = 1, + .inner_idx = 1, +}; + +struct bpf_elf_map SEC("maps") tc_map_2 = { + .type = BPF_MAP_TYPE_ARRAY, + .size_key = sizeof(__u32), + .size_value = sizeof(__u32), + .max_elem = 2, + .id = 2, + .inner_id = 2, + .inner_idx = 2, +}; + +SEC("classifier") +int tc_pass(void *ctx) { + __u32 key = 0; + __u32 val = 42; + + bpf_map_update_elem(&tc_map_1, &key, &val, BPF_ANY); + bpf_map_update_elem(&tc_map_2, &key, &val, BPF_ANY); + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/test/integration-test/build.rs b/test/integration-test/build.rs index e6390c017..24fe40227 100644 --- a/test/integration-test/build.rs +++ b/test/integration-test/build.rs @@ -93,6 +93,7 @@ fn main() -> Result<()> { ("struct_flavors_reloc.bpf.c", true), ("text_64_64_reloc.c", false), ("variables_reloc.bpf.c", false), + ("tc_legacy_map.bpf.c", false), ]; const C_BPF_HEADERS: &[&str] = &["reloc.h", "struct_with_scalars.h"]; diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index 6927e6129..b6f5a18ff 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -11,6 +11,7 @@ bpf_file!( ITER_TASK => "iter.bpf.o", MAIN => "main.bpf.o", MULTIMAP_BTF => "multimap-btf.bpf.o", + TC_LEGACY_MAP => "tc_legacy_map.bpf.o", RINGBUF_BTF => "ringbuf-btf.bpf.o", ENUM_SIGNED_32_RELOC_BPF => "enum_signed_32_reloc.bpf.o", diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index 8ff890975..3bd819e3f 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -675,3 +675,14 @@ fn pin_lifecycle_uprobe() { // Make sure the function isn't optimized out. uprobe_function(); } + +#[test_log::test] +fn legacy_36_byte_maps() { + let mut bpf = Ebpf::load(crate::TC_LEGACY_MAP).unwrap(); + + let map_1: Array<_, u32> = bpf.take_map("tc_map_1").unwrap().try_into().unwrap(); + let map_2: Array<_, u32> = bpf.take_map("tc_map_2").unwrap().try_into().unwrap(); + + assert_eq!(map_1.len(), 1); + assert_eq!(map_2.len(), 2); +} diff --git a/xtask/public-api/aya-obj.txt b/xtask/public-api/aya-obj.txt index 207acf59f..653766f34 100644 --- a/xtask/public-api/aya-obj.txt +++ b/xtask/public-api/aya-obj.txt @@ -8625,6 +8625,8 @@ impl core::convert::From for aya_obj::maps::LegacyMap pub fn aya_obj::maps::LegacyMap::from(t: T) -> T #[repr(C)] pub struct aya_obj::maps::bpf_map_def pub aya_obj::maps::bpf_map_def::id: u32 +pub aya_obj::maps::bpf_map_def::inner_id: u32 +pub aya_obj::maps::bpf_map_def::inner_idx: u32 pub aya_obj::maps::bpf_map_def::key_size: u32 pub aya_obj::maps::bpf_map_def::map_flags: u32 pub aya_obj::maps::bpf_map_def::map_type: u32 @@ -8762,6 +8764,8 @@ pub aya_obj::obj::ParseError::SymbolTableConflict::section_index: usize pub aya_obj::obj::ParseError::UnknownSymbol pub aya_obj::obj::ParseError::UnknownSymbol::address: u64 pub aya_obj::obj::ParseError::UnknownSymbol::section_index: usize +pub aya_obj::obj::ParseError::UnsupportedLegacyPinning +pub aya_obj::obj::ParseError::UnsupportedLegacyPinning::name: alloc::string::String pub aya_obj::obj::ParseError::UnsupportedRelocationTarget impl core::convert::From for aya_obj::ParseError pub fn aya_obj::ParseError::from(source: aya_obj::btf::BtfError) -> Self @@ -9644,6 +9648,8 @@ pub aya_obj::ParseError::SymbolTableConflict::section_index: usize pub aya_obj::ParseError::UnknownSymbol pub aya_obj::ParseError::UnknownSymbol::address: u64 pub aya_obj::ParseError::UnknownSymbol::section_index: usize +pub aya_obj::ParseError::UnsupportedLegacyPinning +pub aya_obj::ParseError::UnsupportedLegacyPinning::name: alloc::string::String pub aya_obj::ParseError::UnsupportedRelocationTarget impl core::convert::From for aya_obj::ParseError pub fn aya_obj::ParseError::from(source: aya_obj::btf::BtfError) -> Self