diff --git a/crates/bpf-common/src/program.rs b/crates/bpf-common/src/program.rs index 74bbbbf0..99cd4ba7 100644 --- a/crates/bpf-common/src/program.rs +++ b/crates/bpf-common/src/program.rs @@ -13,10 +13,10 @@ use aya::{ Array, HashMap, Map, MapData, }, programs::{CgroupSkb, CgroupSkbAttachType, KProbe, Lsm, RawTracePoint, TracePoint}, - util::online_cpus, + util::{online_cpus, KernelVersion}, Bpf, BpfLoader, Btf, BtfError, Pod, }; -use bpf_feature_autodetect::{autodetect_features, kernel_version::KernelVersion}; +use bpf_feature_autodetect::autodetect_features; use bpf_features::BpfFeatures; use bytes::{Buf, Bytes, BytesMut}; use thiserror::Error; @@ -83,15 +83,11 @@ impl BpfContext { log::warn!("The default value {PERF_PAGES_DEFAULT} will be used."); perf_pages = PERF_PAGES_DEFAULT; } - let kernel_version = match KernelVersion::autodetect() { + let kernel_version = match KernelVersion::current() { Ok(version) => version, Err(err) => { log::warn!("Error identifying kernel version {err:?}. Assuming kernel 5.0.4"); - KernelVersion { - major: 5, - minor: 0, - patch: 4, - } + KernelVersion::new(5, 0, 4) } }; // aya doesn't support specifying from userspace wether or not to pin maps. @@ -280,7 +276,7 @@ impl ProgramBuilder { .set_global("log_level", &(self.ctx.log_level as i32), true) .set_global( "LINUX_KERNEL_VERSION", - &self.ctx.kernel_version.as_i32(), + &self.ctx.kernel_version.code(), true, ) .load(&self.probe)?; diff --git a/crates/bpf-feature-autodetect/src/kernel_version.rs b/crates/bpf-feature-autodetect/src/kernel_version.rs deleted file mode 100644 index bc2c399e..00000000 --- a/crates/bpf-feature-autodetect/src/kernel_version.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! Extract kernel version from the currently running system. -//! Code ported from libbpf. - -use std::str::FromStr; - -use anyhow::{Context, Result}; -use nix::fcntl::AtFlags; -use nix::sys::utsname::uname; -use nix::unistd::{faccessat, AccessFlags}; - -#[derive(Debug, Clone, PartialEq, PartialOrd)] -pub struct KernelVersion { - pub major: u32, - pub minor: u32, - pub patch: u32, -} - -impl KernelVersion { - pub fn autodetect() -> Result { - // On Ubuntu LINUX_VERSION_CODE doesn't correspond to info.release, - // but Ubuntu provides /proc/version_signature file, as described at - // https://ubuntu.com/kernel, with an example contents below, which we - // can use to get a proper LINUX_VERSION_CODE. - // - // Ubuntu 5.4.0-12.15-generic 5.4.8 - // - // In the above, 5.4.8 is what kernel is actually expecting, while - // uname() call will return 5.4.0 in info.release. - if faccessat( - None, - "/proc/version_signature", - AccessFlags::R_OK, - // TODO: switch to AT_EACCESS once this patch is merged and released: - // https://github.com/nix-rust/nix/pull/1995 - // As a workaround we're using AT_REMOVEDIR, which has the same value on linux - AtFlags::AT_REMOVEDIR, - ) - .is_ok() - { - if let Ok(value) = std::fs::read_to_string("/proc/version_signature") { - return Self::parse_version_signature(&value); - } - } - Self::parse_uname_release( - uname() - .context("Getting kernel version calling uname() failed")? - .release() - .to_str() - .context("Kernel version from uname contained invalid characters")?, - ) - } - - /// Parse release fields from the format "%*s %*s %d.%d.%d\n" - fn parse_version_signature(value: &str) -> Result { - let parse = |value: &str| -> Option { - let version_items: Vec<&str> = value.split_whitespace().nth(2)?.split('.').collect(); - if let [major, minor, patch] = version_items[..] { - Some(KernelVersion { - major: major.parse().ok()?, - minor: minor.parse().ok()?, - patch: patch.parse().ok()?, - }) - } else { - None - } - }; - parse(value).with_context(|| format!("Invalid version_signature format: {value}")) - } - - /// Parse release fields from the format "%d.%d.%d" - fn parse_uname_release(value: &str) -> Result { - let parse = |value: &str| -> Option { - let mut version_items = value.split('.'); - Some(KernelVersion { - major: version_items.next().and_then(|major| major.parse().ok())?, - minor: version_items.next().and_then(|minor| minor.parse().ok())?, - patch: version_items - .next() - .and_then(|patch| parse_u32_skipping_suffix(patch).ok())?, - }) - }; - parse(value).with_context(|| format!("Invalid version_signature format: {value}")) - } - - /// Encode to a single i32 as the kernel macro KERNEL_VERSION() - pub fn as_i32(&self) -> i32 { - ((self.major << 16) + (self.minor << 8) + self.patch.max(255)) as i32 - } -} - -fn parse_u32_skipping_suffix(input: &str) -> Result::Err> { - let i = input.find(|c: char| !c.is_numeric()).unwrap_or(input.len()); - input[..i].parse::() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn parse_version_signature() { - assert_eq!( - KernelVersion::parse_version_signature("Ubuntu 5.4.0-12.15-generic 5.4.8\n").unwrap(), - KernelVersion { - major: 5, - minor: 4, - patch: 8 - } - ); - } - - #[test] - fn parse_uname_release() { - assert_eq!( - KernelVersion::parse_uname_release("5.17.4").unwrap(), - KernelVersion { - major: 5, - minor: 17, - patch: 4 - } - ); - } - - #[test] - fn parse_uname_archlinux() { - assert_eq!( - KernelVersion::parse_uname_release("6.1.8-arch1-1").unwrap(), - KernelVersion { - major: 6, - minor: 1, - patch: 8 - } - ); - } - - #[test] - fn parse_uname_wsl() { - assert_eq!( - KernelVersion::parse_uname_release("5.15.79.1-microsoft-standard-WSL2").unwrap(), - KernelVersion { - major: 5, - minor: 15, - patch: 79 - } - ); - } - - #[test] - fn parse_uname_one_dot() { - assert!(KernelVersion::parse_uname_release("5.15").is_err()); - } - - #[test] - fn int_conversion() { - assert_eq!( - KernelVersion { - major: 5, - minor: 17, - patch: 4 - } - .as_i32(), - 332287 - ); - } -} diff --git a/crates/bpf-feature-autodetect/src/lib.rs b/crates/bpf-feature-autodetect/src/lib.rs index db773547..a2dbc962 100644 --- a/crates/bpf-feature-autodetect/src/lib.rs +++ b/crates/bpf-feature-autodetect/src/lib.rs @@ -13,7 +13,6 @@ pub mod atomic; pub mod bpf_loop; pub mod func; pub mod insn; -pub mod kernel_version; pub mod lsm; use crate::{ diff --git a/crates/modules/process-monitor/src/lib.rs b/crates/modules/process-monitor/src/lib.rs index 157780e3..8aa862d2 100644 --- a/crates/modules/process-monitor/src/lib.rs +++ b/crates/modules/process-monitor/src/lib.rs @@ -1,6 +1,6 @@ use anyhow::Context; use bpf_common::{ - bpf_feature_autodetect::kernel_version::KernelVersion, + aya::util::KernelVersion, containers::ContainerError, ebpf_program, parsing::{BufferIndex, IndexError}, @@ -19,12 +19,7 @@ pub async fn program( let binary = ebpf_program!(&ctx, "probes"); let attach_to_lsm = ctx.lsm_supported(); // LSM task_fix_set* calls are available since kernel commit 39030e1351aa1, in 5.10 - let has_cred_specific_functions = ctx.kernel_version() - >= &KernelVersion { - major: 5, - minor: 10, - patch: 0, - }; + let has_cred_specific_functions = ctx.kernel_version() >= &KernelVersion::new(5, 10, 0); let mut builder = ProgramBuilder::new(ctx, MODULE_NAME, binary) .raw_tracepoint("sched_process_exec") .raw_tracepoint("sched_process_exit")