From f6606473af43090190337dd42f593df2f907ac0a Mon Sep 17 00:00:00 2001 From: Addison Crump Date: Fri, 5 Sep 2025 12:43:13 +0200 Subject: [PATCH] aya-log: properly hint log level to verifier The log level implementation in b36cbc3eb8413d4fba4f2d820fec8176751457ac was incomplete as the verifier could reject programs which exceeded their instruction limits within logging statements. This commit addresses this issue by making the log level static variable immutable (s.t. the compiler puts it in a read-only section) and adds an additional test which the verifier will reject as an infinite loop iff it is unable to detect that the static variable would otherwise allow the logging. --- ebpf/aya-log-ebpf/src/lib.rs | 3 +-- test/integration-ebpf/src/log.rs | 14 +++++++++- test/integration-test/src/tests/log.rs | 37 ++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/ebpf/aya-log-ebpf/src/lib.rs b/ebpf/aya-log-ebpf/src/lib.rs index f2398626..7d93f478 100644 --- a/ebpf/aya-log-ebpf/src/lib.rs +++ b/ebpf/aya-log-ebpf/src/lib.rs @@ -39,12 +39,11 @@ pub mod macro_support { /// /// Userspace may patch this symbol before load via `EbpfLoader::set_global`. #[unsafe(no_mangle)] - pub static mut AYA_LOG_LEVEL: u8 = 0xff; + pub static AYA_LOG_LEVEL: u8 = 0xff; /// Returns `true` if the provided level is enabled according to [`AYA_LOG_LEVEL`]. #[inline(always)] pub fn level_enabled(level: Level) -> bool { - #[expect(static_mut_refs)] let current_level = unsafe { core::ptr::read_volatile(&AYA_LOG_LEVEL) }; level as u8 <= current_level } diff --git a/test/integration-ebpf/src/log.rs b/test/integration-ebpf/src/log.rs index 67228b53..bff63e1e 100644 --- a/test/integration-ebpf/src/log.rs +++ b/test/integration-ebpf/src/log.rs @@ -1,7 +1,10 @@ #![no_std] #![no_main] -use core::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use core::{ + hint::black_box, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, +}; use aya_ebpf::{macros::uprobe, programs::ProbeContext}; use aya_log_ebpf::{debug, error, info, trace, warn}; @@ -83,3 +86,12 @@ pub fn test_log(ctx: ProbeContext) { debug!(&ctx, "{:x}", no_copy.consume()); } } + +#[uprobe] +pub fn test_log_omission(ctx: ProbeContext) { + debug!( + &ctx, + "This is the last u32: {}", + black_box(0u32..).last().unwrap_or(u32::MAX) + ); +} diff --git a/test/integration-test/src/tests/log.rs b/test/integration-test/src/tests/log.rs index 91841f03..c7a8976a 100644 --- a/test/integration-test/src/tests/log.rs +++ b/test/integration-test/src/tests/log.rs @@ -224,3 +224,40 @@ fn log_level_only_error_warn() { assert_eq!(records.next(), None); } + +#[test_log::test] +fn log_level_prevents_verif_fail() { + let level = aya_log::Level::Warn as u8; + let mut bpf = EbpfLoader::new() + .set_global(aya_log::LEVEL, &level, true /* must_exist */) + .load(crate::LOG) + .unwrap(); + + let mut captured_logs = Vec::new(); + let logger = TestingLogger { + log: Mutex::new(|record: &Record| { + captured_logs.push(CapturedLog { + body: format!("{}", record.args()).into(), + level: record.level(), + target: record.target().to_string().into(), + }); + }), + }; + let mut logger = EbpfLogger::init_with_logger(&mut bpf, &logger).unwrap(); + + let prog: &mut UProbe = bpf + .program_mut("test_log_omission") + .unwrap() + .try_into() + .unwrap(); + prog.load().unwrap(); + prog.attach("trigger_ebpf_program", "/proc/self/exe", None, None) + .unwrap(); + + trigger_ebpf_program(); + logger.flush(); + + let mut records = captured_logs.iter(); + + assert_eq!(records.next(), None); +}