mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Use TRAP to simplify vsyscall emulation.
PiperOrigin-RevId: 218592058 Change-Id: I373a2d813aa6cc362500dd5a894c0b214a1959d7
This commit is contained in:
@@ -357,15 +357,13 @@ func (t *thread) destroy() {
|
||||
|
||||
// init initializes trace options.
|
||||
func (t *thread) init() {
|
||||
// Set our TRACESYSGOOD option to differeniate real SIGTRAP. Also, we
|
||||
// require the SECCOMP option to ensure that seccomp violations
|
||||
// generate a ptrace event.
|
||||
// Set our TRACESYSGOOD option to differeniate real SIGTRAP.
|
||||
_, _, errno := syscall.RawSyscall6(
|
||||
syscall.SYS_PTRACE,
|
||||
syscall.PTRACE_SETOPTIONS,
|
||||
uintptr(t.tid),
|
||||
0,
|
||||
syscall.PTRACE_O_TRACESYSGOOD|_PTRACE_O_TRACESECCOMP,
|
||||
syscall.PTRACE_O_TRACESYSGOOD,
|
||||
0, 0)
|
||||
if errno != 0 {
|
||||
panic(fmt.Sprintf("ptrace set options failed: %v", errno))
|
||||
@@ -522,12 +520,6 @@ func (s *subprocess) switchToApp(c *context, ac arch.Context) bool {
|
||||
// Ensure registers are sane.
|
||||
updateSyscallRegs(regs)
|
||||
return true
|
||||
} else if sig == (seccompEvent | syscall.SIGTRAP) {
|
||||
// Seccomp is enabled, and caught the system call. This
|
||||
// is an emulated vsyscall call, since those are caught
|
||||
// only by seccomp and explicitly set to trace.
|
||||
updateSyscallRegs(regs)
|
||||
return true
|
||||
} else if sig == syscall.SIGSTOP {
|
||||
// SIGSTOP was delivered to another thread in the same thread
|
||||
// group, which initiated another group stop. Just ignore it.
|
||||
@@ -544,9 +536,17 @@ func (s *subprocess) switchToApp(c *context, ac arch.Context) bool {
|
||||
// either delivered from the kernel or from this process. We
|
||||
// don't respect other signals.
|
||||
if c.signalInfo.Code > 0 {
|
||||
return false // kernel.
|
||||
// The signal was generated by the kernel. We inspect
|
||||
// the signal information, and may patch it in order to
|
||||
// faciliate vsyscall emulation. See patchSignalInfo.
|
||||
patchSignalInfo(regs, &c.signalInfo)
|
||||
return false
|
||||
} else if c.signalInfo.Code <= 0 && c.signalInfo.Pid() == int32(os.Getpid()) {
|
||||
return false // this process.
|
||||
// The signal was generated by this process. That means
|
||||
// that it was an interrupt or something else that we
|
||||
// should bail for. Note that we ignore signals
|
||||
// generated by other processes.
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,7 @@ import (
|
||||
"gvisor.googlesource.com/gvisor/pkg/sentry/platform/procid"
|
||||
)
|
||||
|
||||
const (
|
||||
syscallEvent syscall.Signal = 0x80
|
||||
seccompEvent syscall.Signal = 0x700 // 0x7 (PTRACE_SECCOMP_EVENT) << 8
|
||||
_PTRACE_O_TRACESECCOMP = 0x80 // 1 << 0x7 (PTRACE_SECCOMP_EVENT)
|
||||
)
|
||||
const syscallEvent syscall.Signal = 0x80
|
||||
|
||||
// probeSeccomp returns true iff seccomp is run after ptrace notifications,
|
||||
// which is generally the case for kernel version >= 4.8. This check is dynamic
|
||||
@@ -81,6 +77,27 @@ func probeSeccomp() bool {
|
||||
}
|
||||
}
|
||||
|
||||
// patchSignalInfo patches the signal info to account for hitting the seccomp
|
||||
// filters from vsyscall emulation, specified below. We allow for SIGSYS as a
|
||||
// synchronous trap, but patch the structure to appear like a SIGSEGV with the
|
||||
// Rip as the faulting address.
|
||||
//
|
||||
// Note that this should only be called after verifying that the signalInfo has
|
||||
// been generated by the kernel.
|
||||
func patchSignalInfo(regs *syscall.PtraceRegs, signalInfo *arch.SignalInfo) {
|
||||
if linux.Signal(signalInfo.Signo) == linux.SIGSYS {
|
||||
signalInfo.Signo = int32(linux.SIGSEGV)
|
||||
|
||||
// Unwind the kernel emulation, if any has occurred. A SIGSYS is delivered
|
||||
// with the si_call_addr field pointing to the current RIP. This field
|
||||
// aligns with the si_addr field for a SIGSEGV, so we don't need to touch
|
||||
// anything there. We do need to unwind emulation however, so we set the
|
||||
// instruction pointer to the faulting value, and "unpop" the stack.
|
||||
regs.Rip = signalInfo.Addr()
|
||||
regs.Rsp -= 8
|
||||
}
|
||||
}
|
||||
|
||||
// createStub creates a fresh stub processes.
|
||||
//
|
||||
// Precondition: the runtime OS thread must be locked.
|
||||
@@ -131,7 +148,7 @@ func attachedThread(flags uintptr, defaultAction uint32) (*thread, error) {
|
||||
syscall.SYS_TIME: {},
|
||||
309: {}, // SYS_GETCPU.
|
||||
},
|
||||
Action: uint32(linux.SECCOMP_RET_TRACE),
|
||||
Action: uint32(linux.SECCOMP_RET_TRAP),
|
||||
Vsyscall: true,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user