Skip to content

Commit 19ca8e6

Browse files
tranji-cloudgvisor-bot
authored andcommitted
Detect if 5-level paging is actually enabled on the host.
The CPUID can indicate support for 5-level paging (57 virtual address bits), but the kernel might not have it enabled. This change adds a check using `mmap` to see if addresses above 2^48 are usable. If not, `VirtualAddressBits` is capped at 48, even if CPUID suggests 57. Fixes #12308 PiperOrigin-RevId: 832518109
1 parent 4304bcd commit 19ca8e6

File tree

6 files changed

+44
-4
lines changed

6 files changed

+44
-4
lines changed

pkg/cpuid/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ go_library(
2222
],
2323
visibility = ["//:sandbox"],
2424
deps = [
25+
"//pkg/hostarch",
26+
"//pkg/hostsyscall",
2527
"//pkg/log",
2628
"//pkg/sync",
29+
"@org_golang_x_sys//unix:go_default_library",
2730
],
2831
)
2932

pkg/cpuid/cpuid_amd64.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ import (
2121
"context"
2222
"fmt"
2323
"io"
24+
25+
"golang.org/x/sys/unix"
26+
"gvisor.dev/gvisor/pkg/hostarch"
27+
"gvisor.dev/gvisor/pkg/hostsyscall"
28+
"gvisor.dev/gvisor/pkg/log"
29+
"gvisor.dev/gvisor/pkg/sync"
2430
)
2531

2632
// FeatureSet defines features in terms of CPUID leaves and bits.
@@ -494,3 +500,27 @@ func (fs FeatureSet) AllowedHWCap2() uint64 {
494500
// HWCAPS are not supported on amd64.
495501
return 0
496502
}
503+
504+
var fiveLevelPaging struct {
505+
once sync.Once
506+
enabled bool
507+
}
508+
509+
// FiveLevelPagingEnabled checks if 5-level paging is enabled on the host.
510+
//
511+
//go:nosplit
512+
func FiveLevelPagingEnabled() bool {
513+
fiveLevelPaging.once.Do(func() {
514+
addr := uintptr(1 << 48)
515+
p, errno := hostsyscall.RawSyscall6(unix.SYS_MMAP,
516+
addr, hostarch.PageSize, unix.PROT_NONE, unix.MAP_PRIVATE|unix.MAP_ANONYMOUS|unix.MAP_FIXED, 0, 0)
517+
if errno != 0 {
518+
log.Infof("5-level paging is not enabled: Failed to mmap a page size %d at 0x%x: %v", hostarch.PageSize, addr, errno)
519+
fiveLevelPaging.enabled = false
520+
} else {
521+
hostsyscall.RawSyscall(unix.SYS_MUNMAP, p, hostarch.PageSize, 0)
522+
fiveLevelPaging.enabled = true
523+
}
524+
})
525+
return fiveLevelPaging.enabled
526+
}

pkg/ring0/kernel_amd64.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ func (c *CPU) CR4() uint64 {
205205
if hasUMIP {
206206
cr4 |= _CR4_UMIP
207207
}
208-
if hasLA57 {
208+
if hasLA57 && cpuid.FiveLevelPagingEnabled() {
209209
cr4 |= _CR4_LA57
210210
}
211211
return cr4
@@ -222,6 +222,9 @@ func (c *CPU) EFER() uint64 {
222222
//
223223
//go:nosplit
224224
func IsCanonical(addr uint64) bool {
225+
if hasLA57 && cpuid.FiveLevelPagingEnabled() {
226+
return addr <= 0x00ffffffffffffff || addr >= 0xff00000000000000
227+
}
225228
return addr <= 0x00007fffffffffff || addr >= 0xffff800000000000
226229
}
227230

pkg/ring0/lib_amd64.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ var (
100100
// another time with a different FeatureSet.
101101
func Init(fs cpuid.FeatureSet) {
102102
// Initialize all sizes.
103-
VirtualAddressBits = uintptr(fs.VirtualAddressBits())
103+
if fs.VirtualAddressBits() > 48 && !cpuid.FiveLevelPagingEnabled() {
104+
VirtualAddressBits = 48
105+
} else {
106+
VirtualAddressBits = uintptr(fs.VirtualAddressBits())
107+
}
104108
if PhysicalAddressBits == 0 {
105109
PhysicalAddressBits = uintptr(fs.PhysicalAddressBits())
106110
}

pkg/ring0/pagetables/pagetables_amd64.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const (
5454
//go:nosplit
5555
func (p *PageTables) InitArch(allocator Allocator) {
5656
featureSet := cpuid.HostFeatureSet()
57-
if featureSet.HasFeature(cpuid.X86FeatureLA57) {
57+
if featureSet.HasFeature(cpuid.X86FeatureLA57) && cpuid.FiveLevelPagingEnabled() {
5858
p.largeAddressesEnabled = true
5959
lowerTop = 0x00FFFFFFFFFFFFFF
6060
upperBottom = 0xFF00000000000000

pkg/ring0/pagetables/pagetables_amd64_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ var (
3131

3232
func getLargeAddressesEnabled() bool {
3333
featureSet := cpuid.HostFeatureSet()
34-
return featureSet.HasFeature(cpuid.X86FeatureLA57)
34+
return featureSet.HasFeature(cpuid.X86FeatureLA57) && cpuid.FiveLevelPagingEnabled()
3535
}
3636

3737
func getLowerTopAligned() uintptr {

0 commit comments

Comments
 (0)