github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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 // +build arm64 16 17 package arch 18 19 import ( 20 "golang.org/x/sys/unix" 21 "github.com/SagerNet/gvisor/pkg/abi/linux" 22 "github.com/SagerNet/gvisor/pkg/hostarch" 23 "github.com/SagerNet/gvisor/pkg/log" 24 "github.com/SagerNet/gvisor/pkg/sentry/arch/fpu" 25 ) 26 27 // SignalContext64 is equivalent to struct sigcontext, the type passed as the 28 // second argument to signal handlers set by signal(2). 29 // 30 // +marshal 31 type SignalContext64 struct { 32 FaultAddr uint64 33 Regs [31]uint64 34 Sp uint64 35 Pc uint64 36 Pstate uint64 37 _pad [8]byte // __attribute__((__aligned__(16))) 38 Fpsimd64 FpsimdContext // size = 528 39 } 40 41 // +marshal 42 type aarch64Ctx struct { 43 Magic uint32 44 Size uint32 45 } 46 47 // FpsimdContext is equivalent to struct fpsimd_context on arm64 48 // (arch/arm64/include/uapi/asm/sigcontext.h). 49 // 50 // +marshal 51 type FpsimdContext struct { 52 Head aarch64Ctx 53 Fpsr uint32 54 Fpcr uint32 55 Vregs [64]uint64 // actually [32]uint128 56 } 57 58 // UContext64 is equivalent to ucontext on arm64(arch/arm64/include/uapi/asm/ucontext.h). 59 // 60 // +marshal 61 type UContext64 struct { 62 Flags uint64 63 Link uint64 64 Stack linux.SignalStack 65 Sigset linux.SignalSet 66 // glibc uses a 1024-bit sigset_t 67 _pad [120]byte // (1024 - 64) / 8 = 120 68 // sigcontext must be aligned to 16-byte 69 _pad2 [8]byte 70 // last for future expansion 71 MContext SignalContext64 72 } 73 74 // SignalSetup implements Context.SignalSetup. 75 func (c *context64) SignalSetup(st *Stack, act *linux.SigAction, info *linux.SignalInfo, alt *linux.SignalStack, sigset linux.SignalSet) error { 76 sp := st.Bottom 77 78 // Construct the UContext64 now since we need its size. 79 uc := &UContext64{ 80 Flags: 0, 81 Stack: *alt, 82 MContext: SignalContext64{ 83 Regs: c.Regs.Regs, 84 Sp: c.Regs.Sp, 85 Pc: c.Regs.Pc, 86 Pstate: c.Regs.Pstate, 87 }, 88 Sigset: sigset, 89 } 90 if linux.Signal(info.Signo) == linux.SIGSEGV || linux.Signal(info.Signo) == linux.SIGBUS { 91 uc.MContext.FaultAddr = info.Addr() 92 } 93 94 ucSize := uc.SizeBytes() 95 96 // frameSize = ucSize + sizeof(siginfo). 97 // sizeof(siginfo) == 128. 98 // R30 stores the restorer address. 99 frameSize := ucSize + 128 100 frameBottom := (sp - hostarch.Addr(frameSize)) & ^hostarch.Addr(15) 101 sp = frameBottom + hostarch.Addr(frameSize) 102 st.Bottom = sp 103 104 // Prior to proceeding, figure out if the frame will exhaust the range 105 // for the signal stack. This is not allowed, and should immediately 106 // force signal delivery (reverting to the default handler). 107 if act.Flags&linux.SA_ONSTACK != 0 && alt.IsEnabled() && !alt.Contains(frameBottom) { 108 return unix.EFAULT 109 } 110 111 // Adjust the code. 112 info.FixSignalCodeForUser() 113 114 // Set up the stack frame. 115 if _, err := info.CopyOut(st, StackBottomMagic); err != nil { 116 return err 117 } 118 infoAddr := st.Bottom 119 if _, err := uc.CopyOut(st, StackBottomMagic); err != nil { 120 return err 121 } 122 ucAddr := st.Bottom 123 124 // Set up registers. 125 c.Regs.Sp = uint64(st.Bottom) 126 c.Regs.Pc = act.Handler 127 c.Regs.Regs[0] = uint64(info.Signo) 128 c.Regs.Regs[1] = uint64(infoAddr) 129 c.Regs.Regs[2] = uint64(ucAddr) 130 c.Regs.Regs[30] = act.Restorer 131 132 // Save the thread's floating point state. 133 c.sigFPState = append(c.sigFPState, c.fpState) 134 // Signal handler gets a clean floating point state. 135 c.fpState = fpu.NewState() 136 return nil 137 } 138 139 // SignalRestore implements Context.SignalRestore. 140 func (c *context64) SignalRestore(st *Stack, rt bool) (linux.SignalSet, linux.SignalStack, error) { 141 // Copy out the stack frame. 142 var uc UContext64 143 if _, err := uc.CopyIn(st, StackBottomMagic); err != nil { 144 return 0, linux.SignalStack{}, err 145 } 146 var info linux.SignalInfo 147 if _, err := info.CopyIn(st, StackBottomMagic); err != nil { 148 return 0, linux.SignalStack{}, err 149 } 150 151 // Restore registers. 152 c.Regs.Regs = uc.MContext.Regs 153 c.Regs.Pc = uc.MContext.Pc 154 c.Regs.Sp = uc.MContext.Sp 155 c.Regs.Pstate = uc.MContext.Pstate 156 157 // Restore floating point state. 158 l := len(c.sigFPState) 159 if l > 0 { 160 c.fpState = c.sigFPState[l-1] 161 // NOTE(cl/133042258): State save requires that any slice 162 // elements from '[len:cap]' to be zero value. 163 c.sigFPState[l-1] = nil 164 c.sigFPState = c.sigFPState[0 : l-1] 165 } else { 166 // This might happen if sigreturn(2) calls are unbalanced with 167 // respect to signal handler entries. This is not expected so 168 // don't bother to do anything fancy with the floating point 169 // state. 170 log.Warningf("sigreturn unable to restore application fpstate") 171 } 172 173 return uc.Sigset, uc.Stack, nil 174 }