diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs index 91d3a3aa..b513f09b 100644 --- a/aya/src/bpf.rs +++ b/aya/src/bpf.rs @@ -50,13 +50,41 @@ unsafe_impl_pod!(i8, u8, i16, u16, i32, u32, i64, u64); #[repr(C)] #[derive(Copy, Clone, Debug)] pub(crate) struct bpf_map_def { + // minimum features required by old BPF programs pub(crate) map_type: u32, pub(crate) key_size: u32, pub(crate) value_size: u32, pub(crate) max_entries: u32, pub(crate) map_flags: u32, - pub(crate) id: u32, - pub(crate) pinning: u32, + // optional features + pub(crate) inner_map_fd: u32, // id + pub(crate) numa_node: u32, // pinning + pub(crate) map_name: [u8; BPF_OBJ_NAME_LEN], + pub(crate) map_ifindex: u32, + pub(crate) btf_id: u32, + pub(crate) btf_key_type_id: u32, + pub(crate) btf_value_type_id: u32, + pub(crate) btf_vmlinux_value_type_id: u32, +} + +impl Default for bpf_map_def { + fn default() -> Self { + Self { + map_type: 0, + key_size: 0, + value_size: 0, + max_entries: 0, + map_flags: 0, + inner_map_fd: 0, + numa_node: 0, + map_name: [0u8; BPF_OBJ_NAME_LEN], + map_ifindex: 0, + btf_id: 0, + btf_key_type_id: 0, + btf_value_type_id: 0, + btf_vmlinux_value_type_id: 0 + } + } } /// The main entry point into the library, used to work with eBPF programs and maps. diff --git a/aya/src/maps/hash_map/hash_map.rs b/aya/src/maps/hash_map/hash_map.rs index 63a260f9..1ba608f2 100644 --- a/aya/src/maps/hash_map/hash_map.rs +++ b/aya/src/maps/hash_map/hash_map.rs @@ -162,9 +162,7 @@ mod tests { key_size: 4, value_size: 4, max_entries: 1024, - map_flags: 0, - id: 0, - pinning: 0, + ..Default::default() }, section_index: 0, data: Vec::new(), @@ -215,9 +213,7 @@ mod tests { key_size: 4, value_size: 4, max_entries: 1024, - map_flags: 0, - id: 0, - pinning: 0, + ..Default::default() }, section_index: 0, data: Vec::new(), @@ -273,9 +269,7 @@ mod tests { key_size: 4, value_size: 4, max_entries: 1024, - map_flags: 0, - id: 0, - pinning: 0, + ..Default::default() }, section_index: 0, data: Vec::new(), diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index cb9176f7..f96e4b32 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -426,9 +426,7 @@ mod tests { key_size: 4, value_size: 4, max_entries: 1024, - map_flags: 0, - id: 0, - pinning: 0, + ..Default::default() }, section_index: 0, data: Vec::new(), diff --git a/aya/src/obj/mod.rs b/aya/src/obj/mod.rs index 45b1a3ce..5c714bb4 100644 --- a/aya/src/obj/mod.rs +++ b/aya/src/obj/mod.rs @@ -493,8 +493,7 @@ fn parse_map(section: &Section, name: &str) -> Result { value_size: section.data.len() as u32, max_entries: 1, map_flags: 0, /* FIXME: set rodata readonly */ - id: 0, - pinning: 0, + ..Default::default() }; (def, section.data.to_vec()) } else { @@ -510,13 +509,31 @@ fn parse_map(section: &Section, name: &str) -> Result { } fn parse_map_def(name: &str, data: &[u8]) -> Result { - if mem::size_of::() > data.len() { + if mem::size_of::() < data.len() { return Err(ParseError::InvalidMapDefinition { name: name.to_owned(), }); } - Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) }) + let mut map_def = bpf_map_def{ + ..Default::default() + }; + + unsafe { + // std::ptr::copy is const, we can't use it because data.len() isn't known at + // compile time + let mut p = data.as_ptr(); + let mut q = &mut map_def as *mut bpf_map_def as *mut u8; + for _ in 0..=data.len() { + *q = *p; + q = q.add(1); + p = p.add(1); + } + } + + Ok(map_def) + + //Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) }) } fn copy_instructions(data: &[u8]) -> Result, ParseError> { @@ -657,10 +674,19 @@ mod tests { #[test] fn test_parse_map_def() { + #![allow(unused_variables)] // map_def is used by the assertion assert!(matches!( - parse_map_def("foo", &[]), + parse_map_def("foo", &[0u8; std::mem::size_of::() + 10]), Err(ParseError::InvalidMapDefinition { .. }) )); + let map_def = bpf_map_def { + map_type: 1, + key_size: 2, + value_size: 3, + max_entries: 4, + map_flags: 5, + ..Default::default() + }; assert!(matches!( parse_map_def( "foo", @@ -670,32 +696,32 @@ mod tests { value_size: 3, max_entries: 4, map_flags: 5, - id: 0, - pinning: 0 + ..Default::default() }) ), - Ok(bpf_map_def { - map_type: 1, - key_size: 2, - value_size: 3, - max_entries: 4, - map_flags: 5, - id: 0, - pinning: 0 - }) + Ok(map_def) )); } #[test] fn test_parse_map_error() { assert!(matches!( - parse_map(&fake_section("maps/foo", &[]), "foo"), + parse_map(&fake_section("maps/foo", &[0u8; std::mem::size_of::() + 10]), "foo"), Err(ParseError::InvalidMapDefinition { .. }) )) } #[test] fn test_parse_map() { + #![allow(unused_variables)] // def is used by the assertion + let def = bpf_map_def { + map_type: 1, + key_size: 2, + value_size: 3, + max_entries: 4, + map_flags: 5, + ..Default::default() + }; assert!(matches!( parse_map( &fake_section( @@ -706,8 +732,7 @@ mod tests { value_size: 3, max_entries: 4, map_flags: 5, - id: 0, - pinning: 0 + ..Default::default() }) ), "foo" @@ -715,15 +740,7 @@ mod tests { Ok(Map { section_index: 0, name, - def: bpf_map_def { - map_type: 1, - key_size: 2, - value_size: 3, - max_entries: 4, - map_flags: 5, - id: 0, - pinning: 0 - }, + def, data }) if name == "foo" && data.is_empty() )) @@ -731,7 +748,18 @@ mod tests { #[test] fn test_parse_map_data() { + #![allow(unused_variables)] // def is used by the assertion let map_data = b"map data"; + let _map_type = BPF_MAP_TYPE_ARRAY; + let value_size = map_data.len() as u32; + let def = bpf_map_def { + map_type: _map_type as u32, + key_size: 4, + value_size, + max_entries: 1, + map_flags: 0, + ..Default::default() + }; assert!(matches!( parse_map( &fake_section( @@ -743,15 +771,7 @@ mod tests { Ok(Map { section_index: 0, name, - def: bpf_map_def { - map_type: _map_type, - key_size: 4, - value_size, - max_entries: 1, - map_flags: 0, - id: 0, - pinning: 0 - }, + def, data }) if name == ".bss" && data == map_data && value_size == map_data.len() as u32 )) @@ -809,8 +829,7 @@ mod tests { value_size: 3, max_entries: 4, map_flags: 5, - id: 0, - pinning: 0 + ..Default::default() }) ),), Ok(())