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