From 44baee9c1983c5a0d357504db89cb5bfa09743e3 Mon Sep 17 00:00:00 2001
From: Rafael Ortiz <rafael.ortiz@redcanary.com>
Date: Mon, 21 Jun 2021 17:43:59 -0400
Subject: [PATCH] `bpf_map_def` from libbpf and iproute2

---
 aya/src/bpf.rs     | 32 +++-----------------------------
 aya/src/obj/mod.rs | 44 ++++++++++++++++++++++++--------------------
 2 files changed, 27 insertions(+), 49 deletions(-)

diff --git a/aya/src/bpf.rs b/aya/src/bpf.rs
index b513f09b..175798cd 100644
--- a/aya/src/bpf.rs
+++ b/aya/src/bpf.rs
@@ -48,7 +48,7 @@ unsafe_impl_pod!(i8, u8, i16, u16, i32, u32, i64, u64);
 
 #[allow(non_camel_case_types)]
 #[repr(C)]
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Default)]
 pub(crate) struct bpf_map_def {
     // minimum features required by old BPF programs
     pub(crate) map_type: u32,
@@ -57,34 +57,8 @@ pub(crate) struct bpf_map_def {
     pub(crate) max_entries: u32,
     pub(crate) map_flags: 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
-        }
-    }
+    pub(crate) id: u32, // id
+    pub(crate) pinning: u32,    // pinning
 }
 
 /// The main entry point into the library, used to work with eBPF programs and maps.
diff --git a/aya/src/obj/mod.rs b/aya/src/obj/mod.rs
index 2579dca7..5e548a3a 100644
--- a/aya/src/obj/mod.rs
+++ b/aya/src/obj/mod.rs
@@ -509,33 +509,24 @@ fn parse_map(section: &Section, name: &str) -> Result<Map, ParseError> {
 }
 
 fn parse_map_def(name: &str, data: &[u8]) -> Result<bpf_map_def, ParseError> {
-    if mem::size_of::<bpf_map_def>() < data.len() {
+    if data.len() > mem::size_of::<bpf_map_def>() {
         return Err(ParseError::InvalidMapDefinition {
             name: name.to_owned(),
         });
     }
 
-    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, this is only safe because we've asserted that data.len()
-        // must be <= mem::size_of::<bpf_map_def>(), if you change that check, then
-        // you must change this copy
-        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);
+    if data.len() <  mem::size_of::<bpf_map_def>() {
+        let mut map_def = bpf_map_def { ..Default::default() };
+        unsafe {
+            ptr::copy(data.as_ptr() as *const bpf_map_def, &mut map_def as *mut bpf_map_def, 1);
+            // id and pinning will be garbage data
+            map_def.id = 0;
+            map_def.pinning = 0;
         }
+        Ok(map_def)
+    } else {
+        Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) })
     }
-
-    Ok(map_def)
-
-    //Ok(unsafe { ptr::read_unaligned(data.as_ptr() as *const bpf_map_def) })
 }
 
 fn copy_instructions(data: &[u8]) -> Result<Vec<bpf_insn>, ParseError> {
@@ -703,6 +694,19 @@ mod tests {
             ),
             Ok(map_def)
         ));
+
+        assert!(matches!(
+            parse_map_def(
+                "foo",
+                &[0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8, 0u8, 5u8]
+            ),
+            Ok(map_def)
+        ));
+        let map = parse_map_def(
+            "foo",
+            &[0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8, 0u8, 5u8]
+        ).unwrap();
+        assert!(map.id == 0 && map.pinning == 0)
     }
 
     #[test]