-
Notifications
You must be signed in to change notification settings - Fork 305
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(aya): Add task storage map type (in the user-space)
Task storage is a type of map which uses `task_struct` kernel type as a key. When the task (process) stops, the corresponding entry is automatically removed. This change add support only in the user-space and tests the functionality with a C program.
- Loading branch information
1 parent
76ca85c
commit 4b526d7
Showing
10 changed files
with
284 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
//! Task storage. | ||
use std::{ | ||
borrow::Borrow, | ||
ffi::c_int, | ||
marker::PhantomData, | ||
os::fd::{AsFd, AsRawFd}, | ||
}; | ||
|
||
use crate::{ | ||
maps::{check_kv_size, MapData, MapError}, | ||
sys::{bpf_map_lookup_elem, PidFd, SyscallError}, | ||
Pod, | ||
}; | ||
|
||
/// Task storage is a type of map which uses `task_struct` kernel type as a | ||
/// key. When the task (process) stops, the corresponding entry is | ||
/// automatically removed. | ||
/// | ||
/// # Minimum kernel version | ||
/// | ||
/// The minimum kernel version required to use this feature is 5.12. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```no_run | ||
/// # let mut ebpf = aya::Ebpf::load(&[])?; | ||
/// use aya::maps::TaskStorage; | ||
/// | ||
/// let mut task_storage: TaskStorage<_, u32> = TaskStorage::try_from(ebpf.map_mut("TASK_STORAGE").unwrap())?; | ||
/// | ||
/// let pid = 0; | ||
/// let value = task_storage.get(&pid, 0)?; | ||
/// # Ok::<(), aya::EbpfError>(()) | ||
/// ``` | ||
#[doc(alias = "BPF_MAP_TYPE_TASK_STORAGE")] | ||
#[derive(Debug)] | ||
pub struct TaskStorage<T, V> { | ||
pub(crate) inner: T, | ||
_v: PhantomData<V>, | ||
} | ||
|
||
impl<T: Borrow<MapData>, V: Pod> TaskStorage<T, V> { | ||
pub(crate) fn new(map: T) -> Result<Self, MapError> { | ||
let data = map.borrow(); | ||
check_kv_size::<c_int, V>(data)?; | ||
Ok(Self { | ||
inner: map, | ||
_v: PhantomData, | ||
}) | ||
} | ||
|
||
/// Returns the value stored for the given `pid`. | ||
pub fn get(&self, pid: &u32, flags: u64) -> Result<V, MapError> { | ||
let pidfd = PidFd::open(*pid, 0).map_err(|(_, io_error)| SyscallError { | ||
call: "pidfd_open", | ||
io_error, | ||
})?; | ||
let map_fd = self.inner.borrow().fd().as_fd(); | ||
let value = | ||
bpf_map_lookup_elem(map_fd, &pidfd.as_raw_fd(), flags).map_err(|(_, io_error)| { | ||
SyscallError { | ||
call: "bpf_map_lookup_elem", | ||
io_error, | ||
} | ||
})?; | ||
value.ok_or(MapError::KeyNotFound) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::io; | ||
|
||
use assert_matches::assert_matches; | ||
use aya_obj::generated::bpf_map_type::BPF_MAP_TYPE_TASK_STORAGE; | ||
use libc::EFAULT; | ||
|
||
use crate::{ | ||
maps::{ | ||
test_utils::{self, new_map}, | ||
Map, | ||
}, | ||
sys::{override_syscall, SysResult, Syscall}, | ||
}; | ||
|
||
use super::*; | ||
|
||
fn new_obj_map() -> aya_obj::Map { | ||
test_utils::new_obj_map::<u32>(BPF_MAP_TYPE_TASK_STORAGE) | ||
} | ||
|
||
fn sys_error(value: i32) -> SysResult<i64> { | ||
Err((-1, io::Error::from_raw_os_error(value))) | ||
} | ||
|
||
#[test] | ||
fn test_wrong_value_size() { | ||
let map = new_map(new_obj_map()); | ||
let map = Map::TaskStorage(map); | ||
assert_matches!( | ||
TaskStorage::<_, u16>::try_from(&map), | ||
Err(MapError::InvalidValueSize { | ||
size: 2, | ||
expected: 4 | ||
}) | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_try_from_wrong_map() { | ||
let map = new_map(new_obj_map()); | ||
let map = Map::Array(map); | ||
assert_matches!( | ||
TaskStorage::<_, u32>::try_from(&map), | ||
Err(MapError::InvalidMapType { .. }) | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_new_ok() { | ||
let map = new_map(new_obj_map()); | ||
assert!(TaskStorage::<_, u32>::new(&map).is_ok()); | ||
} | ||
|
||
#[test] | ||
fn test_try_from_ok() { | ||
let map = new_map(new_obj_map()); | ||
let map = Map::TaskStorage(map); | ||
assert!(TaskStorage::<_, u32>::try_from(&map).is_ok()); | ||
} | ||
|
||
#[test] | ||
fn test_get_pidfd_syscall_error() { | ||
let mut map = new_map(new_obj_map()); | ||
let map = TaskStorage::<_, u32>::new(&mut map).unwrap(); | ||
|
||
override_syscall(|call| match call { | ||
Syscall::Ebpf { .. } => Ok(1), | ||
Syscall::PidfdOpen { .. } => sys_error(EFAULT), | ||
_ => sys_error(EFAULT), | ||
}); | ||
|
||
assert_matches!( | ||
map.get(&1, 0), Err(MapError::SyscallError( | ||
SyscallError { | ||
call: "pidfd_open", | ||
io_error | ||
} | ||
)) | ||
if io_error.raw_os_error() == Some(EFAULT) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
use std::os::fd::{AsRawFd, FromRawFd, RawFd}; | ||
|
||
use libc::pid_t; | ||
|
||
use crate::{ | ||
sys::{SysResult, Syscall}, | ||
MockableFd, | ||
}; | ||
|
||
/// A file descriptor of a process. | ||
/// | ||
/// A similar type is provided by the Rust standard library as | ||
/// [`std::os::linux::process`] as a nigtly-only experimental API. We are | ||
/// planning to migrate to it once it stabilizes. | ||
pub(crate) struct PidFd(MockableFd); | ||
|
||
impl PidFd { | ||
pub(crate) fn open(pid: u32, flags: u32) -> SysResult<Self> { | ||
let pid_fd = pidfd_open(pid, flags)? as RawFd; | ||
let pid_fd = unsafe { MockableFd::from_raw_fd(pid_fd) }; | ||
Ok(Self(pid_fd)) | ||
} | ||
} | ||
|
||
impl AsRawFd for PidFd { | ||
fn as_raw_fd(&self) -> RawFd { | ||
self.0.as_raw_fd() | ||
} | ||
} | ||
|
||
fn pidfd_open(pid: u32, flags: u32) -> SysResult<i64> { | ||
let call = Syscall::PidfdOpen { | ||
pid: pid as pid_t, | ||
flags, | ||
}; | ||
#[cfg(not(test))] | ||
return crate::sys::syscall(call); | ||
#[cfg(test)] | ||
return crate::sys::TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// clang-format off | ||
#include <vmlinux.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_core_read.h> | ||
#include <bpf/bpf_tracing.h> | ||
// clang-format on | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_TASK_STORAGE); | ||
__uint(map_flags, BPF_F_NO_PREALLOC); | ||
__type(key, int); | ||
__type(value, __u32); | ||
} task_storage SEC(".maps"); | ||
|
||
SEC("fentry/security_task_alloc") | ||
int BPF_PROG(task_alloc, struct task_struct *task, unsigned long clone_flags) { | ||
__u32 value = 1; | ||
bpf_task_storage_get(&task_storage, task, &value, | ||
BPF_LOCAL_STORAGE_GET_F_CREATE); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ mod relocations; | |
mod ring_buf; | ||
mod smoke; | ||
mod strncmp; | ||
mod task_storage; | ||
mod tcx; | ||
mod uprobe_cookie; | ||
mod xdp; |
Oops, something went wrong.