mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
1ebf17e9d9
commit
f282345e8c
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user