Skip to content

Commit 1826627

Browse files
nixprimegvisor-bot
authored andcommitted
kvm: ensure hint address > 1<<47 when necessary
The intent of the affected code is to mmap() with a hint address above 1<<47 in order to notify Linux that we can accept, and want, mappings above this address. Using ring0.PhysicalAddressBits for this purpose is incorrect for two reasons: - Some machines can have 57 virtual address bits (i.e. support 5-level paging) but fewer than 47 physical address bits. - When cgo is enabled, the physical address space is artificially limited to 40 bits: https://github.com/google/gvisor/blob/1941bc68e20da25c6cb29330399f122cb3ecfa5a/pkg/sentry/platform/kvm/machine_cgo.go#L30 Also hoist computation of suggestedAddr, which is loop-invariant, out of the loop. PiperOrigin-RevId: 800506920
1 parent 1941bc6 commit 1826627

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

pkg/sentry/platform/kvm/physical_map.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,20 @@ func fillAddressSpace() (specialRegions []specialVirtualRegion) {
107107
}
108108
required := uintptr(requiredAddr)
109109
current := required // Attempted mmap size.
110-
for filled := uintptr(0); filled < required && current > 0; {
111-
suggestedAddr := uintptr(0)
112-
if ring0.VirtualAddressBits > 48 {
113-
// Even though it's safe to pass a high hint address on older kernel or
114-
// older machine without 5-level paging support. We need to guard
115-
// passing the hint based on `ring0.VirtualAddressBits` because Sentry might
116-
// not support 5-level paging for the underlying CPU uarch i.e. arm64.
117-
suggestedAddr = uintptr(1 << ring0.PhysicalAddressBits)
118-
}
110+
filled := uintptr(0)
111+
suggestedAddr := uintptr(0)
112+
if ring0.VirtualAddressBits > 48 {
113+
// Pass a hint address above 47 bits to indicate to the kernel that
114+
// we can handle, and want, mappings above 47 bits:
115+
// https://docs.kernel.org/arch/x86/x86_64/5level-paging.html#user-space-and-large-virtual-address-space.
116+
// Even though it's safe to pass a high hint address on older kernel or
117+
// older machine without 5-level paging support. We need to guard
118+
// passing the hint based on `ring0.VirtualAddressBits` because Sentry might
119+
// not support 5-level paging for the underlying CPU uarch i.e. arm64.
120+
suggestedAddr = ring0.UserspaceSize - hostarch.PageSize
121+
}
122+
var lastMmapErrno unix.Errno
123+
for filled < required && current > 0 {
119124
addr, errno := hostsyscall.RawSyscall6(
120125
unix.SYS_MMAP,
121126
suggestedAddr,
@@ -128,6 +133,7 @@ func fillAddressSpace() (specialRegions []specialVirtualRegion) {
128133
// One page is the smallest mapping that can be allocated.
129134
if current == hostarch.PageSize {
130135
current = 0
136+
lastMmapErrno = errno
131137
break
132138
}
133139
// Attempt half the size; overflow not possible.
@@ -168,6 +174,17 @@ func fillAddressSpace() (specialRegions []specialVirtualRegion) {
168174
}
169175
}
170176
if current == 0 {
177+
log.Warningf("Filling address space failed (VirtualAddressBits=%d PhysicalAddressBits=%d vSize=%#x pSize=%#x faultBlockSize=%#x required=%#x filled=%#x); last mmap errno: %v; VMAs:", ring0.VirtualAddressBits, ring0.PhysicalAddressBits, vSize, pSize, faultBlockSize, required, filled, lastMmapErrno)
178+
err := applyVirtualRegions(func(vr virtualRegion) {
179+
ps := "p"
180+
if vr.shared {
181+
ps = "s"
182+
}
183+
log.Warningf("%x-%x %v%s %08x %s", vr.region.virtual, vr.region.virtual+vr.region.length, vr.accessType, ps, vr.offset, vr.filename)
184+
})
185+
if err != nil {
186+
log.Warningf("Failed to get all VMAs: %v", err)
187+
}
171188
panic("filling address space failed")
172189
}
173190
sort.Slice(specialRegions, func(i, j int) bool {

0 commit comments

Comments
 (0)