diff options
-rw-r--r-- | pkg/sentry/platform/ptrace/subprocess.go | 24 | ||||
-rw-r--r-- | pkg/sentry/platform/ptrace/subprocess_linux.go | 29 |
2 files changed, 35 insertions, 18 deletions
diff --git a/pkg/sentry/platform/ptrace/subprocess.go b/pkg/sentry/platform/ptrace/subprocess.go index 6a9da5db8..2cd49d1ec 100644 --- a/pkg/sentry/platform/ptrace/subprocess.go +++ b/pkg/sentry/platform/ptrace/subprocess.go @@ -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 } } } diff --git a/pkg/sentry/platform/ptrace/subprocess_linux.go b/pkg/sentry/platform/ptrace/subprocess_linux.go index 73ddc559b..885ba4b2e 100644 --- a/pkg/sentry/platform/ptrace/subprocess_linux.go +++ b/pkg/sentry/platform/ptrace/subprocess_linux.go @@ -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, }, } |