kvm: fix a race condition between seccompMMapHandler and machine.Destroy

A machine file descriptor has to be closed only when we are sure that
it isn't used by seccompMMapHandler.

PiperOrigin-RevId: 424207803
This commit is contained in:
Andrei Vagin
2022-01-25 16:30:44 -08:00
committed by gVisor bot
parent edb6bd399e
commit 18dca1bf99
2 changed files with 26 additions and 4 deletions
+3 -4
View File
@@ -369,10 +369,6 @@ func (m *machine) mapPhysical(physical, length uintptr, phyRegions []physicalReg
func (m *machine) Destroy() {
runtime.SetFinalizer(m, nil)
machinePoolMu.Lock()
machinePool[m.machinePoolIndex].Store(nil)
machinePoolMu.Unlock()
// Destroy vCPUs.
for _, c := range m.vCPUsByID {
if c == nil {
@@ -396,6 +392,9 @@ func (m *machine) Destroy() {
}
}
machinePool[m.machinePoolIndex].Store(nil)
seccompMmapSync()
// vCPUs are gone: teardown machine state.
if err := unix.Close(m.fd); err != nil {
panic(fmt.Sprintf("error closing VM fd: %v", err))
+23
View File
@@ -24,6 +24,7 @@ package kvm
import (
"fmt"
"math"
"runtime"
"sync/atomic"
"unsafe"
@@ -172,6 +173,26 @@ func (c *vCPU) setSignalMask() error {
return nil
}
// seccompMmapHandlerCnt is a number of currently running seccompMmapHandler
// instances.
var seccompMmapHandlerCnt int64
// seccompMmapSync waits for all currently runnuing seccompMmapHandler
// instances.
//
// The standard locking primitives can't be used in this case since
// seccompMmapHandler is executed in a signal handler context.
//
// It can be implemented by using FUTEX calls, but it will require to call
// FUTEX_WAKE from seccompMmapHandler. Consider machine.Destroy is called only
// once, and the probability is racing with seccompMmapHandler is very low the
// spinlock-like way looks more reasonable.
func seccompMmapSync() {
for atomic.LoadInt64(&seccompMmapHandlerCnt) != 0 {
runtime.Gosched()
}
}
// seccompMmapHandler is a signal handler for runtime mmap system calls
// that are trapped by seccomp.
//
@@ -185,6 +206,7 @@ func seccompMmapHandler(context unsafe.Pointer) {
return
}
atomic.AddInt64(&seccompMmapHandlerCnt, 1)
for i := uint32(0); i < atomic.LoadUint32(&machinePoolLen); i++ {
m := machinePool[i].Load()
if m == nil {
@@ -213,4 +235,5 @@ func seccompMmapHandler(context unsafe.Pointer) {
virtual += length
}
}
atomic.AddInt64(&seccompMmapHandlerCnt, -1)
}