diff --git a/Cargo.lock b/Cargo.lock index 523cb53c..432f0568 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1430,6 +1430,7 @@ dependencies = [ "log", "mac_address", "nix 0.29.0", + "rand", "raw-cpuid", "rftrace", "rftrace-frontend", diff --git a/Cargo.toml b/Cargo.toml index 840198ba..60cbfac8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,8 @@ path = "benches/benchmarks.rs" harness = false [features] -default = [] +default = ["aslr"] +aslr = [] instrument = ["rftrace", "rftrace-frontend"] [dependencies] @@ -60,6 +61,7 @@ uhyve-interface = { version = "0.1.1", path = "uhyve-interface", features = ["st virtio-bindings = { version = "0.2", features = ["virtio-v4_14_0"] } rftrace = { version = "0.1", optional = true } rftrace-frontend = { version = "0.1", optional = true } +rand = "0.8.5" [target.'cfg(target_os = "linux")'.dependencies] kvm-bindings = "0.8" @@ -79,4 +81,4 @@ bitflags = "2.4" [dev-dependencies] assert_fs = "1" -criterion = "0.5" +criterion = "0.5" \ No newline at end of file diff --git a/src/consts.rs b/src/consts.rs index b33727f3..a5480546 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -20,7 +20,7 @@ pub const EFER_LMA: u64 = 1 << 10; /* Long mode active (read-only) */ pub const EFER_NXE: u64 = 1 << 11; /* PTE No-Execute bit enable */ pub const IOAPIC_BASE: u64 = 0xfec00000; pub const IOAPIC_SIZE: u64 = 0x1000; -pub const KERNEL_STACK_SIZE: u64 = 32_768; +pub const KERNEL_STACK_SIZE: u64 = 0x20000; pub const SHAREDQUEUE_START: usize = 0x80000; pub const UHYVE_NET_MTU: usize = 1500; pub const UHYVE_QUEUE_SIZE: usize = 8; diff --git a/src/vm.rs b/src/vm.rs index 8f0ba51a..b9e96205 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -14,6 +14,8 @@ use hermit_entry::{ elf::{KernelObject, LoadedKernel, ParseKernelError}, }; use log::{error, warn}; +#[cfg(feature = "aslr")] +use rand::Rng; use thiserror::Error; #[cfg(target_arch = "x86_64")] @@ -82,6 +84,7 @@ pub struct UhyveVm { boot_info: *const RawBootInfo, verbose: bool, pub virtio_device: Arc>, + aslr_status: bool, #[allow(dead_code)] // gdb is not supported on macos pub(super) gdb_port: Option, _vcpu_type: PhantomData, @@ -125,6 +128,7 @@ impl UhyveVm { args: params.kernel_args, boot_info: ptr::null(), verbose: params.verbose, + aslr_status: false, virtio_device, gdb_port: params.gdb_port, _vcpu_type: PhantomData, @@ -175,12 +179,37 @@ impl UhyveVm { ); } + #[cfg(feature = "aslr")] + fn generate_start_address(&mut self, object_mem_size: u64) -> u64 { + let mut rng = rand::thread_rng(); + + // TODO: This breaks sometimes, causing the _kernel_ to return InsufficientMemory errors, despite the + // checks the boot process passing. Why? + // + // This seems to be a problem on the side of hermit-os/kernel, which does not behave very well if the + // start address is way too high. For some mysterious reason, this problem never occurs if we do not + // go past 0x3000000. + let start_address_upper_bound: u64 = std::cmp::min( + self.mem.memory_size as u64 - self.mem.guest_address.as_u64() - object_mem_size, + 0x3000000, + ); + + // TODO: Add test. (from start_address_upper_bound-0x000001 to start_address_upper_bound+0x000001) + // + // We use 0x100000 as the offset for the start address so as to not use the zero page. + rng.gen_range(0x100000..start_address_upper_bound) & 0xffff_ffff_ffff_fff0 + } + pub fn load_kernel(&mut self) -> LoadKernelResult<()> { let elf = fs::read(self.kernel_path())?; let object = KernelObject::parse(&elf).map_err(LoadKernelError::ParseKernelError)?; - // TODO: should be a random start address, if we have a relocatable executable + #[cfg(not(feature = "aslr"))] let kernel_start_address = object.start_addr().unwrap_or(0x400000) as usize; + + #[cfg(feature = "aslr")] + let kernel_start_address = self.generate_start_address(object.mem_size() as u64) as usize; + let kernel_end_address = kernel_start_address + object.mem_size(); self.offset = kernel_start_address as u64; @@ -198,6 +227,10 @@ impl UhyveVm { kernel_start_address as u64, ); self.entry_point = entry_point; + #[cfg(feature = "aslr")] + { + self.aslr_status = true; + } let boot_info = BootInfo { hardware_info: HardwareInfo { @@ -245,6 +278,7 @@ impl fmt::Debug for UhyveVm { .field("boot_info", &self.boot_info) .field("verbose", &self.verbose) .field("virtio_device", &self.virtio_device) + .field("aslr_status", &self.aslr_status) .finish() } }