Skip to content

Commit af5adfa

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 af5adfa

File tree

7 files changed

+37
-4
lines changed

7 files changed

+37
-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/native_amd64.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import (
2323
"os"
2424
"strconv"
2525

26+
"golang.org/x/sys/unix"
27+
"gvisor.dev/gvisor/pkg/hostarch"
28+
"gvisor.dev/gvisor/pkg/hostsyscall"
2629
"gvisor.dev/gvisor/pkg/log"
2730
)
2831

@@ -192,6 +195,9 @@ func HostFeatureSet() FeatureSet {
192195
var (
193196
// cpuFreqMHz is the native CPU frequency.
194197
cpuFreqMHz float64
198+
199+
// IsFiveLevelPagingEnabled is true if 5-level paging is enabled on the host.
200+
IsFiveLevelPagingEnabled bool
195201
)
196202

197203
// Reads max cpu frequency from host /proc/cpuinfo. Must run before syscall
@@ -241,6 +247,20 @@ func readMaxCPUFreq() {
241247
// xgetbv reads an extended control register.
242248
func xgetbv(reg uintptr) uint64
243249

250+
// fiveLevelPagingEnabled checks if 5-level paging is enabled on the host.
251+
func fiveLevelPagingEnabled() bool {
252+
addr := uintptr(1 << 48)
253+
p, errno := hostsyscall.RawSyscall6(unix.SYS_MMAP,
254+
addr, hostarch.PageSize, unix.PROT_NONE, unix.MAP_PRIVATE|unix.MAP_ANONYMOUS|unix.MAP_FIXED, 0, 0)
255+
if errno != 0 {
256+
log.Infof("5-level paging is not enabled: Failed to mmap a page size %d at 0x%x: %v", hostarch.PageSize, addr, errno)
257+
return false
258+
} else {
259+
hostsyscall.RawSyscall(unix.SYS_MUNMAP, p, hostarch.PageSize, 0)
260+
}
261+
return true
262+
}
263+
244264
// archInitialize initializes hostFeatureSet.
245265
func archInitialize() {
246266
hostFeatureSet = FeatureSet{
@@ -249,4 +269,5 @@ func archInitialize() {
249269

250270
readMaxCPUFreq()
251271
initHWCap()
272+
IsFiveLevelPagingEnabled = fiveLevelPagingEnabled()
252273
}

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.IsFiveLevelPagingEnabled {
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.IsFiveLevelPagingEnabled {
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.IsFiveLevelPagingEnabled {
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.IsFiveLevelPagingEnabled {
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.IsFiveLevelPagingEnabled
3535
}
3636

3737
func getLowerTopAligned() uintptr {

pkg/tcpip/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ deps_test(
7272
"//pkg/buffer",
7373
"//pkg/cpuid",
7474
"//pkg/gohacks",
75+
"//pkg/hostarch",
76+
"//pkg/hostsyscall",
7577
"//pkg/goid",
7678
"//pkg/ilist",
7779
"//pkg/linewriter",

0 commit comments

Comments
 (0)