ControlSocket: duplicate VirtIO socket connection's file descriptor (#1333)

This commit is contained in:
edi-oai
2026-09-16 11:37:56 +01:00
committed by GitHub
parent 9bb2af2434
commit acaf3ca7ef
+21 -1
View File
@@ -1,4 +1,7 @@
import Foundation
import Darwin
import System
import Virtualization
import Network
import os.log
import NIO
@@ -72,7 +75,13 @@ class ControlSocket {
self.logger.info("running control socket proxy")
let vmChannel = try await ClientBootstrap(group: eventLoopGroup).withConnectedSocket(vmConnection.fileDescriptor) { childChannel in
// Duplicate the connection's file descriptor
//
// This way VZVirtioSocketConnection and NIO won't race to close the same descriptor,
// which may result in "tart run" crashing because of NIO's fatal assertion on EBADF.
let vmSocket = try duplicateAndCloseConnection(vmConnection)
let vmChannel = try await ClientBootstrap(group: eventLoopGroup).withConnectedSocket(vmSocket) { childChannel in
childChannel.eventLoop.makeCompletedFuture {
try NIOAsyncChannel<ByteBuffer, ByteBuffer>(
wrappingChannelSynchronously: childChannel
@@ -104,4 +113,15 @@ class ControlSocket {
}
}
}
private func duplicateAndCloseConnection(_ connection: VZVirtioSocketConnection) throws -> CInt {
defer { connection.close() }
let fd = fcntl(connection.fileDescriptor, F_DUPFD_CLOEXEC, 0)
guard fd >= 0 else {
throw Errno(rawValue: errno)
}
return fd
}
}