diff --git a/crates/libafl_intelpt/README.md b/crates/libafl_intelpt/README.md index deebb9303a..d1df5f2b31 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 89447d718c..46d2e32387 100644 --- a/crates/libafl_intelpt/src/lib.rs +++ b/crates/libafl_intelpt/src/lib.rs @@ -84,6 +84,12 @@ pub fn availability_in_qemu_kvm() -> Result<(), String> { #[cfg(target_os = "linux")] { + 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"; // Ignore the case when the file does not exist since it has been removed. // KVM default is `System` mode @@ -123,7 +129,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 ec365cb7eb..ffbe67d5fd 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,28 @@ 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 { + 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}"))?; + + Ok(buf[1] & 0b0100_0000 != 0) +} + fn new_perf_event_attr_intel_pt() -> Result { let type_ = match &*PERF_EVENT_TYPE { Ok(t) => Ok(*t), @@ -909,7 +932,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))) =