mirror of https://github.com/aya-rs/aya
Add support for BPF_PROG_TYPE_CGROUP_DEVICE
Kernel 4.15 added a new eBPF program that can be used with cgroup v2 to control & observe device access (e.g. read, write, mknod) - `BPF_PROG_TYPE_CGROUP_DEVICE`. We add the ability to create these programs with the `cgroup_device` proc macro which creates the `cgroup/dev` link section. Device details are available to the eBPF program in `DeviceContext`. The userspace representation is provided with the `CgroupDevice` structure. Fixes: #212 Signed-off-by: Milan <milan@mdaverde.com>pull/466/head
parent
9ce1530695
commit
8f1163a400
@ -0,0 +1,135 @@
|
|||||||
|
//! Cgroup device programs.
|
||||||
|
use std::os::unix::prelude::{AsRawFd, RawFd};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
generated::{bpf_attach_type::BPF_CGROUP_DEVICE, bpf_prog_type::BPF_PROG_TYPE_CGROUP_DEVICE},
|
||||||
|
programs::{
|
||||||
|
define_link_wrapper, load_program, FdLink, Link, ProgAttachLink, ProgramData, ProgramError,
|
||||||
|
},
|
||||||
|
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A program used to watch or prevent device interaction from a cgroup
|
||||||
|
///
|
||||||
|
/// [`CgroupDevice`] programs can be attached to a cgroup and will be called every
|
||||||
|
/// time a process inside that cgroup tries to access (e.g. read, write, mknod)
|
||||||
|
/// a device (identified through its major and minor number). See
|
||||||
|
/// [mknod](https://man7.org/linux/man-pages/man2/mknod.2.html) as a starting point.
|
||||||
|
///
|
||||||
|
/// # Minimum kernel version
|
||||||
|
///
|
||||||
|
/// The minimum kernel version required to use this feature is [4.15](https://github.com/torvalds/linux/commit/ebc614f687369f9df99828572b1d85a7c2de3d92).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use aya::programs::CgroupDevice;
|
||||||
|
///
|
||||||
|
/// let cgroup = std::fs::File::open("/sys/fs/cgroup/unified")?;
|
||||||
|
/// let program: &mut CgroupDevice = bpf.program_mut("cgroup_dev").unwrap().try_into()?;
|
||||||
|
/// program.load()?;
|
||||||
|
/// program.attach(cgroup)?;
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[doc(alias = "BPF_PROG_TYPE_CGROUP_DEVICE")]
|
||||||
|
pub struct CgroupDevice {
|
||||||
|
pub(crate) data: ProgramData<CgroupDeviceLink>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CgroupDevice {
|
||||||
|
/// Loads the program inside the kernel
|
||||||
|
pub fn load(&mut self) -> Result<(), ProgramError> {
|
||||||
|
load_program(BPF_PROG_TYPE_CGROUP_DEVICE, &mut self.data)
|
||||||
|
}
|
||||||
|
/// Attaches the program to the given cgroup.
|
||||||
|
///
|
||||||
|
/// The returned value can be used to detach, see [CgroupDevice::detach]
|
||||||
|
pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupDeviceLinkId, ProgramError> {
|
||||||
|
let prog_fd = self.data.fd_or_err()?;
|
||||||
|
let cgroup_fd = cgroup.as_raw_fd();
|
||||||
|
|
||||||
|
let k_ver = kernel_version().unwrap();
|
||||||
|
if k_ver >= (5, 7, 0) {
|
||||||
|
let link_fd = bpf_link_create(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE, None, 0).map_err(
|
||||||
|
|(_, io_error)| ProgramError::SyscallError {
|
||||||
|
call: "bpf_link_create".to_owned(),
|
||||||
|
io_error,
|
||||||
|
},
|
||||||
|
)? as RawFd;
|
||||||
|
self.data
|
||||||
|
.links
|
||||||
|
.insert(CgroupDeviceLink(CgroupDeviceLinkInner::Fd(FdLink::new(
|
||||||
|
link_fd,
|
||||||
|
))))
|
||||||
|
} else {
|
||||||
|
bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE).map_err(|(_, io_error)| {
|
||||||
|
ProgramError::SyscallError {
|
||||||
|
call: "bpf_prog_attach".to_owned(),
|
||||||
|
io_error,
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
self.data
|
||||||
|
.links
|
||||||
|
.insert(CgroupDeviceLink(CgroupDeviceLinkInner::ProgAttach(
|
||||||
|
ProgAttachLink::new(prog_fd, cgroup_fd, BPF_CGROUP_DEVICE),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes ownership of the link referenced by the provided link_id.
|
||||||
|
///
|
||||||
|
/// The link will be detached on `Drop` and the caller is now responsible
|
||||||
|
/// for managing its lifetime.
|
||||||
|
pub fn take_link(
|
||||||
|
&mut self,
|
||||||
|
link_id: CgroupDeviceLinkId,
|
||||||
|
) -> Result<CgroupDeviceLink, ProgramError> {
|
||||||
|
self.data.take_link(link_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Detaches the program
|
||||||
|
///
|
||||||
|
/// See [CgroupDevice::attach].
|
||||||
|
pub fn detach(&mut self, link_id: CgroupDeviceLinkId) -> Result<(), ProgramError> {
|
||||||
|
self.data.links.remove(link_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Hash, Eq, PartialEq)]
|
||||||
|
enum CgroupDeviceLinkIdInner {
|
||||||
|
Fd(<FdLink as Link>::Id),
|
||||||
|
ProgAttach(<ProgAttachLink as Link>::Id),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum CgroupDeviceLinkInner {
|
||||||
|
Fd(FdLink),
|
||||||
|
ProgAttach(ProgAttachLink),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Link for CgroupDeviceLinkInner {
|
||||||
|
type Id = CgroupDeviceLinkIdInner;
|
||||||
|
|
||||||
|
fn id(&self) -> Self::Id {
|
||||||
|
match self {
|
||||||
|
CgroupDeviceLinkInner::Fd(fd) => CgroupDeviceLinkIdInner::Fd(fd.id()),
|
||||||
|
CgroupDeviceLinkInner::ProgAttach(p) => CgroupDeviceLinkIdInner::ProgAttach(p.id()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detach(self) -> Result<(), ProgramError> {
|
||||||
|
match self {
|
||||||
|
CgroupDeviceLinkInner::Fd(fd) => fd.detach(),
|
||||||
|
CgroupDeviceLinkInner::ProgAttach(p) => p.detach(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define_link_wrapper!(
|
||||||
|
/// The link used by [CgroupDevice] programs.
|
||||||
|
CgroupDeviceLink,
|
||||||
|
/// The type returned by [CgroupDevice::attach]. Can be passed to [CgroupDevice::detach].
|
||||||
|
CgroupDeviceLinkId,
|
||||||
|
CgroupDeviceLinkInner,
|
||||||
|
CgroupDeviceLinkIdInner
|
||||||
|
);
|
@ -0,0 +1,19 @@
|
|||||||
|
use core::ffi::c_void;
|
||||||
|
|
||||||
|
use crate::{bindings::bpf_cgroup_dev_ctx, BpfContext};
|
||||||
|
|
||||||
|
pub struct DeviceContext {
|
||||||
|
pub device: *mut bpf_cgroup_dev_ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceContext {
|
||||||
|
pub fn new(device: *mut bpf_cgroup_dev_ctx) -> DeviceContext {
|
||||||
|
DeviceContext { device }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BpfContext for DeviceContext {
|
||||||
|
fn as_ptr(&self) -> *mut c_void {
|
||||||
|
self.device as *mut _
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue