From 759df1eed922cbe8a3f566eb6ef69d1b4580927d Mon Sep 17 00:00:00 2001 From: Marco Cavenati Date: Mon, 7 Jul 2025 09:29:24 +0200 Subject: [PATCH 1/3] intel PT: check for availability in VMX --- crates/libafl_intelpt/README.md | 3 +++ crates/libafl_intelpt/src/lib.rs | 6 +++++- crates/libafl_intelpt/src/linux.rs | 30 ++++++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/crates/libafl_intelpt/README.md b/crates/libafl_intelpt/README.md index deebb9303a6..d1df5f2b315 100644 --- a/crates/libafl_intelpt/README.md +++ b/crates/libafl_intelpt/README.md @@ -3,3 +3,6 @@ This module is a wrapper around the `IntelPT` kernel driver, exposing functionalities specifically crafted for `LibAFL`. At the moment only `Linux` hosts are supported. + +You can run `sudo -E cargo test intel_pt_check_availability -- --show-output` to check if your host has all the features +used by this crate. diff --git a/crates/libafl_intelpt/src/lib.rs b/crates/libafl_intelpt/src/lib.rs index 89447d718c4..e3e7b985791 100644 --- a/crates/libafl_intelpt/src/lib.rs +++ b/crates/libafl_intelpt/src/lib.rs @@ -84,6 +84,10 @@ pub fn availability_in_qemu_kvm() -> Result<(), String> { #[cfg(target_os = "linux")] { + if let Err(reason) = availability_in_vmx() { + reasons.push(reason); + } + let kvm_pt_mode_path = "/sys/module/kvm_intel/parameters/pt_mode"; // Ignore the case when the file does not exist since it has been removed. // KVM default is `System` mode @@ -123,7 +127,7 @@ mod test { /// Quick way to check if your machine is compatible with Intel PT's features used by libafl /// - /// Simply run `cargo test intel_pt_check_availability -- --show-output` + /// Simply run `sudo -E cargo test intel_pt_check_availability -- --show-output` #[test] fn intel_pt_check_availability() { print!("Intel PT availability:\t\t\t"); diff --git a/crates/libafl_intelpt/src/linux.rs b/crates/libafl_intelpt/src/linux.rs index ec365cb7ebc..dd3a7802e8b 100644 --- a/crates/libafl_intelpt/src/linux.rs +++ b/crates/libafl_intelpt/src/linux.rs @@ -11,6 +11,7 @@ use alloc::{ use core::{ffi::CStr, fmt::Debug, ops::RangeInclusive, ptr}; use std::{ fs, + io::{Read, Seek, SeekFrom}, os::{ fd::{AsRawFd, FromRawFd, OwnedFd}, raw::c_void, @@ -544,7 +545,7 @@ impl Default for IntelPTBuilder { /// .inherit(false) /// .perf_buffer_size(128 * PAGE_SIZE + PAGE_SIZE) /// .unwrap() - /// .perf_aux_buffer_size(2 * 1024 * 1024) + /// .perf_aux_buffer_size(4 * 1024 * 1024) /// .unwrap() /// .ip_filters(&[]); /// assert_eq!(builder, IntelPTBuilder::default()); @@ -557,7 +558,7 @@ impl Default for IntelPTBuilder { exclude_hv: true, inherit: false, perf_buffer_size: 128 * PAGE_SIZE + PAGE_SIZE, - perf_aux_buffer_size: 2 * 1024 * 1024, + perf_aux_buffer_size: 4 * 1024 * 1024, ip_filters: Vec::new(), } } @@ -833,6 +834,31 @@ pub(crate) fn availability_in_linux() -> Result<(), String> { } } +/// Check if the `MSR IA32_VMX_MISC` has bit 14 set, which indicates that Intel PT is +/// available in VMX operations. +pub(crate) fn availability_in_vmx() -> Result<(), String> { + let error_prefix = "Failed to check for PT availability in VM operations: "; + let mut msrs = fs::OpenOptions::new() + .read(true) + .open("/dev/cpu/0/msr") + .map_err(|e| { + format!( + "{error_prefix} Failed to open /dev/cpu/0/msr: {e} \ + Make sure you have the `msr` kernel module loaded" + ) + })?; + msrs.seek(SeekFrom::Start(0x485)) + .map_err(|e| format!("{error_prefix} Failed to seek in /dev/cpu/0/msr: {e}"))?; + let mut buf = [0u8; 8]; + msrs.read_exact(&mut buf) + .map_err(|e| format!("{error_prefix} Failed to read MSR 0x485: {e}"))?; + if buf[1] & 0b0100_0000 == 0 { + return Err("Intel PT is not available for VMX operations.".to_owned()); + } + + Ok(()) +} + fn new_perf_event_attr_intel_pt() -> Result { let type_ = match &*PERF_EVENT_TYPE { Ok(t) => Ok(*t), From 3617cf6dd42ef5b7d8026cac1cadc3425bdf5193 Mon Sep 17 00:00:00 2001 From: Marco Cavenati Date: Mon, 7 Jul 2025 10:16:01 +0200 Subject: [PATCH 2/3] intelPT: fix linux version parser containing +deb --- crates/libafl_intelpt/src/linux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/libafl_intelpt/src/linux.rs b/crates/libafl_intelpt/src/linux.rs index dd3a7802e8b..9292222115a 100644 --- a/crates/libafl_intelpt/src/linux.rs +++ b/crates/libafl_intelpt/src/linux.rs @@ -935,7 +935,7 @@ fn linux_version() -> Result<(usize, usize, usize), ()> { let release = unsafe { CStr::from_ptr(uname_data.release.as_ptr()) }; let mut parts = release .to_bytes() - .split(|&c| c == b'.' || c == b'-') + .split(|&c| matches!(c, b'.' | b'-' | b'+')) .take(3) .map(|s| String::from_utf8_lossy(s).parse::()); if let (Some(Ok(major)), Some(Ok(minor)), Some(Ok(patch))) = From 349de2ed3d4b1360f1166cc8bc020aa1967aeab2 Mon Sep 17 00:00:00 2001 From: Marco Cavenati Date: Mon, 7 Jul 2025 14:19:17 +0200 Subject: [PATCH 3/3] make availability_in_vmx return a bool --- crates/libafl_intelpt/src/lib.rs | 6 ++++-- crates/libafl_intelpt/src/linux.rs | 7 ++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/libafl_intelpt/src/lib.rs b/crates/libafl_intelpt/src/lib.rs index e3e7b985791..46d2e323874 100644 --- a/crates/libafl_intelpt/src/lib.rs +++ b/crates/libafl_intelpt/src/lib.rs @@ -84,8 +84,10 @@ pub fn availability_in_qemu_kvm() -> Result<(), String> { #[cfg(target_os = "linux")] { - if let Err(reason) = availability_in_vmx() { - reasons.push(reason); + match availability_in_vmx() { + Err(reason) => reasons.push(reason), + Ok(false) => reasons.push("Intel PT is not available for VMX operations.".to_owned()), + Ok(true) => {} } let kvm_pt_mode_path = "/sys/module/kvm_intel/parameters/pt_mode"; diff --git a/crates/libafl_intelpt/src/linux.rs b/crates/libafl_intelpt/src/linux.rs index 9292222115a..ffbe67d5fd4 100644 --- a/crates/libafl_intelpt/src/linux.rs +++ b/crates/libafl_intelpt/src/linux.rs @@ -836,7 +836,7 @@ pub(crate) fn availability_in_linux() -> Result<(), String> { /// Check if the `MSR IA32_VMX_MISC` has bit 14 set, which indicates that Intel PT is /// available in VMX operations. -pub(crate) fn availability_in_vmx() -> Result<(), String> { +pub(crate) fn availability_in_vmx() -> Result { let error_prefix = "Failed to check for PT availability in VM operations: "; let mut msrs = fs::OpenOptions::new() .read(true) @@ -852,11 +852,8 @@ pub(crate) fn availability_in_vmx() -> Result<(), String> { let mut buf = [0u8; 8]; msrs.read_exact(&mut buf) .map_err(|e| format!("{error_prefix} Failed to read MSR 0x485: {e}"))?; - if buf[1] & 0b0100_0000 == 0 { - return Err("Intel PT is not available for VMX operations.".to_owned()); - } - Ok(()) + Ok(buf[1] & 0b0100_0000 != 0) } fn new_perf_event_attr_intel_pt() -> Result {