From 633e3adc617580b8e2ee15589f9f27a792d61ab7 Mon Sep 17 00:00:00 2001 From: Erin Date: Fri, 24 Nov 2023 01:09:15 +0100 Subject: [PATCH] Add basic Win32 support --- Cargo.lock | 77 +++++++++++++++++++++++++++++++ hbvm/fuzz/.gitignore | 5 -- hbvm/fuzz/Cargo.toml | 30 ------------ hbvm/fuzz/fuzz_targets/vm.rs | 82 --------------------------------- hbxrt/Cargo.toml | 14 +++++- hbxrt/src/main.rs | 20 +++++--- hbxrt/src/{linux.rs => unix.rs} | 2 +- hbxrt/src/win32.rs | 69 +++++++++++++++++++++++++++ 8 files changed, 173 insertions(+), 126 deletions(-) delete mode 100644 hbvm/fuzz/.gitignore delete mode 100644 hbvm/fuzz/Cargo.toml delete mode 100644 hbvm/fuzz/fuzz_targets/vm.rs rename hbxrt/src/{linux.rs => unix.rs} (97%) create mode 100644 hbxrt/src/win32.rs diff --git a/Cargo.lock b/Cargo.lock index d6b4d5124..6f8b02af4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,6 +221,7 @@ version = "0.1.0" dependencies = [ "hbvm", "nix", + "windows", ] [[package]] @@ -527,6 +528,82 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "with_builtin_macros" version = "0.0.3" diff --git a/hbvm/fuzz/.gitignore b/hbvm/fuzz/.gitignore deleted file mode 100644 index 615384a80..000000000 --- a/hbvm/fuzz/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -target -artifacts -corpus -coverage -Cargo.lock \ No newline at end of file diff --git a/hbvm/fuzz/Cargo.toml b/hbvm/fuzz/Cargo.toml deleted file mode 100644 index 42566bd34..000000000 --- a/hbvm/fuzz/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "hbvm-fuzz" -version = "0.0.0" -publish = false -edition = "2021" - -[package.metadata] -cargo-fuzz = true - -[dependencies] -libfuzzer-sys = "0.4" - -[dependencies.hbvm] -path = ".." - -[dependencies.hbbytecode] -path = "../../hbbytecode" - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[profile.release] -debug = 1 - -[[bin]] -name = "vm" -path = "fuzz_targets/vm.rs" -test = false -doc = false diff --git a/hbvm/fuzz/fuzz_targets/vm.rs b/hbvm/fuzz/fuzz_targets/vm.rs deleted file mode 100644 index aa6d7ccf9..000000000 --- a/hbvm/fuzz/fuzz_targets/vm.rs +++ /dev/null @@ -1,82 +0,0 @@ -#![no_main] - -use { - hbvm::{ - mem::{ - softpaging::{ - paging::{PageTable, Permission}, - HandlePageFault, PageSize, SoftPagedMem, - }, - Address, MemoryAccessReason, - }, - Vm, - }, - libfuzzer_sys::fuzz_target, -}; - -fuzz_target!(|data: &[u8]| { - let mut vm = unsafe { - Vm::<_, 16384>::new( - SoftPagedMem::<_, true> { - pf_handler: TestTrapHandler, - program: data, - root_pt: Box::into_raw(Default::default()), - icache: Default::default(), - }, - Address::new(4), - ) - }; - - // Alloc and map some memory - let pages = [ - alloc_and_map(&mut vm.memory, 0), - alloc_and_map(&mut vm.memory, 4096), - ]; - - // Run VM - let _ = vm.run(); - - // Unmap and dealloc the memory - for (i, page) in pages.into_iter().enumerate() { - unmap_and_dealloc(&mut vm.memory, page, i as u64 * 4096); - } - - let _ = unsafe { Box::from_raw(vm.memory.root_pt) }; -}); - -fn alloc_and_map(memory: &mut SoftPagedMem, at: u64) -> *mut u8 { - let ptr = Box::into_raw(Box::::default()).cast(); - unsafe { - memory - .map(ptr, Address::new(at), Permission::Write, PageSize::Size4K) - .unwrap() - }; - ptr -} - -fn unmap_and_dealloc(memory: &mut SoftPagedMem, ptr: *mut u8, from: u64) { - memory.unmap(Address::new(from)).unwrap(); - let _ = unsafe { Box::from_raw(ptr.cast::()) }; -} - -#[repr(align(4096))] -struct Page([u8; 4096]); -impl Default for Page { - fn default() -> Self { - unsafe { std::mem::MaybeUninit::zeroed().assume_init() } - } -} - -struct TestTrapHandler; -impl HandlePageFault for TestTrapHandler { - fn page_fault( - &mut self, - _: MemoryAccessReason, - _: &mut PageTable, - _: Address, - _: PageSize, - _: *mut u8, - ) -> bool { - false - } -} diff --git a/hbxrt/Cargo.toml b/hbxrt/Cargo.toml index 2fd08a924..c880971e4 100644 --- a/hbxrt/Cargo.toml +++ b/hbxrt/Cargo.toml @@ -6,4 +6,16 @@ default-run = "hbxrt" [dependencies] hbvm.path = "../hbvm" -nix = { version = "0.27", features = ["mman", "signal"] } + +[target.'cfg(unix)'.dependencies] +nix = { version = "0.27", features = ["mman", "signal"] } + +[target.'cfg(windows)'.dependencies.windows] +version = "0.52" +features = [ + "Win32_Foundation", + "Win32_System_Memory", + "Win32_System_SystemServices", + "Win32_Security", + "Win32_Storage_FileSystem", +] diff --git a/hbxrt/src/main.rs b/hbxrt/src/main.rs index 121af6ada..07aafe4b4 100644 --- a/hbxrt/src/main.rs +++ b/hbxrt/src/main.rs @@ -2,17 +2,23 @@ #![deny(unsafe_op_in_unsafe_fn)] -mod linux; +#[cfg(unix)] +#[path = "unix.rs"] +mod platform; + +#[cfg(windows)] +#[path = "win32.rs"] +mod platform; + mod mem; use { hbvm::{mem::Address, Vm, VmRunOk}, - nix::sys::mman::{mmap, MapFlags, ProtFlags}, - std::{env::args, fs::File, num::NonZeroUsize, process::exit}, + std::{env::args, process::exit}, }; fn main() -> Result<(), Box> { - eprintln!("== HB×RT (Holey Bytes Linux Runtime) v0.1 =="); + eprintln!("== HB×RT (Holey Bytes Experimental Runtime) v0.1 =="); eprintln!("[W] Currently supporting only flat images"); let Some(image_path) = args().nth(1) else { @@ -21,18 +27,18 @@ fn main() -> Result<(), Box> { }; // Allocate stack - let stack_ptr = unsafe { linux::alloc_stack(1024 * 1024 * 2) }?; + let stack_ptr = unsafe { platform::alloc_stack(1024 * 1024 * 2) }?; eprintln!("[I] Stack allocated at {stack_ptr:p}"); // Load program eprintln!("[I] Loading image from \"{image_path}\""); - let ptr = unsafe { linux::mmap_bytecode(image_path) }?; + let ptr = unsafe { platform::mmap_bytecode(image_path) }?; eprintln!("[I] Image loaded at {ptr:p}"); let mut vm = unsafe { Vm::<_, 0>::new(mem::HostMemory, Address::new(ptr as u64)) }; vm.write_reg(254, stack_ptr as u64); - unsafe { linux::hook_pagefault() }?; + unsafe { platform::catch_mafs() }?; // Execute program let stat = loop { diff --git a/hbxrt/src/linux.rs b/hbxrt/src/unix.rs similarity index 97% rename from hbxrt/src/linux.rs rename to hbxrt/src/unix.rs index 949d971cb..419d014f4 100644 --- a/hbxrt/src/linux.rs +++ b/hbxrt/src/unix.rs @@ -38,7 +38,7 @@ pub unsafe fn mmap_bytecode(path: impl AsRef) -> Result<*mut u8, Box nix::Result<()> { +pub unsafe fn catch_mafs() -> nix::Result<()> { unsafe { use nix::sys::signal; diff --git a/hbxrt/src/win32.rs b/hbxrt/src/win32.rs new file mode 100644 index 000000000..516b4a52b --- /dev/null +++ b/hbxrt/src/win32.rs @@ -0,0 +1,69 @@ +use { + std::path::Path, + windows::{ + core::PCSTR, + Win32::{ + Foundation::{GetLastError, GENERIC_READ}, + Storage::FileSystem, + System::{ + Memory::{self}, + SystemServices::{self}, + }, + }, + }, +}; + +/// Allocates tack for the program +pub unsafe fn alloc_stack(size: usize) -> windows::core::Result<*mut u8> { + let ptr = unsafe { + Memory::VirtualAlloc( + None, + size, + Memory::VIRTUAL_ALLOCATION_TYPE(SystemServices::MEM_TOP_DOWN) | Memory::MEM_COMMIT, + Memory::PAGE_READWRITE, + ) + }; + + if ptr.is_null() { + unsafe { GetLastError() }?; + } + + Ok(ptr.cast()) +} + +/// Memory map bytecode +pub unsafe fn mmap_bytecode(path: impl AsRef) -> windows::core::Result<*mut u8> { + unsafe { + let file = FileSystem::CreateFileA( + PCSTR(path.as_ref().as_os_str().as_encoded_bytes().as_ptr()), + GENERIC_READ.0, + FileSystem::FILE_SHARE_READ, + None, + FileSystem::OPEN_EXISTING, + FileSystem::FILE_ATTRIBUTE_NORMAL, + None, + )?; + + let h = Memory::CreateFileMappingA( + file, + None, + Memory::PAGE_READONLY, + 0, + 0, + PCSTR("Bytecode\0".as_ptr()), + )?; + + let addr = Memory::MapViewOfFile(h, Memory::FILE_MAP_READ, 0, 0, 0); + + if addr.Value.is_null() { + GetLastError()?; + } + + Ok(addr.Value.cast()) + } +} + +/// Catch memory access faults +pub unsafe fn catch_mafs() -> std::io::Result<()> { + Ok(()) +}