Send error to subprocess in case of invalid shared memory.

Like with known errors that a stub thread can trigger, there are also
known values that we expect in memory shared with stub threads.
We should kill the subprocess in case these are unexpected.

PiperOrigin-RevId: 605344484
This commit is contained in:
Konstantin Bogomolov
2024-02-08 09:46:25 -08:00
committed by gVisor bot
parent 1ebf17e9d9
commit f282345e8c
3 changed files with 19 additions and 6 deletions
+6 -3
View File
@@ -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() {
+5 -3
View File
@@ -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
+8
View File
@@ -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,
}
}