Prevent verification failure by making the log level static immutable

The log level implementation in #1335 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.
reviewable/pr1337/r1
Addison Crump 6 days ago
parent b36cbc3eb8
commit 55aa5a655d
No known key found for this signature in database
GPG Key ID: D495C2DF24C779B2

@ -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
}

@ -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)
);
}

@ -224,3 +224,39 @@ 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);
}

Loading…
Cancel
Save