aya: Add BPF_PROG_TYPE_CGROUP_SOCK_ADDR

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/261/head
Dave Tucker 3 years ago
parent 41a27e3784
commit af54b6c818

@ -22,10 +22,10 @@ use crate::{
MapKind, Object, ParseError, ProgramSection,
},
programs::{
BtfTracePoint, CgroupSkb, CgroupSkbAttachType, CgroupSysctl, Extension, FEntry, FExit,
KProbe, LircMode2, Lsm, PerfEvent, ProbeKind, Program, ProgramData, ProgramError,
RawTracePoint, SchedClassifier, SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint,
UProbe, Xdp,
BtfTracePoint, CgroupSkb, CgroupSkbAttachType, CgroupSockAddr, CgroupSysctl, Extension,
FEntry, FExit, KProbe, LircMode2, Lsm, PerfEvent, ProbeKind, Program, ProgramData,
ProgramError, RawTracePoint, SchedClassifier, SkMsg, SkSkb, SkSkbKind, SockOps,
SocketFilter, TracePoint, UProbe, Xdp,
},
sys::{
bpf_load_btf, bpf_map_freeze, bpf_map_update_elem_ptr, is_btf_datasec_supported,
@ -481,6 +481,12 @@ impl<'a> BpfLoader<'a> {
data: ProgramData::new(prog_name, obj, btf_fd),
expected_attach_type: Some(CgroupSkbAttachType::Egress),
}),
ProgramSection::CgroupSockAddr { attach_type, .. } => {
Program::CgroupSockAddr(CgroupSockAddr {
data: ProgramData::new(prog_name, obj, btf_fd),
attach_type: *attach_type,
})
}
ProgramSection::LircMode2 { .. } => Program::LircMode2(LircMode2 {
data: ProgramData::new(prog_name, obj, btf_fd),
}),

@ -21,6 +21,7 @@ use crate::{
bpf_map_def,
generated::{bpf_insn, bpf_map_type::BPF_MAP_TYPE_ARRAY, BPF_F_RDONLY_PROG},
obj::btf::{Btf, BtfError, BtfExt},
programs::CgroupSockAddrAttachType,
BpfError,
};
use std::slice::from_raw_parts_mut;
@ -104,30 +105,82 @@ pub(crate) struct Function {
#[derive(Debug, Clone)]
pub enum ProgramSection {
KRetProbe { name: String },
KProbe { name: String },
UProbe { name: String },
URetProbe { name: String },
TracePoint { name: String },
SocketFilter { name: String },
Xdp { name: String },
SkMsg { name: String },
SkSkbStreamParser { name: String },
SkSkbStreamVerdict { name: String },
SockOps { name: String },
SchedClassifier { name: String },
CgroupSkb { name: String },
CgroupSkbIngress { name: String },
CgroupSkbEgress { name: String },
CgroupSysctl { name: String },
LircMode2 { name: String },
PerfEvent { name: String },
RawTracePoint { name: String },
Lsm { name: String },
BtfTracePoint { name: String },
FEntry { name: String },
FExit { name: String },
Extension { name: String },
KRetProbe {
name: String,
},
KProbe {
name: String,
},
UProbe {
name: String,
},
URetProbe {
name: String,
},
TracePoint {
name: String,
},
SocketFilter {
name: String,
},
Xdp {
name: String,
},
SkMsg {
name: String,
},
SkSkbStreamParser {
name: String,
},
SkSkbStreamVerdict {
name: String,
},
SockOps {
name: String,
},
SchedClassifier {
name: String,
},
CgroupSkb {
name: String,
},
CgroupSkbIngress {
name: String,
},
CgroupSkbEgress {
name: String,
},
CgroupSockAddr {
name: String,
attach_type: CgroupSockAddrAttachType,
},
CgroupSysctl {
name: String,
},
LircMode2 {
name: String,
},
PerfEvent {
name: String,
},
RawTracePoint {
name: String,
},
Lsm {
name: String,
},
BtfTracePoint {
name: String,
},
FEntry {
name: String,
},
FExit {
name: String,
},
Extension {
name: String,
},
}
impl ProgramSection {
@ -145,9 +198,10 @@ impl ProgramSection {
ProgramSection::SkSkbStreamVerdict { name } => name,
ProgramSection::SockOps { name } => name,
ProgramSection::SchedClassifier { name } => name,
ProgramSection::CgroupSkb { name } => name,
ProgramSection::CgroupSkbIngress { name } => name,
ProgramSection::CgroupSkbEgress { name } => name,
ProgramSection::CgroupSkb { name, .. } => name,
ProgramSection::CgroupSkbIngress { name, .. } => name,
ProgramSection::CgroupSkbEgress { name, .. } => name,
ProgramSection::CgroupSockAddr { name, .. } => name,
ProgramSection::CgroupSysctl { name } => name,
ProgramSection::LircMode2 { name } => name,
ProgramSection::PerfEvent { name } => name,
@ -221,11 +275,63 @@ impl FromStr for ProgramSection {
"skb" => CgroupSkb { name },
"sysctl" => CgroupSysctl { name },
_ => {
return Err(ParseError::InvalidProgramSection {
section: section.to_owned(),
})
if let Ok(attach_type) = CgroupSockAddrAttachType::try_from(name.as_str()) {
CgroupSockAddr { name, attach_type }
} else {
return Err(ParseError::InvalidProgramSection {
section: section.to_owned(),
});
}
}
},
"cgroup/bind4" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::Bind4,
},
"cgroup/bind6" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::Bind6,
},
"cgroup/connect4" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::Connect4,
},
"cgroup/connect6" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::Connect6,
},
"cgroup/getpeername4" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::GetPeerName4,
},
"cgroup/getpeername6" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::GetPeerName6,
},
"cgroup/getsockname4" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::GetSockName4,
},
"cgroup/getsockname6" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::GetSockName6,
},
"cgroup/sendmsg4" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::UDPSendMsg4,
},
"cgroup/sendmsg6" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::UDPSendMsg6,
},
"cgroup/recvmsg4" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::UDPRecvMsg4,
},
"cgroup/recvmsg6" => CgroupSockAddr {
name,
attach_type: CgroupSockAddrAttachType::UDPRecvMsg6,
},
"lirc_mode2" => LircMode2 { name },
"perf_event" => PerfEvent { name },
"raw_tp" | "raw_tracepoint" => RawTracePoint { name },
@ -1641,6 +1747,54 @@ mod tests {
);
}
#[test]
fn test_parse_section_sock_addr_named() {
let mut obj = fake_obj();
assert_matches!(
obj.parse_section(fake_section(
BpfSectionKind::Program,
"cgroup/connect4/foo",
bytes_of(&fake_ins())
)),
Ok(())
);
assert_matches!(
obj.programs.get("foo"),
Some(Program {
section: ProgramSection::CgroupSockAddr {
attach_type: CgroupSockAddrAttachType::Connect4,
..
},
..
})
);
}
#[test]
fn test_parse_section_sock_addr_unnamed() {
let mut obj = fake_obj();
assert_matches!(
obj.parse_section(fake_section(
BpfSectionKind::Program,
"cgroup/connect4",
bytes_of(&fake_ins())
)),
Ok(())
);
assert_matches!(
obj.programs.get("connect4"),
Some(Program {
section: ProgramSection::CgroupSockAddr {
attach_type: CgroupSockAddrAttachType::Connect4,
..
},
..
})
);
}
#[test]
fn test_patch_map_data() {
let mut obj = fake_obj();

@ -0,0 +1,233 @@
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_ADDR,
programs::{
define_link_wrapper, load_program, FdLink, Link, OwnedLink, ProgAttachLink, ProgramData,
ProgramError,
},
sys::{bpf_link_create, bpf_prog_attach, kernel_version},
};
/// A program that can be used to inspect or modify socket addresses (`struct sockaddr`).
///
/// [`SockAddr`] programs can be used to inspect or modify socket addresses passed to
/// various syscalls within a [cgroup]. They can be attached to a number of different
/// places as described in [`SockAddrAttachType`].
///
/// [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.17.
///
/// # 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::{CgroupSockAddr, CgroupSockAddrAttachType};
///
/// let file = File::open("/sys/fs/cgroup/unified")?;
/// let egress: &mut CgroupSockAddr = bpf.program_mut("connect4").unwrap().try_into()?;
/// egress.load()?;
/// egress.attach(file)?;
/// # Ok::<(), Error>(())
/// ```
#[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_CGROUP_SOCK_ADDR")]
pub struct CgroupSockAddr {
pub(crate) data: ProgramData<CgroupSockAddrLink>,
pub(crate) attach_type: CgroupSockAddrAttachType,
}
impl CgroupSockAddr {
/// 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_ADDR, &mut self.data)
}
/// Attaches the program to the given cgroup.
///
/// The returned value can be used to detach, see [SockAddr::detach].
pub fn attach<T: AsRawFd>(&mut self, cgroup: T) -> Result<CgroupSockAddrLinkId, 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(CgroupSockAddrLink(CgroupSockAddrLinkInner::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(CgroupSockAddrLink(CgroupSockAddrLinkInner::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 forget_link(
&mut self,
link_id: CgroupSockAddrLinkId,
) -> Result<OwnedLink<CgroupSockAddrLink>, ProgramError> {
Ok(OwnedLink::new(self.data.forget_link(link_id)?))
}
/// Detaches the program.
///
/// See [SockAddr::attach].
pub fn detach(&mut self, link_id: CgroupSockAddrLinkId) -> Result<(), ProgramError> {
self.data.links.remove(link_id)
}
}
#[derive(Debug, Hash, Eq, PartialEq)]
enum CgroupSockAddrLinkIdInner {
Fd(<FdLink as Link>::Id),
ProgAttach(<ProgAttachLink as Link>::Id),
}
#[derive(Debug)]
enum CgroupSockAddrLinkInner {
Fd(FdLink),
ProgAttach(ProgAttachLink),
}
impl Link for CgroupSockAddrLinkInner {
type Id = CgroupSockAddrLinkIdInner;
fn id(&self) -> Self::Id {
match self {
CgroupSockAddrLinkInner::Fd(fd) => CgroupSockAddrLinkIdInner::Fd(fd.id()),
CgroupSockAddrLinkInner::ProgAttach(p) => CgroupSockAddrLinkIdInner::ProgAttach(p.id()),
}
}
fn detach(self) -> Result<(), ProgramError> {
match self {
CgroupSockAddrLinkInner::Fd(fd) => fd.detach(),
CgroupSockAddrLinkInner::ProgAttach(p) => p.detach(),
}
}
}
define_link_wrapper!(
/// The link used by [SockAddr] programs.
CgroupSockAddrLink,
/// The type returned by [SockAddr::attach]. Can be passed to [SockAddr::detach].
CgroupSockAddrLinkId,
CgroupSockAddrLinkInner,
CgroupSockAddrLinkIdInner
);
/// Defines where to attach a [`SockAddr`] program.
#[derive(Copy, Clone, Debug)]
pub enum CgroupSockAddrAttachType {
/// Attach to IPv4 bind events.
Bind4,
/// Attach to IPv6 bind events.
Bind6,
/// Attach to IPv4 connect events.
Connect4,
/// Attach to IPv6 connect events.
Connect6,
/// Attach to IPv4 getpeername events.
GetPeerName4,
/// Attach to IPv6 getpeername events.
GetPeerName6,
/// Attach to IPv4 getsockname events.
GetSockName4,
/// Attach to IPv6 getsockname events.
GetSockName6,
/// Attach to IPv4 udp_sendmsg events.
UDPSendMsg4,
/// Attach to IPv6 udp_sendmsg events.
UDPSendMsg6,
/// Attach to IPv4 udp_recvmsg events.
UDPRecvMsg4,
/// Attach to IPv6 udp_recvmsg events.
UDPRecvMsg6,
}
impl From<CgroupSockAddrAttachType> for bpf_attach_type {
fn from(s: CgroupSockAddrAttachType) -> bpf_attach_type {
match s {
CgroupSockAddrAttachType::Bind4 => bpf_attach_type::BPF_CGROUP_INET4_BIND,
CgroupSockAddrAttachType::Bind6 => bpf_attach_type::BPF_CGROUP_INET6_BIND,
CgroupSockAddrAttachType::Connect4 => bpf_attach_type::BPF_CGROUP_INET4_CONNECT,
CgroupSockAddrAttachType::Connect6 => bpf_attach_type::BPF_CGROUP_INET6_CONNECT,
CgroupSockAddrAttachType::GetPeerName4 => bpf_attach_type::BPF_CGROUP_INET4_GETPEERNAME,
CgroupSockAddrAttachType::GetPeerName6 => bpf_attach_type::BPF_CGROUP_INET6_GETPEERNAME,
CgroupSockAddrAttachType::GetSockName4 => bpf_attach_type::BPF_CGROUP_INET4_GETSOCKNAME,
CgroupSockAddrAttachType::GetSockName6 => bpf_attach_type::BPF_CGROUP_INET6_GETSOCKNAME,
CgroupSockAddrAttachType::UDPSendMsg4 => bpf_attach_type::BPF_CGROUP_UDP4_SENDMSG,
CgroupSockAddrAttachType::UDPSendMsg6 => bpf_attach_type::BPF_CGROUP_UDP6_SENDMSG,
CgroupSockAddrAttachType::UDPRecvMsg4 => bpf_attach_type::BPF_CGROUP_UDP4_RECVMSG,
CgroupSockAddrAttachType::UDPRecvMsg6 => bpf_attach_type::BPF_CGROUP_UDP6_RECVMSG,
}
}
}
#[derive(Debug, Error)]
#[error("{0} is not a valid attach type for a CGROUP_SOCK_ADDR program")]
pub(crate) struct InvalidAttachType(String);
impl CgroupSockAddrAttachType {
pub(crate) fn try_from(value: &str) -> Result<CgroupSockAddrAttachType, InvalidAttachType> {
match value {
"bind4" => Ok(CgroupSockAddrAttachType::Bind4),
"bind6" => Ok(CgroupSockAddrAttachType::Bind6),
"connect4" => Ok(CgroupSockAddrAttachType::Connect4),
"connect6" => Ok(CgroupSockAddrAttachType::Connect6),
"getpeername4" => Ok(CgroupSockAddrAttachType::GetPeerName4),
"getpeername6" => Ok(CgroupSockAddrAttachType::GetPeerName6),
"getsockname4" => Ok(CgroupSockAddrAttachType::GetSockName4),
"getsockname6" => Ok(CgroupSockAddrAttachType::GetSockName6),
"sendmsg4" => Ok(CgroupSockAddrAttachType::UDPSendMsg4),
"sendmsg6" => Ok(CgroupSockAddrAttachType::UDPSendMsg6),
"recvmsg4" => Ok(CgroupSockAddrAttachType::UDPRecvMsg4),
"recvmsg6" => Ok(CgroupSockAddrAttachType::UDPRecvMsg6),
_ => Err(InvalidAttachType(value.to_owned())),
}
}
}

@ -37,6 +37,7 @@
//! [`Bpf::program_mut`]: crate::Bpf::program_mut
//! [`maps`]: crate::maps
mod cgroup_skb;
mod cgroup_sock_addr;
mod cgroup_sysctl;
mod extension;
mod fentry;
@ -71,6 +72,7 @@ use std::{
use thiserror::Error;
pub use cgroup_skb::{CgroupSkb, CgroupSkbAttachType};
pub use cgroup_sock_addr::{CgroupSockAddr, CgroupSockAddrAttachType};
pub use cgroup_sysctl::CgroupSysctl;
pub use extension::{Extension, ExtensionError};
pub use fentry::FEntry;
@ -229,6 +231,8 @@ pub enum Program {
SkMsg(SkMsg),
/// A [`SkSkb`] program
SkSkb(SkSkb),
/// A [`CgroupSockAddr`] program
CgroupSockAddr(CgroupSockAddr),
/// A [`SockOps`] program
SockOps(SockOps),
/// A [`SchedClassifier`] program
@ -279,6 +283,7 @@ impl Program {
Program::FEntry(_) => BPF_PROG_TYPE_TRACING,
Program::FExit(_) => BPF_PROG_TYPE_TRACING,
Program::Extension(_) => BPF_PROG_TYPE_EXT,
Program::CgroupSockAddr(_) => BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
}
}
@ -304,6 +309,7 @@ impl Program {
Program::FEntry(p) => p.data.pin(path),
Program::FExit(p) => p.data.pin(path),
Program::Extension(p) => p.data.pin(path),
Program::CgroupSockAddr(p) => p.data.pin(path),
}
}
}
@ -509,6 +515,7 @@ impl ProgramFd for Program {
Program::FEntry(p) => p.data.fd,
Program::FExit(p) => p.data.fd,
Program::Extension(p) => p.data.fd,
Program::CgroupSockAddr(p) => p.data.fd,
}
}
}
@ -556,6 +563,7 @@ impl_program_fd!(
FEntry,
FExit,
Extension,
CgroupSockAddr,
);
macro_rules! impl_try_from_program {
@ -606,6 +614,7 @@ impl_try_from_program!(
FEntry,
FExit,
Extension,
CgroupSockAddr,
);
/// Provides information about a loaded program, like name, id and statistics

Loading…
Cancel
Save