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  }