Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASLR: PoC for generating random address before Uhyve launches #711

Closed
wants to merge 14 commits into from
Closed
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ path = "benches/benchmarks.rs"
harness = false

[features]
default = []
default = ["aslr"]
aslr = []
instrument = ["rftrace", "rftrace-frontend"]

[dependencies]
Expand All @@ -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"
Expand All @@ -79,4 +81,4 @@ bitflags = "2.4"

[dev-dependencies]
assert_fs = "1"
criterion = "0.5"
criterion = "0.5"
2 changes: 1 addition & 1 deletion src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
36 changes: 35 additions & 1 deletion src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -82,6 +84,7 @@ pub struct UhyveVm<VCpuType: VirtualCPU = VcpuDefault> {
boot_info: *const RawBootInfo,
verbose: bool,
pub virtio_device: Arc<Mutex<VirtioNetPciDevice>>,
aslr_status: bool,
#[allow(dead_code)] // gdb is not supported on macos
pub(super) gdb_port: Option<u16>,
_vcpu_type: PhantomData<VCpuType>,
Expand Down Expand Up @@ -125,6 +128,7 @@ impl<VCpuType: VirtualCPU> UhyveVm<VCpuType> {
args: params.kernel_args,
boot_info: ptr::null(),
verbose: params.verbose,
aslr_status: false,
virtio_device,
gdb_port: params.gdb_port,
_vcpu_type: PhantomData,
Expand Down Expand Up @@ -175,12 +179,37 @@ impl<VCpuType: VirtualCPU> UhyveVm<VCpuType> {
);
}

#[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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not cut it for aarch64. I need to get Uhyve to run on aarch64 and adjust this or make this feature explicitly x86_64-only in the meantime.

}

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;

Expand All @@ -198,6 +227,10 @@ impl<VCpuType: VirtualCPU> UhyveVm<VCpuType> {
kernel_start_address as u64,
);
self.entry_point = entry_point;
#[cfg(feature = "aslr")]
{
self.aslr_status = true;
}

let boot_info = BootInfo {
hardware_info: HardwareInfo {
Expand Down Expand Up @@ -245,6 +278,7 @@ impl<VCpuType: VirtualCPU> fmt::Debug for UhyveVm<VCpuType> {
.field("boot_info", &self.boot_info)
.field("verbose", &self.verbose)
.field("virtio_device", &self.virtio_device)
.field("aslr_status", &self.aslr_status)
.finish()
}
}
Expand Down
Loading