github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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/metacubex/gvisor/pkg/abi/linux"
    23  	"github.com/metacubex/gvisor/pkg/cpuid"
    24  	"github.com/metacubex/gvisor/pkg/hostarch"
    25  	"github.com/metacubex/gvisor/pkg/log"
    26  	"github.com/metacubex/gvisor/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  }