diff --git a/pkg/sentry/platform/kvm/machine.go b/pkg/sentry/platform/kvm/machine.go index f1f7e4ea4..14c546081 100644 --- a/pkg/sentry/platform/kvm/machine.go +++ b/pkg/sentry/platform/kvm/machine.go @@ -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)) diff --git a/pkg/sentry/platform/kvm/machine_unsafe.go b/pkg/sentry/platform/kvm/machine_unsafe.go index cf3a4e7c9..5c5b78a84 100644 --- a/pkg/sentry/platform/kvm/machine_unsafe.go +++ b/pkg/sentry/platform/kvm/machine_unsafe.go @@ -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) }