diff --git a/pkg/sentry/platform/systrap/context_queue.go b/pkg/sentry/platform/systrap/context_queue.go index a309cd6d6..245c4ef92 100644 --- a/pkg/sentry/platform/systrap/context_queue.go +++ b/pkg/sentry/platform/systrap/context_queue.go @@ -16,6 +16,8 @@ package systrap import ( "sync/atomic" + + "gvisor.dev/gvisor/pkg/sentry/platform" ) // LINT.IfChange @@ -97,7 +99,7 @@ func (q *contextQueue) queuedContexts() uint32 { // add puts the the given ctx onto the context queue, and records a state of // the subprocess after insertion to see if there are more active stub threads // or more waiting contexts. -func (q *contextQueue) add(ctx *sharedContext) { +func (q *contextQueue) add(ctx *sharedContext) *platform.ContextError { ctx.startWaitingTS = cputicks() if fastpath.stubFastPath() { @@ -110,8 +112,8 @@ func (q *contextQueue) add(ctx *sharedContext) { next := atomic.AddUint32(&q.end, 1) if (next % maxContextQueueEntries) == (atomic.LoadUint32(&q.start) % maxContextQueueEntries) { - // should be unreachable - panic("contextQueue is full") + // reachable only in case of corrupted memory + return corruptedSharedMemoryErr("context queue is full, indicates tampering with queue counters") } idx := next - 1 next = idx % maxContextQueueEntries @@ -121,6 +123,7 @@ func (q *contextQueue) add(ctx *sharedContext) { if atomic.SwapUint32(&q.usedFastPath, 0) != 0 { fastpath.usedStubFastPath.Store(true) } + return nil } func (q *contextQueue) disableFastPath() { diff --git a/pkg/sentry/platform/systrap/subprocess.go b/pkg/sentry/platform/systrap/subprocess.go index 7407f6b92..226a56714 100644 --- a/pkg/sentry/platform/systrap/subprocess.go +++ b/pkg/sentry/platform/systrap/subprocess.go @@ -745,7 +745,9 @@ func (s *subprocess) switchToApp(c *context, ac *arch.Context64) (isSyscall bool s.incAwakeContexts() } ctx.setState(sysmsg.ContextStateNone) - s.contextQueue.add(ctx) + if err := s.contextQueue.add(ctx); err != nil { + return false, false, err + } s.waitOnState(ctx) // Check if there's been an error. @@ -754,7 +756,7 @@ func (s *subprocess) switchToApp(c *context, ac *arch.Context64) (isSyscall bool if sysThread, ok := s.sysmsgThreads[threadID]; ok && sysThread.msg.Err != 0 { return false, false, sysThread.msg.ConvertSysmsgErr() } - log.Warningf("systrap: found unexpected ThreadContext.ThreadID field, expected %d found %d", invalidThreadID, threadID) + return false, false, corruptedSharedMemoryErr(fmt.Sprintf("found unexpected ThreadContext.ThreadID field, expected %d found %d", invalidThreadID, threadID)) } // Copy register state locally. @@ -778,7 +780,7 @@ func (s *subprocess) switchToApp(c *context, ac *arch.Context64) (isSyscall bool updateSyscallRegs(regs) return true, shouldPatchSyscall, nil } else if ctxState != sysmsg.ContextStateFault { - panic(fmt.Sprintf("unknown context state: %v", ctxState)) + return false, false, corruptedSharedMemoryErr(fmt.Sprintf("unknown context state: %v", ctxState)) } return false, false, nil diff --git a/pkg/sentry/platform/systrap/systrap.go b/pkg/sentry/platform/systrap/systrap.go index e5869845c..e64a88ad2 100644 --- a/pkg/sentry/platform/systrap/systrap.go +++ b/pkg/sentry/platform/systrap/systrap.go @@ -53,6 +53,7 @@ import ( "os" "sync" + "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" pkgcontext "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/hostarch" @@ -423,3 +424,10 @@ func createMemoryFile() (*pgalloc.MemoryFile, error) { } return mf, nil } + +func corruptedSharedMemoryErr(additional string) *platform.ContextError { + return &platform.ContextError{ + Err: fmt.Errorf("systrap corrupted memory: %s", additional), + Errno: unix.EPERM, + } +}