Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LSM cgroup attachment type support #1041

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions aya-ebpf-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ use sk_msg::SkMsg;
use sk_skb::{SkSkb, SkSkbKind};
use sock_ops::SockOps;
use socket_filter::SocketFilter;
use syn::parse_macro_input;
use tc::SchedClassifier;
use tracepoint::TracePoint;
use uprobe::{UProbe, UProbeKind};
Expand Down
100 changes: 80 additions & 20 deletions aya-ebpf-macros/src/lsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::args::{err_on_unknown_args, pop_bool_arg, pop_string_arg};
pub(crate) struct Lsm {
item: ItemFn,
hook: Option<String>,
cgroup: bool,
sleepable: bool,
}

Expand All @@ -17,38 +18,68 @@ impl Lsm {
let item = syn::parse2(item)?;
let mut args = syn::parse2(attrs)?;
let hook = pop_string_arg(&mut args, "hook");
let cgroup = pop_bool_arg(&mut args, "cgroup");
let sleepable = pop_bool_arg(&mut args, "sleepable");

err_on_unknown_args(&args)?;
Ok(Lsm {
item,
hook,
cgroup,
sleepable,
})
}

pub(crate) fn expand(&self) -> Result<TokenStream> {
let section_prefix = if self.sleepable { "lsm.s" } else { "lsm" };
let section_name: Cow<'_, _> = if let Some(hook) = &self.hook {
format!("{}/{}", section_prefix, hook).into()
} else {
section_prefix.into()
};
let fn_vis = &self.item.vis;
let fn_name = self.item.sig.ident.clone();
let item = &self.item;
// LSM probes need to return an integer corresponding to the correct
// policy decision. Therefore we do not simply default to a return value
// of 0 as in other program types.
Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
#fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
return #fn_name(::aya_ebpf::programs::LsmContext::new(ctx));

if self.cgroup{
let section_name = if let Some(name) = &self.hook{
format!("lsm_cgroup/{}", name)
}else{
("lsm_cgroup").to_owned()
};

let fn_name = &self.item.sig.ident;
let item = &self.item;

#item
}
})
Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
return #fn_name(::aya_ebpf::programs::LsmContext::new(ctx));

#item
}
})

}else{
let section_prefix = if self.sleepable { "lsm.s" } else { "lsm" };
let section_name: Cow<'_, _> = if let Some(hook) = &self.hook {
format!("{}/{}", section_prefix, hook).into()
} else {
section_prefix.into()
};

let fn_vis = &self.item.vis;
let fn_name = self.item.sig.ident.clone();
let item = &self.item;

Ok(quote! {
#[no_mangle]
#[link_section = #section_name]
#fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
return #fn_name(::aya_ebpf::programs::LsmContext::new(ctx));

#item
}
})
}

}

// LSM probes need to return an integer corresponding to the correct
// policy decision. Therefore we do not simply default to a return value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is something going wrong with your code formatting. Not only here. Can you fix it with rustfmt locally?

// of 0 as in other program types.
}

#[cfg(test)]
Expand Down Expand Up @@ -113,4 +144,33 @@ mod tests {
};
assert_eq!(expected.to_string(), expanded.to_string());
}

#[test]
fn test_lsm_cgroup() {
let prog = Lsm::parse(
parse_quote! {
hook = "bprm_committed_creds",
cgroup
},
parse_quote! {
fn bprm_committed_creds(ctx: &mut ::aya_ebpf::programs::LsmContext) -> i32 {
0
}
},
)
.unwrap();
let expanded = prog.expand().unwrap();
let expected = quote! {
#[no_mangle]
#[link_section = "lsm_cgroup/bprm_committed_creds"]
fn bprm_committed_creds(ctx: *mut ::core::ffi::c_void) -> i32 {
return bprm_committed_creds(::aya_ebpf::programs::LsmContext::new(ctx));

fn bprm_committed_creds(ctx: &mut ::aya_ebpf::programs::LsmContext) -> i32 {
0
}
}
};
assert_eq!(expected.to_string(), expanded.to_string());
}
}
37 changes: 33 additions & 4 deletions aya-obj/src/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::{
},
maps::{bpf_map_def, BtfMap, BtfMapDef, LegacyMap, Map, PinningType, MINIMUM_MAP_SIZE},
programs::{
CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType, XdpAttachType,
CgroupSockAddrAttachType, CgroupSockAttachType, CgroupSockoptAttachType, LsmAttachType, XdpAttachType
},
relocation::*,
util::HashMap,
Expand Down Expand Up @@ -275,6 +275,7 @@ pub enum ProgramSection {
RawTracePoint,
Lsm {
sleepable: bool,
attach_type: LsmAttachType,
},
BtfTracePoint,
FEntry {
Expand Down Expand Up @@ -432,8 +433,9 @@ impl FromStr for ProgramSection {
"lirc_mode2" => LircMode2,
"perf_event" => PerfEvent,
"raw_tp" | "raw_tracepoint" => RawTracePoint,
"lsm" => Lsm { sleepable: false },
"lsm.s" => Lsm { sleepable: true },
"lsm" => Lsm { sleepable: false, attach_type: LsmAttachType::Mac},
"lsm.s" => Lsm { sleepable: true, attach_type: LsmAttachType::Mac },
"lsm_cgroup" => Lsm { sleepable: false, attach_type: LsmAttachType::Cgroup },
"fentry" => FEntry { sleepable: false },
"fentry.s" => FEntry { sleepable: true },
"fexit" => FExit { sleepable: false },
Expand Down Expand Up @@ -2175,7 +2177,7 @@ mod tests {
Some(Program {
section: ProgramSection::Lsm {
sleepable: false,
..
attach_type: LsmAttachType::Mac
},
..
})
Expand Down Expand Up @@ -2208,6 +2210,33 @@ mod tests {
);
}

#[test]
fn test_parse_section_lsm_cgroup() {
let mut obj = fake_obj();
fake_sym(&mut obj, 0, 0, "foo", FAKE_INS_LEN);

assert_matches!(
obj.parse_section(fake_section(
EbpfSectionKind::Program,
"lsm_cgroup/foo",
bytes_of(&fake_ins()),
None
)),
Ok(())
);
assert_matches!(
obj.programs.get("foo"),
Some(Program {
section: ProgramSection::Lsm {
sleepable: false,
attach_type: LsmAttachType::Cgroup
},
..
})
);
}


#[test]
fn test_parse_section_btf_tracepoint() {
let mut obj = fake_obj();
Expand Down
21 changes: 21 additions & 0 deletions aya-obj/src/programs/lsm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! XDP programs.

use crate::generated::bpf_attach_type;

/// Defines where to attach an `XDP` program.
#[derive(Copy, Clone, Debug)]
pub enum LsmAttachType {
/// Cgroup based LSM program
Cgroup,
/// MAC based LSM program
Mac,
}

impl From<LsmAttachType> for bpf_attach_type {
fn from(value: LsmAttachType) -> Self {
match value {
LsmAttachType::Cgroup => bpf_attach_type::BPF_LSM_CGROUP,
LsmAttachType::Mac => bpf_attach_type::BPF_LSM_MAC,
}
}
}
2 changes: 2 additions & 0 deletions aya-obj/src/programs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ pub mod cgroup_sock_addr;
pub mod cgroup_sockopt;
mod types;
pub mod xdp;
pub mod lsm;

pub use cgroup_sock::CgroupSockAttachType;
pub use cgroup_sock_addr::CgroupSockAddrAttachType;
pub use cgroup_sockopt::CgroupSockoptAttachType;
pub use xdp::XdpAttachType;
pub use lsm::LsmAttachType;
21 changes: 10 additions & 11 deletions aya/src/bpf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ use std::{
};

use aya_obj::{
btf::{BtfFeatures, BtfRelocationError},
generated::{BPF_F_SLEEPABLE, BPF_F_XDP_HAS_FRAGS},
relocation::EbpfRelocationError,
EbpfSectionKind, Features,
btf::{BtfFeatures, BtfRelocationError}, generated::{BPF_F_SLEEPABLE, BPF_F_XDP_HAS_FRAGS}, relocation::EbpfRelocationError, EbpfSectionKind, Features
};
use log::{debug, warn};
use thiserror::Error;
Expand All @@ -30,10 +27,7 @@ use crate::{
Object, ParseError, ProgramSection,
},
programs::{
BtfTracePoint, CgroupDevice, CgroupSkb, CgroupSkbAttachType, CgroupSock, CgroupSockAddr,
CgroupSockopt, CgroupSysctl, Extension, FEntry, FExit, KProbe, LircMode2, Lsm, PerfEvent,
ProbeKind, Program, ProgramData, ProgramError, RawTracePoint, SchedClassifier, SkLookup,
SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp,
BtfTracePoint, CgroupDevice, CgroupSkb, CgroupSkbAttachType, CgroupSock, CgroupSockAddr, CgroupSockopt, CgroupSysctl, Extension, FEntry, FExit, KProbe, LircMode2, Lsm, PerfEvent, ProbeKind, Program, ProgramData, ProgramError, RawTracePoint, SchedClassifier, SkLookup, SkMsg, SkSkb, SkSkbKind, SockOps, SocketFilter, TracePoint, UProbe, Xdp
},
sys::{
bpf_load_btf, is_bpf_cookie_supported, is_bpf_global_data_supported,
Expand Down Expand Up @@ -411,7 +405,7 @@ impl<'a> EbpfLoader<'a> {
ProgramSection::Extension
| ProgramSection::FEntry { sleepable: _ }
| ProgramSection::FExit { sleepable: _ }
| ProgramSection::Lsm { sleepable: _ }
| ProgramSection::Lsm { sleepable: _, attach_type: _ }
| ProgramSection::BtfTracePoint => {
return Err(EbpfError::BtfError(err))
}
Expand Down Expand Up @@ -650,13 +644,18 @@ impl<'a> EbpfLoader<'a> {
ProgramSection::RawTracePoint => Program::RawTracePoint(RawTracePoint {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
}),
ProgramSection::Lsm { sleepable } => {
ProgramSection::Lsm { sleepable , attach_type} => {
let mut data =
ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level);

if *sleepable {
data.flags = BPF_F_SLEEPABLE;
}
Program::Lsm(Lsm { data })

Program::Lsm(Lsm {
data,
attach_type: *attach_type,
})
}
ProgramSection::BtfTracePoint => Program::BtfTracePoint(BtfTracePoint {
data: ProgramData::new(prog_name, obj, btf_fd, *verifier_log_level),
Expand Down
Loading
Loading