Skip to content

Conversation

Marcondiro
Copy link
Contributor

Description

This PR improves VM tracing in libafl_qemu with Intel PT.

  • Better filter out the VMX root traces during decoding thanks to the new resync API in libipt (bumped to 0.4.0).
  • Extract the Decoder from the linux intel_pt file, since the file/struct was getting too big and the decoder will eventually be compatible with windows.
  • PT tracing is now enabled manually by fuzzers to have more precise control, instead of beeing always on in vm operations.
  • Add KVM dirty tracing option to qemu config and raw string options

Checklist

  • I have run ./scripts/precommit.sh and addressed all comments

@Marcondiro Marcondiro marked this pull request as draft July 28, 2025 12:21
@Marcondiro Marcondiro marked this pull request as ready for review July 28, 2025 13:38
@tokatoka tokatoka requested a review from rmalmain July 29, 2025 12:19
@Marcondiro Marcondiro force-pushed the for_upstream branch 4 times, most recently from 0c42ca4 to 3251229 Compare August 5, 2025 15:17
@Marcondiro Marcondiro force-pushed the for_upstream branch 5 times, most recently from e739390 to 39c2114 Compare August 14, 2025 09:05
@Marcondiro
Copy link
Contributor Author

Hi, is there any chance someone could take a look at this? Thanks :)

- Better filter out the VMX root traces during decoding thanks to the new `resync` API in libipt (bumped to 0.4.0).
- Extract the Decoder from the linux intel_pt file, since the file/struct was getting too big and the decoder will eventually be compatible with windows.
- PT tracing is now enabled manually by fuzzers to have more precise control, instead of beeing always on in vm operations.
- Add KVM dirty tracing option to qemu config and raw string options
Instead of hardcoding the addresses (that are compiler dependent), read them from the binary.
.map(|filter| {
let size = filter.end() - filter.start();
format!("filter {:#016x}/{:#016x} ", filter.start(), size)
let size = filter.to - filter.from;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it filter.to - filter.from + 1 (it seems to be an inclusive range)?
i only found little information in the intel manual about this, at section 34.2.5.3 - Filtering by IP.
It could be interesting to add a method len to AddrFilter, and maybe some traits implemented by RangeInclusive that could be relevant.
Screenshot_select-area_20250901180816

let str_filter = filters
.iter()
.filter(|f| f.filter_type == AddrFilterType::FILTER)
.map(|filter| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use filter_map?

let str_filter = filters
.iter()
.filter(|f| f.filter_type == AddrFilterType::FILTER)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about AddrFilterType::STOP and AddrFilterType::DISABLED? they seem to be unused.
i saw you create AddrFilterType in libipt. why not use the same names as in the manual (FilterEn and TraceStop)?
by the way, the name of the cfg register in the doc is wrong. it's not IA32_RTIT_ADDRn_CFG, but IA32_RTIT_CTL. or at least i couldn't find this name in the latest version of the intel manual.
Screenshot_select-area_20250901184515

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants