aya: Implement BPF_PROG_TYPE_CGROUP_SOCK

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/315/head
Dave Tucker 2 years ago
parent 6f51b616e1
commit 7b21a2d17e

@ -22,9 +22,9 @@ use crate::{
MapKind, Object, ParseError, ProgramSection, MapKind, Object, ParseError, ProgramSection,
}, },
programs::{ programs::{
BtfTracePoint, CgroupSkb, CgroupSkbAttachType, CgroupSockAddr, CgroupSockopt, CgroupSysctl, BtfTracePoint, CgroupSkb, CgroupSkbAttachType, CgroupSock, CgroupSockAddr, CgroupSockopt,
Extension, FEntry, FExit, KProbe, LircMode2, Lsm, PerfEvent, ProbeKind, Program, CgroupSysctl, Extension, FEntry, FExit, KProbe, LircMode2, Lsm, PerfEvent, ProbeKind,
ProgramData, ProgramError, RawTracePoint, SchedClassifier, SkLookup, SkMsg, SkSkb, Program, ProgramData, ProgramError, RawTracePoint, SchedClassifier, SkLookup, SkMsg, SkSkb,
SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp,
}, },
sys::{ sys::{
@ -524,6 +524,12 @@ impl<'a> BpfLoader<'a> {
ProgramSection::SkLookup { .. } => Program::SkLookup(SkLookup { ProgramSection::SkLookup { .. } => Program::SkLookup(SkLookup {
data: ProgramData::new(prog_name, obj, btf_fd), data: ProgramData::new(prog_name, obj, btf_fd),
}), }),
ProgramSection::CgroupSock { attach_type, .. } => {
Program::CgroupSock(CgroupSock {
data: ProgramData::new(prog_name, obj, btf_fd),
attach_type: *attach_type,
})
}
} }
}; };
(name, program) (name, program)

@ -21,7 +21,7 @@ use crate::{
bpf_map_def, bpf_map_def,
generated::{bpf_insn, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG}, generated::{bpf_insn, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG},
obj::btf::{Btf, BtfError, BtfExt}, obj::btf::{Btf, BtfError, BtfExt},
programs::{CgroupSockAddrAttachType, CgroupSockoptAttachType}, programs::{CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType},
BpfError, BpfError,
}; };
use std::slice::from_raw_parts_mut; use std::slice::from_raw_parts_mut;
@ -188,6 +188,10 @@ pub enum ProgramSection {
SkLookup { SkLookup {
name: String, name: String,
}, },
CgroupSock {
name: String,
attach_type: CgroupSockAttachType,
},
} }
impl ProgramSection { impl ProgramSection {
@ -220,6 +224,7 @@ impl ProgramSection {
ProgramSection::FExit { name } => name, ProgramSection::FExit { name } => name,
ProgramSection::Extension { name } => name, ProgramSection::Extension { name } => name,
ProgramSection::SkLookup { name } => name, ProgramSection::SkLookup { name } => name,
ProgramSection::CgroupSock { name, .. } => name,
} }
} }
} }
@ -279,6 +284,10 @@ impl FromStr for ProgramSection {
"cgroup_skb/ingress" => CgroupSkbIngress { name }, "cgroup_skb/ingress" => CgroupSkbIngress { name },
"cgroup_skb/egress" => CgroupSkbEgress { name }, "cgroup_skb/egress" => CgroupSkbEgress { name },
"cgroup/skb" => CgroupSkb { name }, "cgroup/skb" => CgroupSkb { name },
"cgroup/sock" => CgroupSock {
name,
attach_type: CgroupSockAttachType::default(),
},
"cgroup/sysctl" => CgroupSysctl { name }, "cgroup/sysctl" => CgroupSysctl { name },
"cgroup/getsockopt" => CgroupSockopt { "cgroup/getsockopt" => CgroupSockopt {
name, name,
@ -300,6 +309,19 @@ impl FromStr for ProgramSection {
}); });
} }
} }
"sock" => CgroupSock {
name,
attach_type: CgroupSockAttachType::default(),
},
"post_bind4" | "post_bind6" | "sock_create" | "sock_release" => {
if let Ok(attach_type) = CgroupSockAttachType::try_from(name.as_str()) {
CgroupSock { name, attach_type }
} else {
return Err(ParseError::InvalidProgramSection {
section: section.to_owned(),
});
}
}
_ => { _ => {
if let Ok(attach_type) = CgroupSockAddrAttachType::try_from(name.as_str()) { if let Ok(attach_type) = CgroupSockAddrAttachType::try_from(name.as_str()) {
CgroupSockAddr { name, attach_type } CgroupSockAddr { name, attach_type }
@ -310,6 +332,22 @@ impl FromStr for ProgramSection {
} }
} }
}, },
"cgroup/post_bind4" => CgroupSock {
name,
attach_type: CgroupSockAttachType::PostBind4,
},
"cgroup/post_bind6" => CgroupSock {
name,
attach_type: CgroupSockAttachType::PostBind6,
},
"cgroup/sock_create" => CgroupSock {
name,
attach_type: CgroupSockAttachType::SockCreate,
},
"cgroup/sock_release" => CgroupSock {
name,
attach_type: CgroupSockAttachType::SockRelease,
},
"cgroup/bind4" => CgroupSockAddr { "cgroup/bind4" => CgroupSockAddr {
name, name,
attach_type: CgroupSockAddrAttachType::Bind4, attach_type: CgroupSockAddrAttachType::Bind4,

@ -0,0 +1,209 @@
//! Cgroup socket programs.
use thiserror::Error;
use crate::generated::bpf_attach_type;
use std::{
hash::Hash,
os::unix::prelude::{AsRawFd, RawFd},
};
use crate::{
generated::bpf_prog_type::BPF_PROG_TYPE_CGROUP_SOCK,
programs::{
define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgAttachLink, ProgramData,
ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
};
/// A program that is called on socket creation, bind and release.
///
/// [`CgroupSock`] programs can be used to allow or deny socket creation from
/// within a [cgroup], or they can be used to monitor and gather statistics.
///
/// [cgroup]: https://man7.org/linux/man-pages/man7/cgroups.7.html
///
/// # Minimum kernel version
///
/// The minimum kernel version required to use this feature is 4.10.
///
/// # Examples
///
/// ```no_run
/// # #[derive(thiserror::Error, Debug)]
/// # enum Error {
/// # #[error(transparent)]
/// # IO(#[from] std::io::Error),
/// # #[error(transparent)]
/// # Map(#[from] aya::maps::MapError),
/// # #[error(transparent)]
/// # Program(#[from] aya::programs::ProgramError),
/// # #[error(transparent)]
/// # Bpf(#[from] aya::BpfError)
/// # }
/// # let mut bpf = aya::Bpf::load(&[])?;
/// use std::fs::File;
/// use std::convert::TryInto;
/// use aya::programs::{CgroupSock, CgroupSockAttachType};
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let bind: &mut CgroupSock = bpf.program_mut("bind").unwrap().try_into()?;
/// bind.load()?;
/// bind.attach(file)?;
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCK")]
pub struct CgroupSock {
pub(crate) data: ProgramData<CgroupSockLink>,
pub(crate) attach_type: CgroupSockAttachType,
}
impl CgroupSock {
/// Loads the program inside the kernel.
pub fn load(&mut self) -> Result<(), ProgramError> {
self.data.expected_attach_type = Some(self.attach_type.into());
load_program(BPF_PROG_TYPE_CGROUP_SOCK, &mut self.data)
}
/// Attaches the program to the given cgroup.
///
/// The returned value can be used to detach, see [CgroupSock::detach].
pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockLinkId, ProgramError> {
let prog_fd = self.data.fd_or_err()?;
let cgroup_fd = cgroup.as_raw_fd();
let attach_type = self.data.expected_attach_type.unwrap();
let k_ver = kernel_version().unwrap();
if k_ver >= (5, 7, 0) {
let link_fd = bpf_link_create(prog_fd, cgroup_fd, attach_type, None, 0).map_err(
|(_, io_error)| ProgramError::SyscallError {
call: "bpf_link_create".to_owned(),
io_error,
},
)? as RawFd;
self.data
.links
.insert(CgroupSockLink(CgroupSockLinkInner::Fd(FdLink::new(
link_fd,
))))
} else {
bpf_prog_attach(prog_fd, cgroup_fd, attach_type).map_err(|(_, io_error)| {
ProgramError::SyscallError {
call: "bpf_prog_attach".to_owned(),
io_error,
}
})?;
self.data
.links
.insert(CgroupSockLink(CgroupSockLinkInner::ProgAttach(
ProgAttachLink::new(prog_fd, cgroup_fd, attach_type),
)))
}
}
/// 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: CgroupSockLinkId,
) -> Result<OwnedLink<CgroupSockLink>, ProgramError> {
Ok(OwnedLink::new(self.data.take_link(link_id)?))
}
/// Detaches the program.
///
/// See [CgroupSock::attach].
pub fn detach(&mut self, link_id: CgroupSockLinkId) -> Result<(), ProgramError> {
self.data.links.remove(link_id)
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
enum CgroupSockLinkIdInner {
Fd(<FdLink as Link>::Id),
ProgAttach(<ProgAttachLink as Link>::Id),
}
#[derive(Debug)]
enum CgroupSockLinkInner {
Fd(FdLink),
ProgAttach(ProgAttachLink),
}
impl Link for CgroupSockLinkInner {
type Id = CgroupSockLinkIdInner;
fn id(&self) -> Self::Id {
match self {
CgroupSockLinkInner::Fd(fd) => CgroupSockLinkIdInner::Fd(fd.id()),
CgroupSockLinkInner::ProgAttach(p) => CgroupSockLinkIdInner::ProgAttach(p.id()),
}
}
fn detach(self) -> Result<(), ProgramError> {
match self {
CgroupSockLinkInner::Fd(fd) => fd.detach(),
CgroupSockLinkInner::ProgAttach(p) => p.detach(),
}
}
}
define_link_wrapper!(
/// The link used by [CgroupSock] programs.
CgroupSockLink,
/// The type returned by [CgroupSock::attach]. Can be passed to [CgroupSock::detach].
CgroupSockLinkId,
CgroupSockLinkInner,
CgroupSockLinkIdInner
);
/// Defines where to attach a [`CgroupSock`] program.
#[derive(Copy, Clone, Debug)]
pub enum CgroupSockAttachType {
/// Called after the IPv4 bind events.
PostBind4,
/// Called after the IPv6 bind events.
PostBind6,
/// Attach to IPv4 connect events.
SockCreate,
/// Attach to IPv6 connect events.
SockRelease,
}
impl Default for CgroupSockAttachType {
// The kernel checks for a 0 attach_type and sets it to sock_create
// We may as well do that here also
fn default() -> Self {
CgroupSockAttachType::SockCreate
}
}
impl From<CgroupSockAttachType> for bpf_attach_type {
fn from(s: CgroupSockAttachType) -> bpf_attach_type {
match s {
CgroupSockAttachType::PostBind4 => bpf_attach_type::BPF_CGROUP_INET4_POST_BIND,
CgroupSockAttachType::PostBind6 => bpf_attach_type::BPF_CGROUP_INET6_POST_BIND,
CgroupSockAttachType::SockCreate => bpf_attach_type::BPF_CGROUP_INET_SOCK_CREATE,
CgroupSockAttachType::SockRelease => bpf_attach_type::BPF_CGROUP_INET_SOCK_RELEASE,
}
}
}
#[derive(Debug, Error)]
#[error("{0} is not a valid attach type for a CGROUP_SOCK program")]
pub(crate) struct InvalidAttachType(String);
impl CgroupSockAttachType {
pub(crate) fn try_from(value: &str) -> Result<CgroupSockAttachType, InvalidAttachType> {
match value {
"post_bind4" => Ok(CgroupSockAttachType::PostBind4),
"post_bind6" => Ok(CgroupSockAttachType::PostBind6),
"sock_create" => Ok(CgroupSockAttachType::SockCreate),
"sock_release" => Ok(CgroupSockAttachType::SockRelease),
_ => Err(InvalidAttachType(value.to_owned())),
}
}
}

@ -37,6 +37,7 @@
//! [`Bpf::program_mut`]: crate::Bpf::program_mut //! [`Bpf::program_mut`]: crate::Bpf::program_mut
//! [`maps`]: crate::maps //! [`maps`]: crate::maps
pub mod cgroup_skb; pub mod cgroup_skb;
pub mod cgroup_sock;
pub mod cgroup_sock_addr; pub mod cgroup_sock_addr;
pub mod cgroup_sockopt; pub mod cgroup_sockopt;
pub mod cgroup_sysctl; pub mod cgroup_sysctl;
@ -74,6 +75,7 @@ use std::{
use thiserror::Error; use thiserror::Error;
pub use cgroup_skb::{CgroupSkb, CgroupSkbAttachType}; pub use cgroup_skb::{CgroupSkb, CgroupSkbAttachType};
pub use cgroup_sock::{CgroupSock, CgroupSockAttachType};
pub use cgroup_sock_addr::{CgroupSockAddr, CgroupSockAddrAttachType}; pub use cgroup_sock_addr::{CgroupSockAddr, CgroupSockAddrAttachType};
pub use cgroup_sockopt::{CgroupSockopt, CgroupSockoptAttachType}; pub use cgroup_sockopt::{CgroupSockopt, CgroupSockoptAttachType};
pub use cgroup_sysctl::CgroupSysctl; pub use cgroup_sysctl::CgroupSysctl;
@ -265,6 +267,8 @@ pub enum Program {
Extension(Extension), Extension(Extension),
/// A [`SkLookup`] program /// A [`SkLookup`] program
SkLookup(SkLookup), SkLookup(SkLookup),
/// A [`CgroupSock`] program
CgroupSock(CgroupSock),
} }
impl Program { impl Program {
@ -294,6 +298,7 @@ impl Program {
Program::Extension(_) => BPF_PROG_TYPE_EXT, Program::Extension(_) => BPF_PROG_TYPE_EXT,
Program::CgroupSockAddr(_) => BPF_PROG_TYPE_CGROUP_SOCK_ADDR, Program::CgroupSockAddr(_) => BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
Program::SkLookup(_) => BPF_PROG_TYPE_SK_LOOKUP, Program::SkLookup(_) => BPF_PROG_TYPE_SK_LOOKUP,
Program::CgroupSock(_) => BPF_PROG_TYPE_CGROUP_SOCK,
} }
} }
@ -322,6 +327,7 @@ impl Program {
Program::Extension(p) => p.data.pin(path), Program::Extension(p) => p.data.pin(path),
Program::CgroupSockAddr(p) => p.data.pin(path), Program::CgroupSockAddr(p) => p.data.pin(path),
Program::SkLookup(p) => p.data.pin(path), Program::SkLookup(p) => p.data.pin(path),
Program::CgroupSock(p) => p.data.pin(path),
} }
} }
@ -350,6 +356,7 @@ impl Program {
Program::Extension(p) => p.unload(), Program::Extension(p) => p.unload(),
Program::CgroupSockAddr(p) => p.unload(), Program::CgroupSockAddr(p) => p.unload(),
Program::SkLookup(p) => p.unload(), Program::SkLookup(p) => p.unload(),
Program::CgroupSock(p) => p.unload(),
} }
} }
} }
@ -573,6 +580,7 @@ impl ProgramFd for Program {
Program::Extension(p) => p.data.fd, Program::Extension(p) => p.data.fd,
Program::CgroupSockAddr(p) => p.data.fd, Program::CgroupSockAddr(p) => p.data.fd,
Program::SkLookup(p) => p.data.fd, Program::SkLookup(p) => p.data.fd,
Program::CgroupSock(p) => p.data.fd,
} }
} }
} }
@ -622,7 +630,8 @@ impl_program_unload!(
Extension, Extension,
CgroupSockAddr, CgroupSockAddr,
SkLookup, SkLookup,
SockOps SockOps,
CgroupSock,
); );
macro_rules! impl_program_fd { macro_rules! impl_program_fd {
@ -665,6 +674,7 @@ impl_program_fd!(
Extension, Extension,
CgroupSockAddr, CgroupSockAddr,
SkLookup, SkLookup,
CgroupSock,
); );
macro_rules! impl_try_from_program { macro_rules! impl_try_from_program {
@ -718,6 +728,7 @@ impl_try_from_program!(
Extension, Extension,
CgroupSockAddr, CgroupSockAddr,
SkLookup, SkLookup,
CgroupSock,
); );
/// Provides information about a loaded program, like name, id and statistics /// Provides information about a loaded program, like name, id and statistics

Loading…
Cancel
Save