From e31c3f18da12b54917a22a13a87830b94a1d7922 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 3 Feb 2022 10:39:16 -0800 Subject: [PATCH] kvm: sentry executable mappings have to be read-only The sentry guest page tables must not allow to execute writable memory regions. PiperOrigin-RevId: 426183789 --- pkg/sentry/platform/kvm/machine.go | 19 +++++++++++++++---- pkg/sentry/platform/kvm/machine_arm64.go | 12 +++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/pkg/sentry/platform/kvm/machine.go b/pkg/sentry/platform/kvm/machine.go index 2b71a6e35..5f7a044b1 100644 --- a/pkg/sentry/platform/kvm/machine.go +++ b/pkg/sentry/platform/kvm/machine.go @@ -198,7 +198,7 @@ func (m *machine) createVCPU(id int) *vCPU { // readOnlyGuestRegions contains regions that have to be mapped read-only into // the guest physical address space. Right now, it is used on arm64 only. -var readOnlyGuestRegions []region +var readOnlyGuestRegions []virtualRegion // newMachine returns a new VM context. func newMachine(vm int) (*machine, error) { @@ -247,7 +247,7 @@ func newMachine(vm int) (*machine, error) { m.kernel.PageTables.Map( hostarch.Addr(pr.virtual), pr.length, - pagetables.MapOpts{AccessType: hostarch.AnyAccess}, + pagetables.MapOpts{AccessType: hostarch.ReadWrite}, pr.physical) return true // Keep iterating. @@ -257,7 +257,7 @@ func newMachine(vm int) (*machine, error) { // available in the VM. Note that this doesn't guarantee no future // faults, however it should guarantee that everything is available to // ensure successful vCPU entry. - mapRegion := func(vr region, flags uint32) { + mapRegion := func(vr virtualRegion, flags uint32) { for virtual := vr.virtual; virtual < vr.virtual+vr.length; { physical, length, ok := translateToPhysical(virtual) if !ok { @@ -269,6 +269,17 @@ func newMachine(vm int) (*machine, error) { // Cap the length to the end of the area. length = vr.virtual + vr.length - virtual } + // Update page tables for executable mappings. + if vr.accessType.Execute { + if vr.accessType.Write { + panic(fmt.Sprintf("executable mapping can't be writable: %#v", vr)) + } + m.kernel.PageTables.Map( + hostarch.Addr(virtual), + length, + pagetables.MapOpts{AccessType: vr.accessType}, + physical) + } // Ensure the physical range is mapped. m.mapPhysical(physical, length, physicalRegions, flags) @@ -295,7 +306,7 @@ func newMachine(vm int) (*machine, error) { vr.length += 1 << 20 } - mapRegion(vr.region, 0) + mapRegion(vr, 0) }) diff --git a/pkg/sentry/platform/kvm/machine_arm64.go b/pkg/sentry/platform/kvm/machine_arm64.go index a4f3cf224..f4470b7e6 100644 --- a/pkg/sentry/platform/kvm/machine_arm64.go +++ b/pkg/sentry/platform/kvm/machine_arm64.go @@ -107,16 +107,18 @@ func archPhysicalRegions(physicalRegions []physicalRegion) []physicalRegion { return // skip region. } if !vr.accessType.Write { - readOnlyGuestRegions = append(readOnlyGuestRegions, vr.region) + readOnlyGuestRegions = append(readOnlyGuestRegions, vr) } }) rdRegions := readOnlyGuestRegions[:] // Add an unreachable region. - rdRegions = append(rdRegions, region{ - virtual: 0xffffffffffffffff, - length: 0, + rdRegions = append(rdRegions, virtualRegion{ + region: region{ + virtual: 0xffffffffffffffff, + length: 0, + }, }) var regions []physicalRegion @@ -137,7 +139,7 @@ func archPhysicalRegions(physicalRegions []physicalRegion) []physicalRegion { start := pr.virtual end := pr.virtual + pr.length for start < end { - rdRegion := rdRegions[i] + rdRegion := rdRegions[i].region rdStart := rdRegion.virtual rdEnd := rdRegion.virtual + rdRegion.length if rdEnd <= start {