github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/arch/signal_amd64.go (about) 1 // Copyright 2018 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 amd64 16 17 package arch 18 19 import ( 20 "math" 21 22 "golang.org/x/sys/unix" 23 "github.com/SagerNet/gvisor/pkg/abi/linux" 24 "github.com/SagerNet/gvisor/pkg/hostarch" 25 "github.com/SagerNet/gvisor/pkg/log" 26 "github.com/SagerNet/gvisor/pkg/marshal/primitive" 27 "github.com/SagerNet/gvisor/pkg/sentry/arch/fpu" 28 ) 29 30 // SignalContext64 is equivalent to struct sigcontext, the type passed as the 31 // second argument to signal handlers set by signal(2). 32 // 33 // +marshal 34 type SignalContext64 struct { 35 R8 uint64 36 R9 uint64 37 R10 uint64 38 R11 uint64 39 R12 uint64 40 R13 uint64 41 R14 uint64 42 R15 uint64 43 Rdi uint64 44 Rsi uint64 45 Rbp uint64 46 Rbx uint64 47 Rdx uint64 48 Rax uint64 49 Rcx uint64 50 Rsp uint64 51 Rip uint64 52 Eflags uint64 53 Cs uint16 54 Gs uint16 // always 0 on amd64. 55 Fs uint16 // always 0 on amd64. 56 Ss uint16 // only restored if _UC_STRICT_RESTORE_SS (unsupported). 57 Err uint64 58 Trapno uint64 59 Oldmask linux.SignalSet 60 Cr2 uint64 61 // Pointer to a struct _fpstate. See b/33003106#comment8. 62 Fpstate uint64 63 Reserved [8]uint64 64 } 65 66 // Flags for UContext64.Flags. 67 const ( 68 _UC_FP_XSTATE = 1 69 _UC_SIGCONTEXT_SS = 2 70 _UC_STRICT_RESTORE_SS = 4 71 ) 72 73 // UContext64 is equivalent to ucontext_t on 64-bit x86. 74 // 75 // +marshal 76 type UContext64 struct { 77 Flags uint64 78 Link uint64 79 Stack linux.SignalStack 80 MContext SignalContext64 81 Sigset linux.SignalSet 82 } 83 84 // From Linux 'arch/x86/include/uapi/asm/sigcontext.h' the following is the 85 // size of the magic cookie at the end of the xsave frame. 86 // 87 // NOTE(b/33003106#comment11): Currently we don't actually populate the fpstate 88 // on the signal stack. 89 const _FP_XSTATE_MAGIC2_SIZE = 4 90 91 func (c *context64) fpuFrameSize() (size int, useXsave bool) { 92 size = len(c.fpState) 93 if size > 512 { 94 // Make room for the magic cookie at the end of the xsave frame. 95 size += _FP_XSTATE_MAGIC2_SIZE 96 useXsave = true 97 } 98 return size, useXsave 99 } 100 101 // SignalSetup implements Context.SignalSetup. (Compare to Linux's 102 // arch/x86/kernel/signal.c:__setup_rt_frame().) 103 func (c *context64) SignalSetup(st *Stack, act *linux.SigAction, info *linux.SignalInfo, alt *linux.SignalStack, sigset linux.SignalSet) error { 104 sp := st.Bottom 105 106 // "The 128-byte area beyond the location pointed to by %rsp is considered 107 // to be reserved and shall not be modified by signal or interrupt 108 // handlers. ... leaf functions may use this area for their entire stack 109 // frame, rather than adjusting the stack pointer in the prologue and 110 // epilogue." - AMD64 ABI 111 // 112 // (But this doesn't apply if we're starting at the top of the signal 113 // stack, in which case there is no following stack frame.) 114 if !(alt.IsEnabled() && sp == alt.Top()) { 115 sp -= 128 116 } 117 118 // Allocate space for floating point state on the stack. 119 // 120 // This isn't strictly necessary because we don't actually populate 121 // the fpstate. However we do store the floating point state of the 122 // interrupted thread inside the sentry. Simply accounting for this 123 // space on the user stack naturally caps the amount of memory the 124 // sentry will allocate for this purpose. 125 fpSize, _ := c.fpuFrameSize() 126 sp = (sp - hostarch.Addr(fpSize)) & ^hostarch.Addr(63) 127 128 // Construct the UContext64 now since we need its size. 129 uc := &UContext64{ 130 // No _UC_FP_XSTATE: see Fpstate above. 131 // No _UC_STRICT_RESTORE_SS: we don't allow SS changes. 132 Flags: _UC_SIGCONTEXT_SS, 133 Stack: *alt, 134 MContext: SignalContext64{ 135 R8: c.Regs.R8, 136 R9: c.Regs.R9, 137 R10: c.Regs.R10, 138 R11: c.Regs.R11, 139 R12: c.Regs.R12, 140 R13: c.Regs.R13, 141 R14: c.Regs.R14, 142 R15: c.Regs.R15, 143 Rdi: c.Regs.Rdi, 144 Rsi: c.Regs.Rsi, 145 Rbp: c.Regs.Rbp, 146 Rbx: c.Regs.Rbx, 147 Rdx: c.Regs.Rdx, 148 Rax: c.Regs.Rax, 149 Rcx: c.Regs.Rcx, 150 Rsp: c.Regs.Rsp, 151 Rip: c.Regs.Rip, 152 Eflags: c.Regs.Eflags, 153 Cs: uint16(c.Regs.Cs), 154 Ss: uint16(c.Regs.Ss), 155 Oldmask: sigset, 156 }, 157 Sigset: sigset, 158 } 159 160 // TODO(github.com/SagerNet/issue/159): Set SignalContext64.Err, Trapno, and Cr2 161 // based on the fault that caused the signal. For now, leave Err and 162 // Trapno unset and assume CR2 == info.Addr() for SIGSEGVs and 163 // SIGBUSes. 164 if linux.Signal(info.Signo) == linux.SIGSEGV || linux.Signal(info.Signo) == linux.SIGBUS { 165 uc.MContext.Cr2 = info.Addr() 166 } 167 168 // "... the value (%rsp+8) is always a multiple of 16 (...) when 169 // control is transferred to the function entry point." - AMD64 ABI 170 ucSize := uc.SizeBytes() 171 // st.Arch.Width() is for the restorer address. sizeof(siginfo) == 128. 172 frameSize := int(st.Arch.Width()) + ucSize + 128 173 frameBottom := (sp-hostarch.Addr(frameSize)) & ^hostarch.Addr(15) - 8 174 sp = frameBottom + hostarch.Addr(frameSize) 175 st.Bottom = sp 176 177 // Prior to proceeding, figure out if the frame will exhaust the range 178 // for the signal stack. This is not allowed, and should immediately 179 // force signal delivery (reverting to the default handler). 180 if act.Flags&linux.SA_ONSTACK != 0 && alt.IsEnabled() && !alt.Contains(frameBottom) { 181 return unix.EFAULT 182 } 183 184 // Adjust the code. 185 info.FixSignalCodeForUser() 186 187 // Set up the stack frame. 188 if _, err := info.CopyOut(st, StackBottomMagic); err != nil { 189 return err 190 } 191 infoAddr := st.Bottom 192 if _, err := uc.CopyOut(st, StackBottomMagic); err != nil { 193 return err 194 } 195 ucAddr := st.Bottom 196 if act.Flags&linux.SA_RESTORER != 0 { 197 // Push the restorer return address. 198 // Note that this doesn't need to be popped. 199 if _, err := primitive.CopyUint64Out(st, StackBottomMagic, act.Restorer); err != nil { 200 return err 201 } 202 } else { 203 // amd64 requires a restorer. 204 return unix.EFAULT 205 } 206 207 // Set up registers. 208 c.Regs.Rip = act.Handler 209 c.Regs.Rsp = uint64(st.Bottom) 210 c.Regs.Rdi = uint64(info.Signo) 211 c.Regs.Rsi = uint64(infoAddr) 212 c.Regs.Rdx = uint64(ucAddr) 213 c.Regs.Rax = 0 214 c.Regs.Ds = userDS 215 c.Regs.Es = userDS 216 c.Regs.Cs = userCS 217 c.Regs.Ss = userDS 218 219 // Save the thread's floating point state. 220 c.sigFPState = append(c.sigFPState, c.fpState) 221 222 // Signal handler gets a clean floating point state. 223 c.fpState = fpu.NewState() 224 225 return nil 226 } 227 228 // SignalRestore implements Context.SignalRestore. (Compare to Linux's 229 // arch/x86/kernel/signal.c:sys_rt_sigreturn().) 230 func (c *context64) SignalRestore(st *Stack, rt bool) (linux.SignalSet, linux.SignalStack, error) { 231 // Copy out the stack frame. 232 var uc UContext64 233 if _, err := uc.CopyIn(st, StackBottomMagic); err != nil { 234 return 0, linux.SignalStack{}, err 235 } 236 var info linux.SignalInfo 237 if _, err := info.CopyIn(st, StackBottomMagic); err != nil { 238 return 0, linux.SignalStack{}, err 239 } 240 241 // Restore registers. 242 c.Regs.R8 = uc.MContext.R8 243 c.Regs.R9 = uc.MContext.R9 244 c.Regs.R10 = uc.MContext.R10 245 c.Regs.R11 = uc.MContext.R11 246 c.Regs.R12 = uc.MContext.R12 247 c.Regs.R13 = uc.MContext.R13 248 c.Regs.R14 = uc.MContext.R14 249 c.Regs.R15 = uc.MContext.R15 250 c.Regs.Rdi = uc.MContext.Rdi 251 c.Regs.Rsi = uc.MContext.Rsi 252 c.Regs.Rbp = uc.MContext.Rbp 253 c.Regs.Rbx = uc.MContext.Rbx 254 c.Regs.Rdx = uc.MContext.Rdx 255 c.Regs.Rax = uc.MContext.Rax 256 c.Regs.Rcx = uc.MContext.Rcx 257 c.Regs.Rsp = uc.MContext.Rsp 258 c.Regs.Rip = uc.MContext.Rip 259 c.Regs.Eflags = (c.Regs.Eflags & ^eflagsRestorable) | (uc.MContext.Eflags & eflagsRestorable) 260 c.Regs.Cs = uint64(uc.MContext.Cs) | 3 261 // N.B. _UC_STRICT_RESTORE_SS not supported. 262 c.Regs.Orig_rax = math.MaxUint64 263 264 // Restore floating point state. 265 l := len(c.sigFPState) 266 if l > 0 { 267 c.fpState = c.sigFPState[l-1] 268 // NOTE(cl/133042258): State save requires that any slice 269 // elements from '[len:cap]' to be zero value. 270 c.sigFPState[l-1] = nil 271 c.sigFPState = c.sigFPState[0 : l-1] 272 } else { 273 // This might happen if sigreturn(2) calls are unbalanced with 274 // respect to signal handler entries. This is not expected so 275 // don't bother to do anything fancy with the floating point 276 // state. 277 log.Infof("sigreturn unable to restore application fpstate") 278 } 279 280 return uc.Sigset, uc.Stack, nil 281 }