summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdin Scannell <ascannell@google.com>2018-10-24 15:51:46 -0700
committerShentubot <shentubot@google.com>2018-10-24 15:52:44 -0700
commite7191f058f550cc3a203a854a1d81f7746c96e53 (patch)
treea733e8897a903917e15f475df59bb6de4e82ab10
parent425dccdd7ed035a671aaf8da1982f7b029365d66 (diff)
Use TRAP to simplify vsyscall emulation.
PiperOrigin-RevId: 218592058 Change-Id: I373a2d813aa6cc362500dd5a894c0b214a1959d7
-rw-r--r--pkg/sentry/platform/ptrace/subprocess.go24
-rw-r--r--pkg/sentry/platform/ptrace/subprocess_linux.go29
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,
},
}