diff --git a/test-distro/src/init.rs b/test-distro/src/init.rs index ccc8cdfc..49cc94f2 100644 --- a/test-distro/src/init.rs +++ b/test-distro/src/init.rs @@ -97,6 +97,14 @@ fn run() -> anyhow::Result<()> { data: None, target_mode: None, }, + Mount { + source: "securityfs", + target: "/sys/kernel/security", + fstype: "securityfs", + flags: nix::mount::MsFlags::empty(), + data: None, + target_mode: None, + }, ] { match target_mode { None => { diff --git a/test/integration-ebpf/src/test.rs b/test/integration-ebpf/src/test.rs index b9c4bfdf..d7081044 100644 --- a/test/integration-ebpf/src/test.rs +++ b/test/integration-ebpf/src/test.rs @@ -4,24 +4,18 @@ use aya_ebpf::{ bindings::{bpf_ret_code, xdp_action}, - macros::{flow_dissector, kprobe, kretprobe, tracepoint, uprobe, uretprobe, xdp}, + macros::{flow_dissector, kprobe, kretprobe, lsm, tracepoint, uprobe, uretprobe, xdp}, programs::{ - FlowDissectorContext, ProbeContext, RetProbeContext, TracePointContext, XdpContext, + FlowDissectorContext, LsmContext, ProbeContext, RetProbeContext, TracePointContext, + XdpContext, }, }; #[cfg(not(test))] extern crate ebpf_panic; #[xdp] -fn pass(ctx: XdpContext) -> u32 { - match unsafe { try_pass(ctx) } { - Ok(ret) => ret, - Err(_) => xdp_action::XDP_ABORTED, - } -} - -unsafe fn try_pass(_ctx: XdpContext) -> Result { - Ok(xdp_action::XDP_PASS) +fn pass(_ctx: XdpContext) -> u32 { + xdp_action::XDP_PASS } #[kprobe] @@ -55,3 +49,8 @@ fn test_flow(_ctx: FlowDissectorContext) -> u32 { // Linux kernel for inspiration. bpf_ret_code::BPF_FLOW_DISSECTOR_CONTINUE } + +#[lsm(hook = "socket_bind")] +fn test_lsm(_ctx: LsmContext) -> i32 { + -1 // Disallow. +} diff --git a/test/integration-test/src/tests.rs b/test/integration-test/src/tests.rs index aafc4f36..b7d4d492 100644 --- a/test/integration-test/src/tests.rs +++ b/test/integration-test/src/tests.rs @@ -8,6 +8,7 @@ mod iter; mod linear_data_structures; mod load; mod log; +mod lsm; mod map_pin; mod raw_tracepoint; mod rbpf; diff --git a/test/integration-test/src/tests/lsm.rs b/test/integration-test/src/tests/lsm.rs new file mode 100644 index 00000000..aeecf537 --- /dev/null +++ b/test/integration-test/src/tests/lsm.rs @@ -0,0 +1,50 @@ +use assert_matches::assert_matches; +use aya::{ + Btf, Ebpf, + programs::{Lsm, ProgramError, ProgramType}, + sys::{SyscallError, is_program_supported}, +}; + +macro_rules! expect_permission_denied { + ($result:expr) => { + let result = $result; + if !std::fs::read_to_string("/sys/kernel/security/lsm").unwrap().contains("bpf") { + assert_matches!(result, Ok(_)); + } else { + assert_matches!(result, Err(e) => assert_eq!( + e.kind(), std::io::ErrorKind::PermissionDenied) + ); + } + }; +} + +#[test] +fn lsm() { + let btf = Btf::from_sys_fs().unwrap(); + + let mut bpf: Ebpf = Ebpf::load(crate::TEST).unwrap(); + let prog = bpf.program_mut("test_lsm").unwrap(); + let prog: &mut Lsm = prog.try_into().unwrap(); + prog.load("socket_bind", &btf).unwrap(); + + assert_matches!(std::net::TcpListener::bind("127.0.0.1:0"), Ok(_)); + + let link_id = { + let result = prog.attach(); + if !is_program_supported(ProgramType::Lsm).unwrap() { + assert_matches!(result, Err(ProgramError::SyscallError(SyscallError { call, io_error })) => { + assert_eq!(call, "bpf_raw_tracepoint_open"); + assert_eq!(io_error.raw_os_error(), Some(524)); + }); + eprintln!("skipping test - LSM programs not supported"); + return; + } + result.unwrap() + }; + + expect_permission_denied!(std::net::TcpListener::bind("127.0.0.1:0")); + + prog.detach(link_id).unwrap(); + + assert_matches!(std::net::TcpListener::bind("127.0.0.1:0"), Ok(_)); +}