From ff1449375106557fa666d5b2723096adad94b3bd Mon Sep 17 00:00:00 2001 From: William Findlay Date: Tue, 21 Dec 2021 18:28:57 -0500 Subject: [PATCH 1/2] bpf/maps: implement ProgramArray This PR implements the ProgramArray map type in aya-bpf. Includes a convenient tail_call method that wraps the bpf_tail_call helper. --- bpf/aya-bpf/src/maps/mod.rs | 2 + bpf/aya-bpf/src/maps/program_array.rs | 80 +++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 bpf/aya-bpf/src/maps/program_array.rs diff --git a/bpf/aya-bpf/src/maps/mod.rs b/bpf/aya-bpf/src/maps/mod.rs index 8499ff38..c3ae05ed 100644 --- a/bpf/aya-bpf/src/maps/mod.rs +++ b/bpf/aya-bpf/src/maps/mod.rs @@ -9,6 +9,7 @@ pub mod array; pub mod hash_map; pub mod per_cpu_array; pub mod perf; +pub mod program_array; pub mod queue; pub mod sock_hash; pub mod sock_map; @@ -18,6 +19,7 @@ pub use array::Array; pub use hash_map::{HashMap, LruHashMap, LruPerCpuHashMap, PerCpuHashMap}; pub use per_cpu_array::PerCpuArray; pub use perf::{PerfEventArray, PerfEventByteArray}; +pub use program_array::ProgramArray; pub use queue::Queue; pub use sock_hash::SockHash; pub use sock_map::SockMap; diff --git a/bpf/aya-bpf/src/maps/program_array.rs b/bpf/aya-bpf/src/maps/program_array.rs new file mode 100644 index 00000000..c8f90564 --- /dev/null +++ b/bpf/aya-bpf/src/maps/program_array.rs @@ -0,0 +1,80 @@ +use core::{hint::unreachable_unchecked, mem}; + +use aya_bpf_cty::c_long; + +use crate::{ + bindings::{bpf_map_def, bpf_map_type::BPF_MAP_TYPE_PROG_ARRAY}, + helpers::bpf_tail_call, + maps::PinningType, + BpfContext, +}; + +/// A BPF map that stores an array of program indices for tail calling. +/// +/// # Examples +/// +/// ```no_run +/// # #![allow(dead_code)] +/// use aya_bpf::{macros::map, maps::ProgramArray, cty::c_long}; +/// # use aya_bpf::{programs::LsmContext}; +/// +/// #[map] +/// static mut JUMP_TABLE: ProgramArray = ProgramArray::with_max_entries(16, 0); +/// +/// # unsafe fn try_test(ctx: &LsmContext) -> Result<(), c_long> { +/// let index: u32 = 13; +/// +/// let res = JUMP_TABLE.tail_call(ctx, index); +/// +/// # res +/// } +/// ``` +#[repr(transparent)] +pub struct ProgramArray { + def: bpf_map_def, +} + +impl ProgramArray { + pub const fn with_max_entries(max_entries: u32, flags: u32) -> ProgramArray { + ProgramArray { + def: bpf_map_def { + type_: BPF_MAP_TYPE_PROG_ARRAY, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::None as u32, + }, + } + } + + pub const fn pinned(max_entries: u32, flags: u32) -> ProgramArray { + ProgramArray { + def: bpf_map_def { + type_: BPF_MAP_TYPE_PROG_ARRAY, + key_size: mem::size_of::() as u32, + value_size: mem::size_of::() as u32, + max_entries, + map_flags: flags, + id: 0, + pinning: PinningType::ByName as u32, + }, + } + } + + /// Perform a tail call into a program indexed by this map. + /// + /// # Return Value + /// + /// On success, this function **does not return** into the original program. + /// On failure, a negative error is returned, wrapped in `Err()`. + pub fn tail_call(&mut self, ctx: &C, index: u32) -> Result<(), c_long> { + let res = unsafe { bpf_tail_call(ctx.as_ptr(), &mut self.def as *mut _ as *mut _, index) }; + if res != 0 { + Err(res) + } else { + unsafe { unreachable_unchecked() } + } + } +} From df26fd94a74d40069d10cd448adf4e7c27ede26a Mon Sep 17 00:00:00 2001 From: William Findlay Date: Wed, 22 Dec 2021 01:15:04 -0500 Subject: [PATCH 2/2] bpf/program_array: use never type, add unsafe flag, and document safety --- bpf/aya-bpf/src/lib.rs | 1 + bpf/aya-bpf/src/maps/program_array.rs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/bpf/aya-bpf/src/lib.rs b/bpf/aya-bpf/src/lib.rs index 020fc772..6f7a384d 100644 --- a/bpf/aya-bpf/src/lib.rs +++ b/bpf/aya-bpf/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(never_type)] #![allow(clippy::missing_safety_doc)] #![no_std] diff --git a/bpf/aya-bpf/src/maps/program_array.rs b/bpf/aya-bpf/src/maps/program_array.rs index c8f90564..06c91b36 100644 --- a/bpf/aya-bpf/src/maps/program_array.rs +++ b/bpf/aya-bpf/src/maps/program_array.rs @@ -24,9 +24,11 @@ use crate::{ /// # unsafe fn try_test(ctx: &LsmContext) -> Result<(), c_long> { /// let index: u32 = 13; /// -/// let res = JUMP_TABLE.tail_call(ctx, index); +/// if let Err(e) = JUMP_TABLE.tail_call(ctx, index) { +/// return Err(e); +/// } /// -/// # res +/// # Err(-1) /// } /// ``` #[repr(transparent)] @@ -65,16 +67,23 @@ impl ProgramArray { /// Perform a tail call into a program indexed by this map. /// + /// # Safety + /// + /// This function is inherently unsafe, since it causes control flow to jump into + /// another eBPF program. This can have side effects, such as drop methods not being + /// called. Note that tail calling into an eBPF program is not the same thing as + /// a function call -- control flow never returns to the caller. + /// /// # Return Value /// /// On success, this function **does not return** into the original program. /// On failure, a negative error is returned, wrapped in `Err()`. - pub fn tail_call(&mut self, ctx: &C, index: u32) -> Result<(), c_long> { - let res = unsafe { bpf_tail_call(ctx.as_ptr(), &mut self.def as *mut _ as *mut _, index) }; + pub unsafe fn tail_call(&mut self, ctx: &C, index: u32) -> Result { + let res = bpf_tail_call(ctx.as_ptr(), &mut self.def as *mut _ as *mut _, index); if res != 0 { Err(res) } else { - unsafe { unreachable_unchecked() } + unreachable_unchecked() } } }