Skip to content

Commit bdbd509

Browse files
authored
intel PT: check for availability in VMX (#3328)
* intel PT: check for availability in VMX * intelPT: fix linux version parser containing +deb * make availability_in_vmx return a bool
1 parent 0802674 commit bdbd509

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

crates/libafl_intelpt/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33
This module is a wrapper around the `IntelPT` kernel driver, exposing functionalities specifically crafted for `LibAFL`.
44

55
At the moment only `Linux` hosts are supported.
6+
7+
You can run `sudo -E cargo test intel_pt_check_availability -- --show-output` to check if your host has all the features
8+
used by this crate.

crates/libafl_intelpt/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ pub fn availability_in_qemu_kvm() -> Result<(), String> {
8484

8585
#[cfg(target_os = "linux")]
8686
{
87+
match availability_in_vmx() {
88+
Err(reason) => reasons.push(reason),
89+
Ok(false) => reasons.push("Intel PT is not available for VMX operations.".to_owned()),
90+
Ok(true) => {}
91+
}
92+
8793
let kvm_pt_mode_path = "/sys/module/kvm_intel/parameters/pt_mode";
8894
// Ignore the case when the file does not exist since it has been removed.
8995
// KVM default is `System` mode
@@ -123,7 +129,7 @@ mod test {
123129

124130
/// Quick way to check if your machine is compatible with Intel PT's features used by libafl
125131
///
126-
/// Simply run `cargo test intel_pt_check_availability -- --show-output`
132+
/// Simply run `sudo -E cargo test intel_pt_check_availability -- --show-output`
127133
#[test]
128134
fn intel_pt_check_availability() {
129135
print!("Intel PT availability:\t\t\t");

crates/libafl_intelpt/src/linux.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use alloc::{
1111
use core::{ffi::CStr, fmt::Debug, ops::RangeInclusive, ptr};
1212
use std::{
1313
fs,
14+
io::{Read, Seek, SeekFrom},
1415
os::{
1516
fd::{AsRawFd, FromRawFd, OwnedFd},
1617
raw::c_void,
@@ -544,7 +545,7 @@ impl Default for IntelPTBuilder {
544545
/// .inherit(false)
545546
/// .perf_buffer_size(128 * PAGE_SIZE + PAGE_SIZE)
546547
/// .unwrap()
547-
/// .perf_aux_buffer_size(2 * 1024 * 1024)
548+
/// .perf_aux_buffer_size(4 * 1024 * 1024)
548549
/// .unwrap()
549550
/// .ip_filters(&[]);
550551
/// assert_eq!(builder, IntelPTBuilder::default());
@@ -557,7 +558,7 @@ impl Default for IntelPTBuilder {
557558
exclude_hv: true,
558559
inherit: false,
559560
perf_buffer_size: 128 * PAGE_SIZE + PAGE_SIZE,
560-
perf_aux_buffer_size: 2 * 1024 * 1024,
561+
perf_aux_buffer_size: 4 * 1024 * 1024,
561562
ip_filters: Vec::new(),
562563
}
563564
}
@@ -833,6 +834,28 @@ pub(crate) fn availability_in_linux() -> Result<(), String> {
833834
}
834835
}
835836

837+
/// Check if the `MSR IA32_VMX_MISC` has bit 14 set, which indicates that Intel PT is
838+
/// available in VMX operations.
839+
pub(crate) fn availability_in_vmx() -> Result<bool, String> {
840+
let error_prefix = "Failed to check for PT availability in VM operations: ";
841+
let mut msrs = fs::OpenOptions::new()
842+
.read(true)
843+
.open("/dev/cpu/0/msr")
844+
.map_err(|e| {
845+
format!(
846+
"{error_prefix} Failed to open /dev/cpu/0/msr: {e} \
847+
Make sure you have the `msr` kernel module loaded"
848+
)
849+
})?;
850+
msrs.seek(SeekFrom::Start(0x485))
851+
.map_err(|e| format!("{error_prefix} Failed to seek in /dev/cpu/0/msr: {e}"))?;
852+
let mut buf = [0u8; 8];
853+
msrs.read_exact(&mut buf)
854+
.map_err(|e| format!("{error_prefix} Failed to read MSR 0x485: {e}"))?;
855+
856+
Ok(buf[1] & 0b0100_0000 != 0)
857+
}
858+
836859
fn new_perf_event_attr_intel_pt() -> Result<perf_event_attr, Error> {
837860
let type_ = match &*PERF_EVENT_TYPE {
838861
Ok(t) => Ok(*t),
@@ -909,7 +932,7 @@ fn linux_version() -> Result<(usize, usize, usize), ()> {
909932
let release = unsafe { CStr::from_ptr(uname_data.release.as_ptr()) };
910933
let mut parts = release
911934
.to_bytes()
912-
.split(|&c| c == b'.' || c == b'-')
935+
.split(|&c| matches!(c, b'.' | b'-' | b'+'))
913936
.take(3)
914937
.map(|s| String::from_utf8_lossy(s).parse::<usize>());
915938
if let (Some(Ok(major)), Some(Ok(minor)), Some(Ok(patch))) =

0 commit comments

Comments
 (0)