github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/arch/signal_arm64.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build arm64 16 // +build arm64 17 18 package arch 19 20 import ( 21 "golang.org/x/sys/unix" 22 "github.com/nicocha30/gvisor-ligolo/pkg/abi/linux" 23 "github.com/nicocha30/gvisor-ligolo/pkg/cpuid" 24 "github.com/nicocha30/gvisor-ligolo/pkg/hostarch" 25 "github.com/nicocha30/gvisor-ligolo/pkg/log" 26 "github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch/fpu" 27 ) 28 29 // SignalContext64 is equivalent to struct sigcontext, the type passed as the 30 // second argument to signal handlers set by signal(2). 31 // 32 // +marshal 33 type SignalContext64 struct { 34 FaultAddr uint64 35 Regs [31]uint64 36 Sp uint64 37 Pc uint64 38 Pstate uint64 39 _pad [8]byte // __attribute__((__aligned__(16))) 40 Fpsimd64 FpsimdContext // size = 528 41 } 42 43 // +marshal 44 type aarch64Ctx struct { 45 Magic uint32 46 Size uint32 47 } 48 49 // FpsimdContext is equivalent to struct fpsimd_context on arm64 50 // (arch/arm64/include/uapi/asm/sigcontext.h). 51 // 52 // +marshal 53 type FpsimdContext struct { 54 Head aarch64Ctx 55 Fpsr uint32 56 Fpcr uint32 57 Vregs [64]uint64 // actually [32]uint128 58 } 59 60 // UContext64 is equivalent to ucontext on arm64(arch/arm64/include/uapi/asm/ucontext.h). 61 // 62 // +marshal 63 type UContext64 struct { 64 Flags uint64 65 Link uint64 66 Stack linux.SignalStack 67 Sigset linux.SignalSet 68 // glibc uses a 1024-bit sigset_t 69 _pad [120]byte // (1024 - 64) / 8 = 120 70 // sigcontext must be aligned to 16-byte 71 _pad2 [8]byte 72 // last for future expansion 73 MContext SignalContext64 74 } 75 76 // SignalSetup implements Context.SignalSetup. 77 func (c *Context64) SignalSetup(st *Stack, act *linux.SigAction, info *linux.SignalInfo, alt *linux.SignalStack, sigset linux.SignalSet, featureSet cpuid.FeatureSet) error { 78 sp := st.Bottom 79 80 // Construct the UContext64 now since we need its size. 81 uc := &UContext64{ 82 Flags: 0, 83 Stack: *alt, 84 MContext: SignalContext64{ 85 Regs: c.Regs.Regs, 86 Sp: c.Regs.Sp, 87 Pc: c.Regs.Pc, 88 Pstate: c.Regs.Pstate, 89 }, 90 Sigset: sigset, 91 } 92 if linux.Signal(info.Signo) == linux.SIGSEGV || linux.Signal(info.Signo) == linux.SIGBUS { 93 uc.MContext.FaultAddr = info.Addr() 94 } 95 96 ucSize := uc.SizeBytes() 97 98 // frameSize = ucSize + sizeof(siginfo). 99 // sizeof(siginfo) == 128. 100 // R30 stores the restorer address. 101 frameSize := ucSize + 128 102 frameBottom := (sp - hostarch.Addr(frameSize)) & ^hostarch.Addr(15) 103 sp = frameBottom + hostarch.Addr(frameSize) 104 st.Bottom = sp 105 106 // Prior to proceeding, figure out if the frame will exhaust the range 107 // for the signal stack. This is not allowed, and should immediately 108 // force signal delivery (reverting to the default handler). 109 if act.Flags&linux.SA_ONSTACK != 0 && alt.IsEnabled() && !alt.Contains(frameBottom) { 110 return unix.EFAULT 111 } 112 113 // Adjust the code. 114 info.FixSignalCodeForUser() 115 116 // Set up the stack frame. 117 if _, err := info.CopyOut(st, StackBottomMagic); err != nil { 118 return err 119 } 120 infoAddr := st.Bottom 121 if _, err := uc.CopyOut(st, StackBottomMagic); err != nil { 122 return err 123 } 124 ucAddr := st.Bottom 125 126 // Set up registers. 127 c.Regs.Sp = uint64(st.Bottom) 128 c.Regs.Pc = act.Handler 129 c.Regs.Regs[0] = uint64(info.Signo) 130 c.Regs.Regs[1] = uint64(infoAddr) 131 c.Regs.Regs[2] = uint64(ucAddr) 132 c.Regs.Regs[30] = act.Restorer 133 134 // Save the thread's floating point state. 135 c.sigFPState = append(c.sigFPState, c.fpState) 136 // Signal handler gets a clean floating point state. 137 c.fpState = fpu.NewState() 138 return nil 139 } 140 141 // SPSR_ELx bits which are always architecturally RES0 per ARM DDI 0487D.a. 142 const _SPSR_EL1_AARCH64_RES0_BITS = uint64(0xffffffff0cdfe020) 143 144 func (regs *Registers) userMode() bool { 145 return (regs.Pstate & linux.PSR_MODE_MASK) == linux.PSR_MODE_EL0t 146 } 147 148 func (regs *Registers) validRegs() bool { 149 regs.Pstate &= ^_SPSR_EL1_AARCH64_RES0_BITS 150 151 if regs.userMode() && (regs.Pstate&linux.PSR_MODE32_BIT) == 0 && 152 (regs.Pstate&linux.PSR_D_BIT) == 0 && 153 (regs.Pstate&linux.PSR_A_BIT) == 0 && 154 (regs.Pstate&linux.PSR_I_BIT) == 0 && 155 (regs.Pstate&linux.PSR_F_BIT) == 0 { 156 return true 157 } 158 159 // Force PSR to a valid 64-bit EL0t 160 regs.Pstate &= linux.PSR_N_BIT | linux.PSR_Z_BIT | linux.PSR_C_BIT | linux.PSR_V_BIT 161 return false 162 } 163 164 // SignalRestore implements Context.SignalRestore. 165 func (c *Context64) SignalRestore(st *Stack, rt bool, featureSet cpuid.FeatureSet) (linux.SignalSet, linux.SignalStack, error) { 166 // Copy out the stack frame. 167 var uc UContext64 168 if _, err := uc.CopyIn(st, StackBottomMagic); err != nil { 169 return 0, linux.SignalStack{}, err 170 } 171 var info linux.SignalInfo 172 if _, err := info.CopyIn(st, StackBottomMagic); err != nil { 173 return 0, linux.SignalStack{}, err 174 } 175 176 // Restore registers. 177 c.Regs.Regs = uc.MContext.Regs 178 c.Regs.Pc = uc.MContext.Pc 179 c.Regs.Sp = uc.MContext.Sp 180 c.Regs.Pstate = uc.MContext.Pstate 181 182 if !c.Regs.validRegs() { 183 return 0, linux.SignalStack{}, unix.EFAULT 184 } 185 186 // Restore floating point state. 187 l := len(c.sigFPState) 188 if l > 0 { 189 c.fpState = c.sigFPState[l-1] 190 // NOTE(cl/133042258): State save requires that any slice 191 // elements from '[len:cap]' to be zero value. 192 c.sigFPState[l-1] = nil 193 c.sigFPState = c.sigFPState[0 : l-1] 194 } else { 195 // This might happen if sigreturn(2) calls are unbalanced with 196 // respect to signal handler entries. This is not expected so 197 // don't bother to do anything fancy with the floating point 198 // state. 199 log.Warningf("sigreturn unable to restore application fpstate") 200 return 0, linux.SignalStack{}, unix.EFAULT 201 } 202 203 return uc.Sigset, uc.Stack, nil 204 }