|
| 1 | +use core::{ |
| 2 | + ffi::{CStr, c_char, c_int}, |
| 3 | + marker::PhantomData, |
| 4 | +}; |
| 5 | + |
| 6 | +use libc::{O_NONBLOCK, O_RDONLY}; |
| 7 | +use log::trace; |
| 8 | +use thiserror::Error; |
| 9 | + |
| 10 | +use crate::{ |
| 11 | + asan_swap, |
| 12 | + file::FileReader, |
| 13 | + size_t, ssize_t, |
| 14 | + symbols::{AtomicGuestAddr, Function, FunctionPointer, FunctionPointerError, Symbols}, |
| 15 | +}; |
| 16 | + |
| 17 | +#[derive(Debug)] |
| 18 | +struct FunctionOpen; |
| 19 | + |
| 20 | +impl Function for FunctionOpen { |
| 21 | + const NAME: &CStr = c"open"; |
| 22 | + type Func = unsafe extern "C" fn(*const c_char, c_int, c_int) -> c_int; |
| 23 | +} |
| 24 | + |
| 25 | +#[derive(Debug)] |
| 26 | +struct FunctionClose; |
| 27 | + |
| 28 | +impl Function for FunctionClose { |
| 29 | + const NAME: &CStr = c"close"; |
| 30 | + type Func = unsafe extern "C" fn(c_int) -> c_int; |
| 31 | +} |
| 32 | + |
| 33 | +#[derive(Debug)] |
| 34 | +struct FunctionRead; |
| 35 | + |
| 36 | +impl Function for FunctionRead { |
| 37 | + const NAME: &CStr = c"read"; |
| 38 | + type Func = unsafe extern "C" fn(c_int, *mut c_char, size_t) -> ssize_t; |
| 39 | +} |
| 40 | + |
| 41 | +#[derive(Debug)] |
| 42 | +struct FunctionErrnoLocation; |
| 43 | + |
| 44 | +impl Function for FunctionErrnoLocation { |
| 45 | + const NAME: &CStr = c"__errno_location"; |
| 46 | + type Func = unsafe extern "C" fn() -> *mut c_int; |
| 47 | +} |
| 48 | + |
| 49 | +static OPEN_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); |
| 50 | +static CLOSE_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); |
| 51 | +static READ_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); |
| 52 | +static GET_ERRNO_LOCATION_ADDR: AtomicGuestAddr = AtomicGuestAddr::new(); |
| 53 | + |
| 54 | +#[derive(Debug)] |
| 55 | +pub struct LibcFileReader<S: Symbols> { |
| 56 | + fd: c_int, |
| 57 | + _phantom: PhantomData<S>, |
| 58 | +} |
| 59 | + |
| 60 | +impl<S: Symbols> LibcFileReader<S> { |
| 61 | + fn get_open() -> Result<<FunctionOpen as Function>::Func, LibcFileReaderError<S>> { |
| 62 | + let addr = OPEN_ADDR.try_get_or_insert_with(|| { |
| 63 | + S::lookup(FunctionOpen::NAME).map_err(|e| LibcFileReaderError::FailedToFindSymbol(e)) |
| 64 | + })?; |
| 65 | + let f = |
| 66 | + FunctionOpen::as_ptr(addr).map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; |
| 67 | + Ok(f) |
| 68 | + } |
| 69 | + |
| 70 | + fn get_close() -> Result<<FunctionClose as Function>::Func, LibcFileReaderError<S>> { |
| 71 | + let addr = CLOSE_ADDR.try_get_or_insert_with(|| { |
| 72 | + S::lookup(FunctionClose::NAME).map_err(|e| LibcFileReaderError::FailedToFindSymbol(e)) |
| 73 | + })?; |
| 74 | + let f = |
| 75 | + FunctionClose::as_ptr(addr).map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; |
| 76 | + Ok(f) |
| 77 | + } |
| 78 | + |
| 79 | + fn get_read() -> Result<<FunctionRead as Function>::Func, LibcFileReaderError<S>> { |
| 80 | + let addr = READ_ADDR.try_get_or_insert_with(|| { |
| 81 | + S::lookup(FunctionRead::NAME).map_err(|e| LibcFileReaderError::FailedToFindSymbol(e)) |
| 82 | + })?; |
| 83 | + let f = |
| 84 | + FunctionRead::as_ptr(addr).map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; |
| 85 | + Ok(f) |
| 86 | + } |
| 87 | + |
| 88 | + fn get_errno_location() |
| 89 | + -> Result<<FunctionErrnoLocation as Function>::Func, LibcFileReaderError<S>> { |
| 90 | + let addr = GET_ERRNO_LOCATION_ADDR.try_get_or_insert_with(|| { |
| 91 | + S::lookup(FunctionErrnoLocation::NAME) |
| 92 | + .map_err(|e| LibcFileReaderError::FailedToFindSymbol(e)) |
| 93 | + })?; |
| 94 | + let f = FunctionErrnoLocation::as_ptr(addr) |
| 95 | + .map_err(|e| LibcFileReaderError::InvalidPointerType(e))?; |
| 96 | + Ok(f) |
| 97 | + } |
| 98 | + |
| 99 | + fn errno() -> Result<c_int, LibcFileReaderError<S>> { |
| 100 | + unsafe { asan_swap(false) }; |
| 101 | + let errno_location = Self::get_errno_location()?; |
| 102 | + unsafe { asan_swap(true) }; |
| 103 | + let errno = unsafe { *errno_location() }; |
| 104 | + Ok(errno) |
| 105 | + } |
| 106 | +} |
| 107 | + |
| 108 | +impl<S: Symbols> FileReader for LibcFileReader<S> { |
| 109 | + type Error = LibcFileReaderError<S>; |
| 110 | + fn new(path: &CStr) -> Result<LibcFileReader<S>, Self::Error> { |
| 111 | + let fn_open = Self::get_open()?; |
| 112 | + unsafe { asan_swap(false) }; |
| 113 | + let fd = unsafe { fn_open(path.as_ptr() as *const c_char, O_NONBLOCK | O_RDONLY, 0) }; |
| 114 | + unsafe { asan_swap(true) }; |
| 115 | + if fd < 0 { |
| 116 | + let errno = Self::errno().unwrap(); |
| 117 | + return Err(LibcFileReaderError::FailedToOpen(errno)); |
| 118 | + } |
| 119 | + Ok(LibcFileReader { |
| 120 | + fd, |
| 121 | + _phantom: PhantomData, |
| 122 | + }) |
| 123 | + } |
| 124 | + fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { |
| 125 | + let fn_read = Self::get_read()?; |
| 126 | + unsafe { asan_swap(false) }; |
| 127 | + let ret = unsafe { fn_read(self.fd, buf.as_mut_ptr() as *mut c_char, buf.len()) }; |
| 128 | + unsafe { asan_swap(true) }; |
| 129 | + if ret < 0 { |
| 130 | + let errno = Self::errno().unwrap(); |
| 131 | + return Err(LibcFileReaderError::FailedToRead(self.fd, errno)); |
| 132 | + } |
| 133 | + Ok(ret as usize) |
| 134 | + } |
| 135 | +} |
| 136 | + |
| 137 | +impl<S: Symbols> Drop for LibcFileReader<S> { |
| 138 | + fn drop(&mut self) { |
| 139 | + let fn_close = Self::get_close().unwrap(); |
| 140 | + unsafe { asan_swap(false) }; |
| 141 | + let ret = unsafe { fn_close(self.fd) }; |
| 142 | + unsafe { asan_swap(true) }; |
| 143 | + if ret < 0 { |
| 144 | + let errno = Self::errno().unwrap(); |
| 145 | + panic!("Failed to close: {}, Errno: {}", self.fd, errno); |
| 146 | + } |
| 147 | + trace!("Closed fd: {}", self.fd); |
| 148 | + } |
| 149 | +} |
| 150 | + |
| 151 | +#[derive(Error, Debug, PartialEq)] |
| 152 | +pub enum LibcFileReaderError<S: Symbols> { |
| 153 | + #[error("Failed to find mmap functions")] |
| 154 | + FailedToFindSymbol(S::Error), |
| 155 | + #[error("Invalid pointer type: {0:?}")] |
| 156 | + InvalidPointerType(FunctionPointerError), |
| 157 | + #[error("Failed to read - fd: {0}, errno: {1}")] |
| 158 | + FailedToRead(c_int, c_int), |
| 159 | + #[error("Failed to open - errno: {0}")] |
| 160 | + FailedToOpen(c_int), |
| 161 | +} |
0 commit comments