diff --git a/pkg/abi/linux/ptrace_arm64.go b/pkg/abi/linux/ptrace_arm64.go index 91e5af56b..14967f738 100644 --- a/pkg/abi/linux/ptrace_arm64.go +++ b/pkg/abi/linux/ptrace_arm64.go @@ -17,6 +17,37 @@ package linux +const ( + //PSR bits + PSR_MODE_EL0t = 0x00000000 + PSR_MODE_EL1t = 0x00000004 + PSR_MODE_EL1h = 0x00000005 + PSR_MODE_EL2t = 0x00000008 + PSR_MODE_EL2h = 0x00000009 + PSR_MODE_EL3t = 0x0000000c + PSR_MODE_EL3h = 0x0000000d + PSR_MODE_MASK = 0x0000000f + + // AArch32 CPSR bits + PSR_MODE32_BIT = 0x00000010 + + // AArch64 SPSR bits + PSR_F_BIT = 0x00000040 + PSR_I_BIT = 0x00000080 + PSR_A_BIT = 0x00000100 + PSR_D_BIT = 0x00000200 + PSR_BTYPE_MASK = 0x00000c00 + PSR_SSBS_BIT = 0x00001000 + PSR_PAN_BIT = 0x00400000 + PSR_UAO_BIT = 0x00800000 + PSR_DIT_BIT = 0x01000000 + PSR_TCO_BIT = 0x02000000 + PSR_V_BIT = 0x10000000 + PSR_C_BIT = 0x20000000 + PSR_Z_BIT = 0x40000000 + PSR_N_BIT = 0x80000000 +) + // PtraceRegs is the set of CPU registers exposed by ptrace. Source: // syscall.PtraceRegs. // diff --git a/pkg/sentry/arch/arch_aarch64.go b/pkg/sentry/arch/arch_aarch64.go index 7493d6da2..0d61a21e7 100644 --- a/pkg/sentry/arch/arch_aarch64.go +++ b/pkg/sentry/arch/arch_aarch64.go @@ -196,6 +196,9 @@ func (s *State) PtraceSetRegs(src io.Reader) (int, error) { return 0, err } regs.UnmarshalUnsafe(buf) + if !regs.validRegs() { + return 0, linuxerr.EINVAL + } s.Regs = regs return ptraceRegistersSize, nil } diff --git a/pkg/sentry/arch/signal_arm64.go b/pkg/sentry/arch/signal_arm64.go index 6ae77a689..1118d6a7f 100644 --- a/pkg/sentry/arch/signal_arm64.go +++ b/pkg/sentry/arch/signal_arm64.go @@ -138,6 +138,29 @@ func (c *Context64) SignalSetup(st *Stack, act *linux.SigAction, info *linux.Sig 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. @@ -156,6 +179,10 @@ func (c *Context64) SignalRestore(st *Stack, rt bool, featureSet cpuid.FeatureSe 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 { @@ -170,6 +197,7 @@ func (c *Context64) SignalRestore(st *Stack, rt bool, featureSet cpuid.FeatureSe // 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