From ff6d7b8b0af3236253debbce12ec919e2d6288a2 Mon Sep 17 00:00:00 2001 From: Rafael Ortiz Date: Tue, 22 Jun 2021 08:30:59 -0400 Subject: [PATCH] test for minimum map size, copy map definitions by bytes, fix tests * `data` must be less than or equal to the size of `bpf_map_def` but greater than or equal to 20 bytes (the first five entries, before `id` and `pinning`) * if `data` is not equal to the size of `bpf_map_def` (i.e., we have undefined `id` or `pinning` entries), then we copy it by bytes to an empty `bpf_map_def` * added tests for too large and too small definitions Refs: #10, #14 --- aya/src/obj/mod.rs | 55 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/aya/src/obj/mod.rs b/aya/src/obj/mod.rs index 88755e38..adc4d52b 100644 --- a/aya/src/obj/mod.rs +++ b/aya/src/obj/mod.rs @@ -24,6 +24,8 @@ use crate::{ }; const KERNEL_VERSION_ANY: u32 = 0xFFFF_FFFE; +/// The first five __u32 of `bpf_map_def` must be defined. +const MINIMUM_MAP_SIZE: usize = mem::size_of::() * 5; #[derive(Clone)] pub struct Object { @@ -509,19 +511,22 @@ fn parse_map(section: &Section, name: &str) -> Result { } fn parse_map_def(name: &str, data: &[u8]) -> Result { - if data.len() > mem::size_of::() { + if data.len() > mem::size_of::() || data.len() < MINIMUM_MAP_SIZE { return Err(ParseError::InvalidMapDefinition { name: name.to_owned(), }); } - if data.len() < mem::size_of::() { + if data.len() < mem::size_of::() { let mut map_def = bpf_map_def::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; + let mut data_ptr = data.as_ptr(); + let mut map_def_ptr = &mut map_def as *mut bpf_map_def as *mut u8; + for _ in 0..=data.len() { + *map_def_ptr = *data_ptr; + map_def_ptr = map_def_ptr.add(1); + data_ptr = data_ptr.add(1); + } } Ok(map_def) } else { @@ -668,11 +673,15 @@ mod tests { #[test] fn test_parse_map_def() { #![allow(unused_variables)] // map_def is used by the assertion + assert!(matches!( + parse_map_def("foo", &[]), + Err(ParseError::InvalidMapDefinition { .. }) + )); assert!(matches!( parse_map_def("foo", &[0u8; std::mem::size_of::() + 10]), Err(ParseError::InvalidMapDefinition { .. }) )); - let map_def = bpf_map_def { + let def = bpf_map_def { map_type: 1, key_size: 2, value_size: 3, @@ -692,27 +701,49 @@ mod tests { ..Default::default() }) ), - Ok(map_def) + Ok(def) )); assert!(matches!( parse_map_def( "foo", - &[0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8, 0u8, 5u8] + &bytes_of(&bpf_map_def { + map_type: 1, + key_size: 2, + value_size: 3, + max_entries: 4, + map_flags: 5, + ..Default::default() + })[..(mem::size_of::() * 5)] ), 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(); + &bytes_of(&bpf_map_def { + map_type: 1, + key_size: 2, + value_size: 3, + max_entries: 4, + map_flags: 5, + ..Default::default() + })[..(mem::size_of::() * 5)], + ) + .unwrap(); assert!(map.id == 0 && map.pinning == 0) } #[test] fn test_parse_map_error() { assert!(matches!( - parse_map(&fake_section("maps/foo", &[0u8; std::mem::size_of::() + 10]), "foo"), + parse_map(&fake_section("maps/foo", &[]), "foo"), + Err(ParseError::InvalidMapDefinition { .. }) + )); + assert!(matches!( + parse_map( + &fake_section("maps/foo", &[0u8; std::mem::size_of::() + 10]), + "foo" + ), Err(ParseError::InvalidMapDefinition { .. }) )) }