Skip to content

Commit

Permalink
Merge pull request google#2321 from lubinszARM:pr_nogo
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 306300032
  • Loading branch information
gvisor-bot committed Apr 13, 2020
2 parents 5d885d7 + ab54d4f commit e1959f5
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 65 deletions.
4 changes: 3 additions & 1 deletion pkg/sentry/platform/kvm/kvm_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package kvm

import (
"syscall"

"gvisor.dev/gvisor/pkg/sentry/platform/ring0"
)

type kvmOneReg struct {
Expand Down Expand Up @@ -46,6 +48,6 @@ type userRegs struct {
func updateGlobalOnce(fd int) error {
physicalInit()
err := updateSystemValues(int(fd))
updateVectorTable()
ring0.Init()
return err
}
63 changes: 0 additions & 63 deletions pkg/sentry/platform/kvm/machine_arm64_unsafe.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,69 +48,6 @@ func (m *machine) initArchState() error {
return nil
}

func getPageWithReflect(p uintptr) []byte {
return (*(*[0xFFFFFF]byte)(unsafe.Pointer(p & ^uintptr(syscall.Getpagesize()-1))))[:syscall.Getpagesize()]
}

// Work around: move ring0.Vectors() into a specific address with 11-bits alignment.
//
// According to the design documentation of Arm64,
// the start address of exception vector table should be 11-bits aligned.
// Please see the code in linux kernel as reference: arch/arm64/kernel/entry.S
// But, we can't align a function's start address to a specific address by using golang.
// We have raised this question in golang community:
// https://groups.google.com/forum/m/#!topic/golang-dev/RPj90l5x86I
// This function will be removed when golang supports this feature.
//
// There are 2 jobs were implemented in this function:
// 1, move the start address of exception vector table into the specific address.
// 2, modify the offset of each instruction.
func updateVectorTable() {
fromLocation := reflect.ValueOf(ring0.Vectors).Pointer()
offset := fromLocation & (1<<11 - 1)
if offset != 0 {
offset = 1<<11 - offset
}

toLocation := fromLocation + offset
page := getPageWithReflect(toLocation)
if err := syscall.Mprotect(page, syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC); err != nil {
panic(err)
}

page = getPageWithReflect(toLocation + 4096)
if err := syscall.Mprotect(page, syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC); err != nil {
panic(err)
}

// Move exception-vector-table into the specific address.
var entry *uint32
var entryFrom *uint32
for i := 1; i <= 0x800; i++ {
entry = (*uint32)(unsafe.Pointer(toLocation + 0x800 - uintptr(i)))
entryFrom = (*uint32)(unsafe.Pointer(fromLocation + 0x800 - uintptr(i)))
*entry = *entryFrom
}

// The offset from the address of each unconditionally branch is changed.
// We should modify the offset of each instruction.
nums := []uint32{0x0, 0x80, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780}
for _, num := range nums {
entry = (*uint32)(unsafe.Pointer(toLocation + uintptr(num)))
*entry = *entry - (uint32)(offset/4)
}

page = getPageWithReflect(toLocation)
if err := syscall.Mprotect(page, syscall.PROT_READ|syscall.PROT_EXEC); err != nil {
panic(err)
}

page = getPageWithReflect(toLocation + 4096)
if err := syscall.Mprotect(page, syscall.PROT_READ|syscall.PROT_EXEC); err != nil {
panic(err)
}
}

// initArchState initializes architecture-specific state.
func (c *vCPU) initArchState() error {
var (
Expand Down
2 changes: 2 additions & 0 deletions pkg/sentry/platform/ring0/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ go_library(
"lib_amd64.s",
"lib_arm64.go",
"lib_arm64.s",
"lib_arm64_unsafe.go",
"ring0.go",
],
visibility = ["//pkg/sentry:internal"],
deps = [
"//pkg/cpuid",
"//pkg/safecopy",
"//pkg/sentry/platform/ring0/pagetables",
"//pkg/usermem",
],
Expand Down
7 changes: 7 additions & 0 deletions pkg/sentry/platform/ring0/lib_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,10 @@ func SaveVRegs(*byte)

// LoadVRegs loads V0-V31 registers.
func LoadVRegs(*byte)

// Init sets function pointers based on architectural features.
//
// This must be called prior to using ring0.
func Init() {
rewriteVectors()
}
108 changes: 108 additions & 0 deletions pkg/sentry/platform/ring0/lib_arm64_unsafe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build arm64

package ring0

import (
"reflect"
"syscall"
"unsafe"

"gvisor.dev/gvisor/pkg/safecopy"
"gvisor.dev/gvisor/pkg/usermem"
)

const (
nopInstruction = 0xd503201f
instSize = unsafe.Sizeof(uint32(0))
vectorsRawLen = 0x800
)

func unsafeSlice(addr uintptr, length int) (slice []uint32) {
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
hdr.Data = addr
hdr.Len = length / int(instSize)
hdr.Cap = length / int(instSize)
return slice
}

// Work around: move ring0.Vectors() into a specific address with 11-bits alignment.
//
// According to the design documentation of Arm64,
// the start address of exception vector table should be 11-bits aligned.
// Please see the code in linux kernel as reference: arch/arm64/kernel/entry.S
// But, we can't align a function's start address to a specific address by using golang.
// We have raised this question in golang community:
// https://groups.google.com/forum/m/#!topic/golang-dev/RPj90l5x86I
// This function will be removed when golang supports this feature.
//
// There are 2 jobs were implemented in this function:
// 1, move the start address of exception vector table into the specific address.
// 2, modify the offset of each instruction.
func rewriteVectors() {
vectorsBegin := reflect.ValueOf(Vectors).Pointer()

// The exception-vector-table is required to be 11-bits aligned.
// And the size is 0x800.
// Please see the documentation as reference:
// https://developer.arm.com/docs/100933/0100/aarch64-exception-vector-table
//
// But, golang does not allow to set a function's address to a specific value.
// So, for gvisor, I defined the size of exception-vector-table as 4K,
// filled the 2nd 2K part with NOP-s.
// So that, I can safely move the 1st 2K part into the address with 11-bits alignment.
//
// So, the prerequisite for this function to work correctly is:
// vectorsSafeLen >= 0x1000
// vectorsRawLen = 0x800
vectorsSafeLen := int(safecopy.FindEndAddress(vectorsBegin) - vectorsBegin)
if vectorsSafeLen < 2*vectorsRawLen {
panic("Can't update vectors")
}

vectorsSafeTable := unsafeSlice(vectorsBegin, vectorsSafeLen) // Now a []uint32
vectorsRawLen32 := vectorsRawLen / int(instSize)

offset := vectorsBegin & (1<<11 - 1)
if offset != 0 {
offset = 1<<11 - offset
}

pageBegin := (vectorsBegin + offset) & ^uintptr(usermem.PageSize-1)

_, _, errno := syscall.Syscall(syscall.SYS_MPROTECT, uintptr(pageBegin), uintptr(usermem.PageSize), uintptr(syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC))
if errno != 0 {
panic(errno.Error())
}

offset = offset / instSize // By index, not bytes.
// Move exception-vector-table into the specific address, should uses memmove here.
for i := 1; i <= vectorsRawLen32; i++ {
vectorsSafeTable[int(offset)+vectorsRawLen32-i] = vectorsSafeTable[vectorsRawLen32-i]
}

// Adjust branch since instruction was moved forward.
for i := 0; i < vectorsRawLen32; i++ {
if vectorsSafeTable[int(offset)+i] != nopInstruction {
vectorsSafeTable[int(offset)+i] -= uint32(offset)
}
}

_, _, errno = syscall.Syscall(syscall.SYS_MPROTECT, uintptr(pageBegin), uintptr(usermem.PageSize), uintptr(syscall.PROT_READ|syscall.PROT_EXEC))
if errno != 0 {
panic(errno.Error())
}
}
1 change: 0 additions & 1 deletion tools/nogo.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"/pkg/gohacks/gohacks_unsafe.go": "allowed: special case",
"/pkg/sentry/fs/fsutil/host_file_mapper_unsafe.go": "allowed: special case",
"/pkg/sentry/platform/kvm/(bluepill|machine)_unsafe.go": "allowed: special case",
"/pkg/sentry/platform/kvm/machine_arm64_unsafe.go": "fix: gvisor.dev/issue/22464",
"/pkg/sentry/platform/ring0/pagetables/allocator_unsafe.go": "allowed: special case",
"/pkg/sentry/platform/safecopy/safecopy_unsafe.go": "allowed: special case",
"/pkg/sentry/vfs/mount_unsafe.go": "allowed: special case"
Expand Down

0 comments on commit e1959f5

Please sign in to comment.