uhyve icon indicating copy to clipboard operation
uhyve copied to clipboard

virt_to_phys: breaks if guest_address is not equal to 0

Open n0toose opened this issue 8 months ago • 6 comments

This is the result of an excruciatingly long debugging session for https://github.com/hermit-os/uhyve/pull/711.

Say that we want to replace arch::RAM_START in the line 98 of vm.rs:

https://github.com/hermit-os/uhyve/blob/efc35639f8c6939b9ec6745ad44c71dd4fda0a28/src/vm.rs#L94

... to let mem = MmapMemory::new(0, memory_size, GuestPhysAddr::new(0x20000), params.thp, params.ksm);.

So, guest_address will be equal to 0x20000. There are many parts of the code which effectively already consider this case, by subtracting self.mem.guest_address. This is very often the case in vm.rs.

Debugging this was much more difficult because of the fact that the process "froze". With cargo test gdb (I could've used gdb) and LLDB running on the side. A previous indicator that something in phys_to_virt is broken was running the following test with a similar change: https://github.com/hermit-os/uhyve/blob/efc35639f8c6939b9ec6745ad44c71dd4fda0a28/src/arch/x86_64/mod.rs#L372

This would always return a WrongMemoryError.

virt_to_phys invokes a function called mem.host_address(pagetable_l0): https://github.com/hermit-os/uhyve/blob/efc35639f8c6939b9ec6745ad44c71dd4fda0a28/src/arch/x86_64/mod.rs#L208

That function has two conditions (function slightly modified for clarity and because it was easier for me to debug that way):

	pub fn host_address(&self, addr: GuestPhysAddr) -> Result<*const u8, MemoryError> {
		let addr_lt_guest: bool = addr < self.guest_address;
		let addr_ht_guest_plus_memsize: bool = addr.as_u64() as usize > self.guest_address.as_u64() as usize + self.memory_size;
		let expression: bool = addr_lt_guest || addr_ht_guest_plus_memsize;
		if expression
		{
			return Err(MemoryError::WrongMemoryError);
		}
		Ok(

Let's take a look at read_addrs in uhyve/src/linux/gdb.rs: https://github.com/hermit-os/uhyve/blob/efc35639f8c6939b9ec6745ad44c71dd4fda0a28/src/linux/gdb/mod.rs#L129

This uses a constant: pub const BOOT_PML4: GuestPhysAddr = GuestPhysAddr::new(0x10000);

https://github.com/hermit-os/uhyve/blob/efc35639f8c6939b9ec6745ad44c71dd4fda0a28/src/consts.rs#L12

which is passed onto: https://github.com/hermit-os/uhyve/blob/efc35639f8c6939b9ec6745ad44c71dd4fda0a28/src/linux/gdb/mod.rs#L134

... as the pagetable_l0 variable, which is in turn passed as the addr variable. If we choose a guest_address equal to 0x20000, the first condition will fail.


This error basically pops up everywhere, one way or another, when the guest_address is modified. This was the best and most reproducible case that I could find after spending hours of trying to crack it for https://github.com/hermit-os/uhyve/pull/711.

n0toose avatar Jun 19 '24 11:06 n0toose