mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
205 lines
5.8 KiB
Go
205 lines
5.8 KiB
Go
// Copyright 2020 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.
|
|
|
|
//go:build arm64
|
|
// +build arm64
|
|
|
|
package arch
|
|
|
|
import (
|
|
"golang.org/x/sys/unix"
|
|
"gvisor.dev/gvisor/pkg/abi/linux"
|
|
"gvisor.dev/gvisor/pkg/cpuid"
|
|
"gvisor.dev/gvisor/pkg/hostarch"
|
|
"gvisor.dev/gvisor/pkg/log"
|
|
"gvisor.dev/gvisor/pkg/sentry/arch/fpu"
|
|
)
|
|
|
|
// SignalContext64 is equivalent to struct sigcontext, the type passed as the
|
|
// second argument to signal handlers set by signal(2).
|
|
//
|
|
// +marshal
|
|
type SignalContext64 struct {
|
|
FaultAddr uint64
|
|
Regs [31]uint64
|
|
Sp uint64
|
|
Pc uint64
|
|
Pstate uint64
|
|
_pad [8]byte // __attribute__((__aligned__(16)))
|
|
Fpsimd64 FpsimdContext // size = 528
|
|
}
|
|
|
|
// +marshal
|
|
type aarch64Ctx struct {
|
|
Magic uint32
|
|
Size uint32
|
|
}
|
|
|
|
// FpsimdContext is equivalent to struct fpsimd_context on arm64
|
|
// (arch/arm64/include/uapi/asm/sigcontext.h).
|
|
//
|
|
// +marshal
|
|
type FpsimdContext struct {
|
|
Head aarch64Ctx
|
|
Fpsr uint32
|
|
Fpcr uint32
|
|
Vregs [64]uint64 // actually [32]uint128
|
|
}
|
|
|
|
// UContext64 is equivalent to ucontext on arm64(arch/arm64/include/uapi/asm/ucontext.h).
|
|
//
|
|
// +marshal
|
|
type UContext64 struct {
|
|
Flags uint64
|
|
Link uint64
|
|
Stack linux.SignalStack
|
|
Sigset linux.SignalSet
|
|
// glibc uses a 1024-bit sigset_t
|
|
_pad [120]byte // (1024 - 64) / 8 = 120
|
|
// sigcontext must be aligned to 16-byte
|
|
_pad2 [8]byte
|
|
// last for future expansion
|
|
MContext SignalContext64
|
|
}
|
|
|
|
// SignalSetup implements Context.SignalSetup.
|
|
func (c *Context64) SignalSetup(st *Stack, act *linux.SigAction, info *linux.SignalInfo, alt *linux.SignalStack, sigset linux.SignalSet, featureSet cpuid.FeatureSet) error {
|
|
sp := st.Bottom
|
|
|
|
// Construct the UContext64 now since we need its size.
|
|
uc := &UContext64{
|
|
Flags: 0,
|
|
Stack: *alt,
|
|
MContext: SignalContext64{
|
|
Regs: c.Regs.Regs,
|
|
Sp: c.Regs.Sp,
|
|
Pc: c.Regs.Pc,
|
|
Pstate: c.Regs.Pstate,
|
|
},
|
|
Sigset: sigset,
|
|
}
|
|
if linux.Signal(info.Signo) == linux.SIGSEGV || linux.Signal(info.Signo) == linux.SIGBUS {
|
|
uc.MContext.FaultAddr = info.Addr()
|
|
}
|
|
|
|
ucSize := uc.SizeBytes()
|
|
|
|
// frameSize = ucSize + sizeof(siginfo).
|
|
// sizeof(siginfo) == 128.
|
|
// R30 stores the restorer address.
|
|
frameSize := ucSize + 128
|
|
frameBottom := (sp - hostarch.Addr(frameSize)) & ^hostarch.Addr(15)
|
|
sp = frameBottom + hostarch.Addr(frameSize)
|
|
st.Bottom = sp
|
|
|
|
// Prior to proceeding, figure out if the frame will exhaust the range
|
|
// for the signal stack. This is not allowed, and should immediately
|
|
// force signal delivery (reverting to the default handler).
|
|
if act.Flags&linux.SA_ONSTACK != 0 && alt.IsEnabled() && !alt.Contains(frameBottom) {
|
|
return unix.EFAULT
|
|
}
|
|
|
|
// Adjust the code.
|
|
info.FixSignalCodeForUser()
|
|
|
|
// Set up the stack frame.
|
|
if _, err := info.CopyOut(st, StackBottomMagic); err != nil {
|
|
return err
|
|
}
|
|
infoAddr := st.Bottom
|
|
if _, err := uc.CopyOut(st, StackBottomMagic); err != nil {
|
|
return err
|
|
}
|
|
ucAddr := st.Bottom
|
|
|
|
// Set up registers.
|
|
c.Regs.Sp = uint64(st.Bottom)
|
|
c.Regs.Pc = act.Handler
|
|
c.Regs.Regs[0] = uint64(info.Signo)
|
|
c.Regs.Regs[1] = uint64(infoAddr)
|
|
c.Regs.Regs[2] = uint64(ucAddr)
|
|
c.Regs.Regs[30] = act.Restorer
|
|
|
|
// Save the thread's floating point state.
|
|
c.sigFPState = append(c.sigFPState, c.fpState)
|
|
// Signal handler gets a clean floating point state.
|
|
c.fpState = fpu.NewState()
|
|
return nil
|
|
}
|
|
|
|
// SPSR_ELx bits which are always architecturally RES0 per ARM DDI 0487D.a.
|
|
const _SPSR_EL1_AARCH64_RES0_BITS = uint64(0xffffffff0cdfe020)
|
|
|
|
func (regs *Registers) userMode() bool {
|
|
return (regs.Pstate & linux.PSR_MODE_MASK) == linux.PSR_MODE_EL0t
|
|
}
|
|
|
|
func (regs *Registers) validRegs() bool {
|
|
regs.Pstate &= ^_SPSR_EL1_AARCH64_RES0_BITS
|
|
|
|
if regs.userMode() && (regs.Pstate&linux.PSR_MODE32_BIT) == 0 &&
|
|
(regs.Pstate&linux.PSR_D_BIT) == 0 &&
|
|
(regs.Pstate&linux.PSR_A_BIT) == 0 &&
|
|
(regs.Pstate&linux.PSR_I_BIT) == 0 &&
|
|
(regs.Pstate&linux.PSR_F_BIT) == 0 {
|
|
return true
|
|
}
|
|
|
|
// Force PSR to a valid 64-bit EL0t
|
|
regs.Pstate &= linux.PSR_N_BIT | linux.PSR_Z_BIT | linux.PSR_C_BIT | linux.PSR_V_BIT
|
|
return false
|
|
}
|
|
|
|
// SignalRestore implements Context.SignalRestore.
|
|
func (c *Context64) SignalRestore(st *Stack, rt bool, featureSet cpuid.FeatureSet) (linux.SignalSet, linux.SignalStack, error) {
|
|
// Copy out the stack frame.
|
|
var uc UContext64
|
|
if _, err := uc.CopyIn(st, StackBottomMagic); err != nil {
|
|
return 0, linux.SignalStack{}, err
|
|
}
|
|
var info linux.SignalInfo
|
|
if _, err := info.CopyIn(st, StackBottomMagic); err != nil {
|
|
return 0, linux.SignalStack{}, err
|
|
}
|
|
|
|
// Restore registers.
|
|
c.Regs.Regs = uc.MContext.Regs
|
|
c.Regs.Pc = uc.MContext.Pc
|
|
c.Regs.Sp = uc.MContext.Sp
|
|
c.Regs.Pstate = uc.MContext.Pstate
|
|
|
|
if !c.Regs.validRegs() {
|
|
return 0, linux.SignalStack{}, unix.EFAULT
|
|
}
|
|
|
|
// Restore floating point state.
|
|
l := len(c.sigFPState)
|
|
if l > 0 {
|
|
c.fpState = c.sigFPState[l-1]
|
|
// NOTE(cl/133042258): State save requires that any slice
|
|
// elements from '[len:cap]' to be zero value.
|
|
c.sigFPState[l-1] = nil
|
|
c.sigFPState = c.sigFPState[0 : l-1]
|
|
} else {
|
|
// This might happen if sigreturn(2) calls are unbalanced with
|
|
// respect to signal handler entries. This is not expected so
|
|
// don't bother to do anything fancy with the floating point
|
|
// state.
|
|
log.Warningf("sigreturn unable to restore application fpstate")
|
|
return 0, linux.SignalStack{}, unix.EFAULT
|
|
}
|
|
|
|
return uc.Sigset, uc.Stack, nil
|
|
}
|