uhyve
uhyve copied to clipboard
virt_to_phys: breaks if guest_address is not equal to 0
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.