From 619354ef74f35d94d7d964514cce75c8d31e48f9 Mon Sep 17 00:00:00 2001 From: Danny Canter Date: Thu, 6 Nov 2025 15:48:02 -0800 Subject: [PATCH] Don't ignore possible errors from dup(2) (#382) Everytime we grab a vsock connection we dup the conn and close the original, otherwise we'd need to carry around the vsock connection type everywhere as it closes the fd in its destructor. We weren't checking the return value of dup however, so if it did fail we'd have a useless filehandle with an fd of -1. --- .../VZVirtualMachine+Helpers.swift | 5 +- .../VZVirtualMachineInstance.swift | 48 ++++++++++++++----- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Sources/Containerization/VZVirtualMachine+Helpers.swift b/Sources/Containerization/VZVirtualMachine+Helpers.swift index 135ca019..a3bbfed7 100644 --- a/Sources/Containerization/VZVirtualMachine+Helpers.swift +++ b/Sources/Containerization/VZVirtualMachine+Helpers.swift @@ -139,8 +139,11 @@ extension VZVirtualMachine { } extension VZVirtioSocketConnection { - func dupHandle() -> FileHandle { + func dupHandle() throws -> FileHandle { let fd = dup(self.fileDescriptor) + if fd == -1 { + throw POSIXError.fromErrno() + } self.close() return FileHandle(fileDescriptor: fd, closeOnDealloc: false) } diff --git a/Sources/Containerization/VZVirtualMachineInstance.swift b/Sources/Containerization/VZVirtualMachineInstance.swift index 035009e8..a4364c4f 100644 --- a/Sources/Containerization/VZVirtualMachineInstance.swift +++ b/Sources/Containerization/VZVirtualMachineInstance.swift @@ -195,25 +195,47 @@ extension VZVirtualMachineInstance: VirtualMachineInstance { public func dialAgent() async throws -> Vminitd { try await lock.withLock { connections in - let handle = try await vm.connect( - queue: queue, - port: Vminitd.port - ).dupHandle() + do { + let conn = try await vm.connect( + queue: queue, + port: Vminitd.port + ) + let handle = try conn.dupHandle() + let agent = Vminitd(connection: handle, group: self.group) + connections.agents.append(agent) - let agent = Vminitd(connection: handle, group: self.group) - connections.agents.append(agent) - - return agent + return agent + } catch { + if let err = error as? ContainerizationError { + throw err + } + throw ContainerizationError( + .internalError, + message: "failed to dial agent", + cause: error + ) + } } } func dial(_ port: UInt32) async throws -> FileHandle { try await lock.withLock { connections in - let handle = try await vm.connect( - queue: queue, - port: port - ).dupHandle() - return handle + do { + let conn = try await vm.connect( + queue: queue, + port: port + ) + return try conn.dupHandle() + } catch { + if let err = error as? ContainerizationError { + throw err + } + throw ContainerizationError( + .internalError, + message: "failed to dial vsock port", + cause: error + ) + } } }