From 9b21c85a6ff16c24bce096ff0814cc313725c509 Mon Sep 17 00:00:00 2001
From: aorhant <aorhant@scaleway.com>
Date: Wed, 26 Feb 2025 18:54:13 +0100
Subject: [PATCH] feat(aya): return correct Option from
 bpf_map_lookup_elem_per_cpu

bpf_map_lookup_elem_per_cpu doesn't check the Option inside the Result:Ok,
thus when it receive a Ok(None), it returns a zeroed value PerCpuValues.
---
 aya/src/maps/hash_map/per_cpu_hash_map.rs | 25 ++++++++++++++++++++++-
 aya/src/sys/bpf.rs                        |  2 +-
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/aya/src/maps/hash_map/per_cpu_hash_map.rs b/aya/src/maps/hash_map/per_cpu_hash_map.rs
index d9194668..3d402a8b 100644
--- a/aya/src/maps/hash_map/per_cpu_hash_map.rs
+++ b/aya/src/maps/hash_map/per_cpu_hash_map.rs
@@ -151,12 +151,23 @@ impl<T: Borrow<MapData>, K: Pod, V: Pod> IterableMap<K, PerCpuValues<V>>
 
 #[cfg(test)]
 mod tests {
+    use std::{ffi::c_long, io};
+
+    use assert_matches::assert_matches;
     use aya_obj::generated::bpf_map_type::{
         BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_HASH,
     };
+    use libc::ENOENT;
 
     use super::*;
-    use crate::maps::{test_utils, Map};
+    use crate::{
+        maps::{test_utils, Map},
+        sys::{override_syscall, SysResult},
+    };
+
+    fn sys_error(value: i32) -> SysResult<c_long> {
+        Err((-1, io::Error::from_raw_os_error(value)))
+    }
 
     #[test]
     fn test_try_from_ok() {
@@ -174,4 +185,16 @@ mod tests {
         let map = Map::PerCpuLruHashMap(map_data());
         assert!(PerCpuHashMap::<_, u32, u32>::try_from(&map).is_ok())
     }
+    #[test]
+    #[cfg_attr(miri, ignore = "`open` not available when isolation is enabled")]
+    fn test_get_not_found() {
+        let map_data =
+            || test_utils::new_map(test_utils::new_obj_map::<u32>(BPF_MAP_TYPE_LRU_PERCPU_HASH));
+        let map = Map::PerCpuHashMap(map_data());
+        let map = PerCpuHashMap::<_, u32, u32>::try_from(&map).unwrap();
+
+        override_syscall(|_| sys_error(ENOENT));
+
+        assert_matches!(map.get(&1, 0), Err(MapError::KeyNotFound));
+    }
 }
diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs
index 791959f1..51ca7a97 100644
--- a/aya/src/sys/bpf.rs
+++ b/aya/src/sys/bpf.rs
@@ -249,7 +249,7 @@ pub(crate) fn bpf_map_lookup_elem_per_cpu<K: Pod, V: Pod>(
 ) -> SysResult<Option<PerCpuValues<V>>> {
     let mut mem = PerCpuValues::<V>::alloc_kernel_mem().map_err(|io_error| (-1, io_error))?;
     match bpf_map_lookup_elem_ptr(fd, Some(key), mem.as_mut_ptr(), flags) {
-        Ok(_) => Ok(Some(unsafe { PerCpuValues::from_kernel_mem(mem) })),
+        Ok(v) => Ok(v.map(|()| unsafe { PerCpuValues::from_kernel_mem(mem) })),
         Err((_, io_error)) if io_error.raw_os_error() == Some(ENOENT) => Ok(None),
         Err(e) => Err(e),
     }