vmi_utils/bpm/controller/
breakpoint.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use vmi_core::{
    arch::{EventInterrupt as _, EventReason},
    Architecture, Gfn, MemoryAccess, Pa, Registers as _, Va, View, VmiCore, VmiDriver, VmiError,
    VmiEvent,
};

use super::TapController;
use crate::interceptor::Interceptor;

#[doc = include_str!("breakpoint.md")]
pub struct BreakpointController<Driver>
where
    Driver: VmiDriver,
    <Driver::Architecture as Architecture>::EventReason:
        EventReason<Architecture = Driver::Architecture>,
{
    interceptor: Interceptor<Driver>,
}

impl<Driver> BreakpointController<Driver>
where
    Driver: VmiDriver,
    <Driver::Architecture as Architecture>::EventReason:
        EventReason<Architecture = Driver::Architecture>,
{
    /// Checks if the given event was caused by a software breakpoint.
    pub fn is_breakpoint(
        vmi: &VmiCore<Driver>,
        event: &VmiEvent<Driver::Architecture>,
    ) -> Result<bool, VmiError> {
        let interrupt = match event.reason().as_software_breakpoint() {
            Some(interrupt) => interrupt,
            None => return Ok(false),
        };

        let va = Va(event.registers().instruction_pointer());
        let pa = Driver::Architecture::pa_from_gfn(interrupt.gfn())
            + Driver::Architecture::va_offset(va);

        let mut content = vec![0; Driver::Architecture::BREAKPOINT.len()];
        vmi.read(pa, &mut content)?;

        Ok(content == Driver::Architecture::BREAKPOINT)
    }
}

impl<Driver> TapController for BreakpointController<Driver>
where
    Driver: VmiDriver,
    <Driver::Architecture as Architecture>::EventReason:
        EventReason<Architecture = Driver::Architecture>,
{
    type Driver = Driver;

    fn new() -> Self {
        Self {
            interceptor: Interceptor::new(),
        }
    }

    fn check_event(&self, event: &VmiEvent<Driver::Architecture>) -> Option<(View, Gfn)> {
        let interrupt = match event.reason().as_software_breakpoint() {
            Some(interrupt) => interrupt,
            None => return None,
        };

        let view = match event.view() {
            Some(view) => view,
            None => return None,
        };

        Some((view, interrupt.gfn()))
    }

    fn insert_breakpoint(
        &mut self,
        vmi: &VmiCore<Driver>,
        pa: Pa,
        view: View,
    ) -> Result<(), VmiError> {
        self.interceptor.insert_breakpoint(vmi, pa, view)?;
        Ok(())
    }

    fn remove_breakpoint(
        &mut self,
        vmi: &VmiCore<Driver>,
        pa: Pa,
        view: View,
    ) -> Result<(), VmiError> {
        let breakpoint_was_removed = self.interceptor.remove_breakpoint(vmi, pa, view)?;
        debug_assert_eq!(breakpoint_was_removed, Some(true));
        Ok(())
    }

    fn monitor(&mut self, vmi: &VmiCore<Driver>, gfn: Gfn, view: View) -> Result<(), VmiError> {
        vmi.set_memory_access(gfn, view, MemoryAccess::X)
    }

    fn unmonitor(&mut self, vmi: &VmiCore<Driver>, gfn: Gfn, view: View) -> Result<(), VmiError> {
        vmi.set_memory_access(gfn, view, MemoryAccess::RWX)
    }
}