Coverage Report

Created: 2026-06-07 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cloud-hypervisor/fuzz/fuzz_targets/x86emul.rs
Line
Count
Source
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.93M
    fn write_memory(&mut self, _gva: u64, _data: &[u8]) -> Result<(), PlatformError> {
28
        // Discard writes
29
4.93M
        Ok(())
30
4.93M
    }
31
32
2.12k
    fn cpu_state(&self, _cpu_id: usize) -> Result<Self::CpuState, PlatformError> {
33
2.12k
        Ok(self.state.clone())
34
2.12k
    }
35
36
0
    fn set_cpu_state(&self, _cpu_id: usize, _state: Self::CpuState) -> Result<(), PlatformError> {
37
        // Ignore
38
0
        Ok(())
39
0
    }
40
41
0
    fn fetch(&self, _ip: u64, _data: &mut [u8]) -> Result<(), PlatformError> {
42
        // 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
17.0k
fn generate_segment_register(
65
17.0k
    u: &mut arbitrary::Unstructured<'_>,
66
17.0k
) -> arbitrary::Result<SegmentRegister> {
67
    Ok(SegmentRegister {
68
17.0k
        base: u.arbitrary()?,
69
17.0k
        limit: u.arbitrary()?,
70
17.0k
        selector: u.arbitrary()?,
71
17.0k
        avl: u.arbitrary()?,
72
17.0k
        dpl: u.arbitrary()?,
73
17.0k
        db: u.arbitrary()?,
74
17.0k
        g: u.arbitrary()?,
75
17.0k
        l: u.arbitrary()?,
76
17.0k
        present: u.arbitrary()?,
77
17.0k
        s: u.arbitrary()?,
78
17.0k
        type_: u.arbitrary()?,
79
17.0k
        unusable: u.arbitrary()?,
80
    })
81
17.0k
}
82
83
4.25k
fn generate_descriptor_table(
84
4.25k
    u: &mut arbitrary::Unstructured<'_>,
85
4.25k
) -> arbitrary::Result<DescriptorTable> {
86
    Ok(DescriptorTable {
87
4.25k
        base: u.arbitrary()?,
88
4.25k
        limit: u.arbitrary()?,
89
    })
90
4.25k
}
91
92
2.12k
fn generate_context_and_instruction(
93
2.12k
    bytes: &[u8],
94
2.12k
) -> arbitrary::Result<(EmulatorContext, [u8; 16])> {
95
2.12k
    let mut u = arbitrary::Unstructured::new(bytes);
96
97
2.12k
    let mut regs = mshv_bindings::StandardRegisters {
98
2.12k
        rax: u.arbitrary()?,
99
2.12k
        rbx: u.arbitrary()?,
100
2.12k
        rcx: u.arbitrary()?,
101
2.12k
        rdx: u.arbitrary()?,
102
2.12k
        rsi: u.arbitrary()?,
103
2.12k
        rdi: u.arbitrary()?,
104
2.12k
        rsp: u.arbitrary()?,
105
2.12k
        rbp: u.arbitrary()?,
106
2.12k
        r8: u.arbitrary()?,
107
2.12k
        r9: u.arbitrary()?,
108
2.12k
        r10: u.arbitrary()?,
109
2.12k
        r11: u.arbitrary()?,
110
2.12k
        r12: u.arbitrary()?,
111
2.12k
        r13: u.arbitrary()?,
112
2.12k
        r14: u.arbitrary()?,
113
2.12k
        r15: u.arbitrary()?,
114
2.12k
        rip: u.arbitrary()?,
115
2.12k
        rflags: u.arbitrary()?,
116
    };
117
118
    // Cap RCX to avoid looping for too long for reps instructions.
119
2.12k
    regs.rcx &= 0xFFFFu64;
120
121
2.12k
    let regs = StandardRegisters::Mshv(regs);
122
123
2.12k
    let sregs = SpecialRegisters {
124
2.12k
        cs: generate_segment_register(&mut u)?,
125
2.12k
        ds: generate_segment_register(&mut u)?,
126
2.12k
        es: generate_segment_register(&mut u)?,
127
2.12k
        fs: generate_segment_register(&mut u)?,
128
2.12k
        gs: generate_segment_register(&mut u)?,
129
2.12k
        ss: generate_segment_register(&mut u)?,
130
2.12k
        tr: generate_segment_register(&mut u)?,
131
2.12k
        ldt: generate_segment_register(&mut u)?,
132
2.12k
        gdt: generate_descriptor_table(&mut u)?,
133
2.12k
        idt: generate_descriptor_table(&mut u)?,
134
2.12k
        cr0: u.arbitrary()?,
135
2.12k
        cr2: u.arbitrary()?,
136
2.12k
        cr3: u.arbitrary()?,
137
2.12k
        cr4: u.arbitrary()?,
138
2.12k
        cr8: u.arbitrary()?,
139
2.12k
        efer: u.arbitrary()?,
140
2.12k
        apic_base: u.arbitrary()?,
141
2.12k
        interrupt_bitmap: u.arbitrary()?,
142
    };
143
144
2.12k
    let memory = u.arbitrary::<[u8; 8]>()?;
145
2.12k
    let insn = u.arbitrary::<[u8; 16]>()?;
146
147
2.12k
    let ctx = EmulatorContext {
148
2.12k
        state: EmulatorCpuState { regs, sregs },
149
2.12k
        memory,
150
2.12k
    };
151
152
2.12k
    Ok((ctx, insn))
153
2.12k
}