mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user