feature_probe: properly check for LSM support

Turns out this is not supported in aarch64 until 6.4.
reviewable/pr1359/r8
Tamir Duberstein 1 month ago
parent efa5857c0d
commit b4f07ca1de
No known key found for this signature in database

@ -1,6 +1,10 @@
//! Probes and identifies available eBPF features supported by the host kernel. //! Probes and identifies available eBPF features supported by the host kernel.
use std::{mem, os::fd::AsRawFd as _, ptr}; use std::{
mem,
os::fd::{AsFd as _, AsRawFd as _},
ptr,
};
use aya_obj::{ use aya_obj::{
btf::{Btf, BtfKind}, btf::{Btf, BtfKind},
@ -10,7 +14,10 @@ use aya_obj::{
}; };
use libc::{E2BIG, EBADF, EINVAL}; use libc::{E2BIG, EBADF, EINVAL};
use super::{SyscallError, bpf_prog_load, fd_sys_bpf, unit_sys_bpf, with_trivial_prog}; use super::{
SyscallError, bpf_prog_load, bpf_raw_tracepoint_open, fd_sys_bpf, unit_sys_bpf,
with_trivial_prog,
};
use crate::{ use crate::{
MockableFd, MockableFd,
maps::MapType, maps::MapType,
@ -85,7 +92,7 @@ pub fn is_program_supported(program_type: ProgramType) -> Result<bool, ProgramEr
.unwrap_or(0) .unwrap_or(0)
}); });
let error = match with_trivial_prog(program_type, |attr| { with_trivial_prog(program_type, |attr| {
// SAFETY: union access // SAFETY: union access
let u = unsafe { &mut attr.__bindgen_anon_3 }; let u = unsafe { &mut attr.__bindgen_anon_3 };
@ -100,22 +107,11 @@ pub fn is_program_supported(program_type: ProgramType) -> Result<bool, ProgramEr
u.log_size = verifier_log.len() as u32; u.log_size = verifier_log.len() as u32;
} }
bpf_prog_load(attr).err().map(|io_error| { match bpf_prog_load(attr) {
ProgramError::SyscallError(SyscallError { Err(io_error) => match io_error.raw_os_error() {
call: "bpf_prog_load", // Loading may fail for some types (namely tracing, extension, lsm, & struct_ops), so we
io_error, // perform additional examination on the OS error and/or verifier logs.
}) //
})
}) {
Some(err) => err,
None => return Ok(true),
};
// Loading may fail for some types (namely tracing, extension, lsm, & struct_ops), so we
// perform additional examination on the OS error and/or verifier logs.
match &error {
ProgramError::SyscallError(err) => {
match err.io_error.raw_os_error() {
// For most types, `EINVAL` typically indicates it is not supported. // For most types, `EINVAL` typically indicates it is not supported.
// However, further examination is required for tracing, extension, and lsm. // However, further examination is required for tracing, extension, and lsm.
Some(EINVAL) => { Some(EINVAL) => {
@ -152,11 +148,34 @@ pub fn is_program_supported(program_type: ProgramType) -> Result<bool, ProgramEr
// //
// [0] https://elixir.bootlin.com/linux/v5.6/source/kernel/bpf/verifier.c#L9740 // [0] https://elixir.bootlin.com/linux/v5.6/source/kernel/bpf/verifier.c#L9740
Some(524) if program_type == ProgramType::StructOps => Ok(true), Some(524) if program_type == ProgramType::StructOps => Ok(true),
_ => Err(error), _ => Err(ProgramError::SyscallError(SyscallError {
call: "bpf_prog_load",
io_error,
})),
},
Ok(prog_fd) => {
// Some arm64 kernels (notably < 6.4) can load LSM programs but cannot attach them:
// `bpf_raw_tracepoint_open` fails with `-ENOTSUPP`. Probe attach support
// explicitly.
//
// h/t to https://www.exein.io/blog/exploring-bpf-lsm-support-on-aarch64-with-ftrace.
if program_type != ProgramType::Lsm {
Ok(true)
} else {
match bpf_raw_tracepoint_open(None, prog_fd.as_fd()) {
Ok(_) => Ok(true),
Err(io_error) => match io_error.raw_os_error() {
Some(524) => Ok(false),
_ => Err(ProgramError::SyscallError(SyscallError {
call: "bpf_raw_tracepoint_open",
io_error,
})),
},
}
}
} }
} }
_ => Err(error), })
}
} }
/// Whether the host kernel supports the [`MapType`]. /// Whether the host kernel supports the [`MapType`].

@ -107,31 +107,39 @@ fn probe_supported_programs() {
kernel_assert!(is_supported!(ProgramType::StructOps), kern_version); kernel_assert!(is_supported!(ProgramType::StructOps), kern_version);
kernel_assert!(is_supported!(ProgramType::Extension), kern_version); kernel_assert!(is_supported!(ProgramType::Extension), kern_version);
let kern_version = KernelVersion::new(5, 7, 0); {
// `lsm` requires `CONFIG_DEBUG_INFO_BTF=y` & `CONFIG_BPF_LSM=y` let kern_version = if cfg!(target_arch = "aarch64") {
// Ways to check if `CONFIG_BPF_LSM` is enabled: KernelVersion::new(6, 4, 0)
// - kernel config has `CONFIG_BPF_LSM=y`, but config is not always exposed. } else {
// - an LSM hook is present in BTF, e.g. `bpf_lsm_bpf`. hooks are found in `bpf_lsm.c` KernelVersion::new(5, 7, 0)
if current >= kern_version { };
let lsm_enabled = matches!( // `lsm` requires `CONFIG_DEBUG_INFO_BTF=y` & `CONFIG_BPF_LSM=y`
kernel_config.get("CONFIG_BPF_LSM"), // Ways to check if `CONFIG_BPF_LSM` is enabled:
Some(procfs::ConfigSetting::Yes) // - kernel config has `CONFIG_BPF_LSM=y`, but config is not always exposed.
) || Btf::from_sys_fs() // - an LSM hook is present in BTF, e.g. `bpf_lsm_bpf`. hooks are found in `bpf_lsm.c`
.and_then(|btf| btf.id_by_type_name_kind("bpf_lsm_bpf", aya_obj::btf::BtfKind::Func)) if current >= kern_version {
.is_ok(); let lsm_enabled = matches!(
assert_eq!( kernel_config.get("CONFIG_BPF_LSM"),
is_supported!(ProgramType::Lsm), Some(procfs::ConfigSetting::Yes)
lsm_enabled, ) || Btf::from_sys_fs()
"current={current}" .and_then(|btf| {
); btf.id_by_type_name_kind("bpf_lsm_bpf", aya_obj::btf::BtfKind::Func)
if !lsm_enabled { })
eprintln!("CONFIG_BPF_LSM required for lsm program type"); .is_ok();
assert_eq!(
is_supported!(ProgramType::Lsm),
lsm_enabled,
"current={current}"
);
if !lsm_enabled {
eprintln!("CONFIG_BPF_LSM required for lsm program type");
}
} else {
assert!(
!is_supported!(ProgramType::Lsm),
"{current} < {kern_version}"
);
} }
} else {
assert!(
!is_supported!(ProgramType::Lsm),
"{current} < {kern_version}"
);
} }
let kern_version = KernelVersion::new(5, 9, 0); let kern_version = KernelVersion::new(5, 9, 0);

Loading…
Cancel
Save