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