Coverage Report

Created: 2025-03-07 06:49

/src/cloud-hypervisor/fuzz/fuzz_targets/x86emul.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright © 2025 Microsoft Corporation
2
//
3
// SPDX-License-Identifier: Apache-2.0
4
5
#![no_main]
6
7
use hypervisor::arch::emulator::{PlatformEmulator, PlatformError};
8
use hypervisor::arch::x86::emulator::{Emulator, EmulatorCpuState};
9
use hypervisor::arch::x86::{DescriptorTable, SegmentRegister, SpecialRegisters};
10
use hypervisor::StandardRegisters;
11
use libfuzzer_sys::{fuzz_target, Corpus};
12
13
#[derive(Debug)]
14
struct EmulatorContext {
15
    state: EmulatorCpuState,
16
    memory: [u8; 8],
17
}
18
19
impl PlatformEmulator for EmulatorContext {
20
    type CpuState = EmulatorCpuState;
21
22
2.23M
    fn read_memory(&self, _gva: u64, data: &mut [u8]) -> Result<(), PlatformError> {
23
2.23M
        data.copy_from_slice(&self.memory[..data.len()]);
24
2.23M
        Ok(())
25
2.23M
    }
26
27
4.82M
    fn write_memory(&mut self, _gva: u64, _data: &[u8]) -> Result<(), PlatformError> {
28
4.82M
        // Discard writes
29
4.82M
        Ok(())
30
4.82M
    }
31
32
1.91k
    fn cpu_state(&self, _cpu_id: usize) -> Result<Self::CpuState, PlatformError> {
33
1.91k
        Ok(self.state.clone())
34
1.91k
    }
35
36
0
    fn set_cpu_state(&self, _cpu_id: usize, _state: Self::CpuState) -> Result<(), PlatformError> {
37
0
        // Ignore
38
0
        Ok(())
39
0
    }
40
41
0
    fn fetch(&self, _ip: u64, _data: &mut [u8]) -> Result<(), PlatformError> {
42
0
        // The fuzzer already provides 16 bytes of data, we don't need to fetch anything
43
0
        panic!("fetch should not be called");
44
    }
45
}
46
47
fuzz_target!(|bytes: &[u8]| -> Corpus {
48
    let (mut ctx, insn) = match generate_context_and_instruction(bytes) {
49
        Ok((ctx, insn)) => (ctx, insn),
50
        Err(_) => return Corpus::Reject,
51
    };
52
53
    let mut e = Emulator::new(&mut ctx);
54
55
    if e.emulate_first_insn(0, &insn).is_err() {
56
        return Corpus::Reject;
57
    }
58
59
    Corpus::Keep
60
});
61
62
// Helper functions to generate structures from fuzzer input below
63
64
15.2k
fn generate_segment_register(
65
15.2k
    u: &mut arbitrary::Unstructured<'_>,
66
15.2k
) -> arbitrary::Result<SegmentRegister> {
67
15.2k
    Ok(SegmentRegister {
68
15.2k
        base: u.arbitrary()?,
69
15.2k
        limit: u.arbitrary()?,
70
15.2k
        selector: u.arbitrary()?,
71
15.2k
        avl: u.arbitrary()?,
72
15.2k
        dpl: u.arbitrary()?,
73
15.2k
        db: u.arbitrary()?,
74
15.2k
        g: u.arbitrary()?,
75
15.2k
        l: u.arbitrary()?,
76
15.2k
        present: u.arbitrary()?,
77
15.2k
        s: u.arbitrary()?,
78
15.2k
        type_: u.arbitrary()?,
79
15.2k
        unusable: u.arbitrary()?,
80
    })
81
15.2k
}
82
83
3.82k
fn generate_descriptor_table(
84
3.82k
    u: &mut arbitrary::Unstructured<'_>,
85
3.82k
) -> arbitrary::Result<DescriptorTable> {
86
3.82k
    Ok(DescriptorTable {
87
3.82k
        base: u.arbitrary()?,
88
3.82k
        limit: u.arbitrary()?,
89
    })
90
3.82k
}
91
92
1.91k
fn generate_context_and_instruction(
93
1.91k
    bytes: &[u8],
94
1.91k
) -> arbitrary::Result<(EmulatorContext, [u8; 16])> {
95
1.91k
    let mut u = arbitrary::Unstructured::new(bytes);
96
97
1.91k
    let mut regs = mshv_bindings::StandardRegisters {
98
1.91k
        rax: u.arbitrary()?,
99
1.91k
        rbx: u.arbitrary()?,
100
1.91k
        rcx: u.arbitrary()?,
101
1.91k
        rdx: u.arbitrary()?,
102
1.91k
        rsi: u.arbitrary()?,
103
1.91k
        rdi: u.arbitrary()?,
104
1.91k
        rsp: u.arbitrary()?,
105
1.91k
        rbp: u.arbitrary()?,
106
1.91k
        r8: u.arbitrary()?,
107
1.91k
        r9: u.arbitrary()?,
108
1.91k
        r10: u.arbitrary()?,
109
1.91k
        r11: u.arbitrary()?,
110
1.91k
        r12: u.arbitrary()?,
111
1.91k
        r13: u.arbitrary()?,
112
1.91k
        r14: u.arbitrary()?,
113
1.91k
        r15: u.arbitrary()?,
114
1.91k
        rip: u.arbitrary()?,
115
1.91k
        rflags: u.arbitrary()?,
116
    };
117
118
    // Cap RCX to avoid looping for too long for reps instructions.
119
1.91k
    regs.rcx &= 0xFFFFu64;
120
1.91k
121
1.91k
    let regs = StandardRegisters::Mshv(regs);
122
123
1.91k
    let sregs = SpecialRegisters {
124
1.91k
        cs: generate_segment_register(&mut u)?,
125
1.91k
        ds: generate_segment_register(&mut u)?,
126
1.91k
        es: generate_segment_register(&mut u)?,
127
1.91k
        fs: generate_segment_register(&mut u)?,
128
1.91k
        gs: generate_segment_register(&mut u)?,
129
1.91k
        ss: generate_segment_register(&mut u)?,
130
1.91k
        tr: generate_segment_register(&mut u)?,
131
1.91k
        ldt: generate_segment_register(&mut u)?,
132
1.91k
        gdt: generate_descriptor_table(&mut u)?,
133
1.91k
        idt: generate_descriptor_table(&mut u)?,
134
1.91k
        cr0: u.arbitrary()?,
135
1.91k
        cr2: u.arbitrary()?,
136
1.91k
        cr3: u.arbitrary()?,
137
1.91k
        cr4: u.arbitrary()?,
138
1.91k
        cr8: u.arbitrary()?,
139
1.91k
        efer: u.arbitrary()?,
140
1.91k
        apic_base: u.arbitrary()?,
141
1.91k
        interrupt_bitmap: u.arbitrary()?,
142
    };
143
144
1.91k
    let memory = u.arbitrary::<[u8; 8]>()?;
145
1.91k
    let insn = u.arbitrary::<[u8; 16]>()?;
146
147
1.91k
    let ctx = EmulatorContext {
148
1.91k
        state: EmulatorCpuState { regs, sregs },
149
1.91k
        memory,
150
1.91k
    };
151
1.91k
152
1.91k
    Ok((ctx, insn))
153
1.91k
}