1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE-BSD-3-Clause file. 4 // 5 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 6 7 #![no_main] 8 use std::ffi; 9 use std::fs::File; 10 use std::io::{self, Cursor, Read, Seek, SeekFrom, Write}; 11 use std::mem::size_of; 12 use std::os::unix::io::{FromRawFd, RawFd}; 13 14 use block::qcow::{QcowFile, RawFile}; 15 use libfuzzer_sys::{fuzz_target, Corpus}; 16 17 // Take the first 64 bits of data as an address and the next 64 bits as data to 18 // store there. The rest of the data is used as a qcow image. 19 fuzz_target!(|bytes: &[u8]| -> Corpus { 20 if bytes.len() < 16 { 21 // Need an address and data, each are 8 bytes. 22 return Corpus::Reject; 23 } 24 let mut disk_image = Cursor::new(bytes); 25 let addr = read_u64(&mut disk_image); 26 let value = read_u64(&mut disk_image); 27 let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap(); 28 let mut disk_file: File = unsafe { File::from_raw_fd(shm) }; 29 disk_file.write_all(&bytes[16..]).unwrap(); 30 disk_file.seek(SeekFrom::Start(0)).unwrap(); 31 if let Ok(mut qcow) = QcowFile::from(RawFile::new(disk_file, false)) { 32 if qcow.seek(SeekFrom::Start(addr)).is_ok() { 33 let _ = qcow.write_all(&value.to_le_bytes()); 34 } 35 } 36 37 Corpus::Keep 38 }); 39 40 fn read_u64<T: Read>(readable: &mut T) -> u64 { 41 let mut buf = [0u8; size_of::<u64>()]; 42 readable.read_exact(&mut buf[..]).unwrap(); 43 u64::from_le_bytes(buf) 44 } 45 46 fn memfd_create(name: &ffi::CStr, flags: u32) -> Result<RawFd, io::Error> { 47 let res = unsafe { libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags) }; 48 49 if res < 0 { 50 Err(io::Error::last_os_error()) 51 } else { 52 Ok(res as RawFd) 53 } 54 } 55