diff --git a/Sources/Containerization/LinuxContainer.swift b/Sources/Containerization/LinuxContainer.swift index b8eda640..d572cff2 100644 --- a/Sources/Containerization/LinuxContainer.swift +++ b/Sources/Containerization/LinuxContainer.swift @@ -447,8 +447,8 @@ public final class LinuxContainer: Container, Sendable { "/run/container/\(id)/rootfs" } - private static func guestSocketStagingPath(_ containerID: String, socketID: String) -> String { - "/run/container/\(containerID)/sockets/\(socketID).sock" + private static func guestSocketStagingPath(_ socketID: String) -> String { + "/run/container/sockets/\(socketID).sock" } } @@ -693,7 +693,7 @@ extension LinuxContainer { mounts.append( ContainerizationOCI.Mount( type: "bind", - source: Self.guestSocketStagingPath(self.id, socketID: socket.id), + source: Self.guestSocketStagingPath(socket.id), destination: socket.destination.path, options: ["bind"] )) @@ -1030,7 +1030,7 @@ extension LinuxContainer { let port: UInt32 if socket.direction == .into { port = self.hostVsockPorts.wrappingAdd(1, ordering: .relaxed).oldValue - socket.destination = URL(filePath: Self.guestSocketStagingPath(self.id, socketID: socket.id)) + socket.destination = URL(filePath: Self.guestSocketStagingPath(socket.id)) } else { port = self.guestVsockPorts.wrappingAdd(1, ordering: .relaxed).oldValue socket.source = rootInGuest.appending(path: socket.source.path) diff --git a/Sources/Containerization/LinuxPod.swift b/Sources/Containerization/LinuxPod.swift index 63c96ebc..bb91a76d 100644 --- a/Sources/Containerization/LinuxPod.swift +++ b/Sources/Containerization/LinuxPod.swift @@ -296,8 +296,8 @@ public final class LinuxPod: Sendable { "/run/container/\(containerID)/rootfs" } - private static func guestSocketStagingPath(_ containerID: String, socketID: String) -> String { - "/run/container/\(containerID)/sockets/\(socketID).sock" + private static func guestSocketStagingPath(_ socketID: String) -> String { + "/run/container/sockets/\(socketID).sock" } private static func guestVolumePath(_ volumeName: String) -> String { @@ -659,7 +659,7 @@ extension LinuxPod { mounts.append( ContainerizationOCI.Mount( type: "bind", - source: Self.guestSocketStagingPath(containerID, socketID: socket.id), + source: Self.guestSocketStagingPath(socket.id), destination: socket.destination.path, options: ["bind"] )) @@ -1057,7 +1057,7 @@ extension LinuxPod { let port: UInt32 if socket.direction == .into { port = self.hostVsockPorts.wrappingAdd(1, ordering: .relaxed).oldValue - socket.destination = URL(filePath: Self.guestSocketStagingPath(containerID, socketID: socket.id)) + socket.destination = URL(filePath: Self.guestSocketStagingPath(socket.id)) } else { port = self.guestVsockPorts.wrappingAdd(1, ordering: .relaxed).oldValue socket.source = rootInGuest.appending(path: socket.source.path) diff --git a/Sources/Integration/ContainerTests.swift b/Sources/Integration/ContainerTests.swift index eaf6e50b..404bfb43 100644 --- a/Sources/Integration/ContainerTests.swift +++ b/Sources/Integration/ContainerTests.swift @@ -1121,6 +1121,64 @@ extension IntegrationSuite { } } + // NOTE: Once upon a time our guest agent created any proxied unix sockets at + // a path that contained the container ID in it. The problem here is if the container + // ID is comically long we exceed the max length of a unix domain socket path. + func testUnixSocketIntoGuestLongContainerID() async throws { + let id = "test-unixsocket-long-id-" + String(repeating: "a", count: 40) + + let bs = try await bootstrap(id) + + let hostSocketPath = try createHostUnixSocket() + + let buffer = BufferWriter() + let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in + config.process.arguments = ["sleep", "100"] + config.sockets = [ + UnixSocketConfiguration( + source: URL(filePath: hostSocketPath), + destination: URL(filePath: "/tmp/test.sock"), + direction: .into + ) + ] + config.bootLog = bs.bootLog + } + + do { + try await container.create() + try await container.start() + + let lsExec = try await container.exec("ls-socket") { config in + config.arguments = ["ls", "-l", "/tmp/test.sock"] + config.stdout = buffer + } + + try await lsExec.start() + let status = try await lsExec.wait() + try await lsExec.delete() + + guard status.exitCode == 0 else { + throw IntegrationError.assert(msg: "ls command failed with status \(status)") + } + + guard let output = String(data: buffer.data, encoding: .utf8) else { + throw IntegrationError.assert(msg: "failed to convert ls output to UTF8") + } + + guard output.hasPrefix("s") else { + throw IntegrationError.assert( + msg: "expected socket file (starting with 's'), got: \(output)") + } + + try await container.kill(.kill) + try await container.wait() + try await container.stop() + } catch { + try? await container.stop() + throw error + } + } + func testNonClosureConstructor() async throws { let id = "test-container-non-closure-constructor" diff --git a/Sources/Integration/Suite.swift b/Sources/Integration/Suite.swift index 9eec1248..a0e0ba91 100644 --- a/Sources/Integration/Suite.swift +++ b/Sources/Integration/Suite.swift @@ -313,6 +313,7 @@ struct IntegrationSuite: AsyncParsableCommand { Test("container memory events OOM kill", testMemoryEventsOOMKill), Test("container no serial console", testNoSerialConsole), Test("unix socket into guest", testUnixSocketIntoGuest), + Test("unix socket into guest long container id", testUnixSocketIntoGuestLongContainerID), Test("unix socket into guest symlink", testUnixSocketIntoGuestSymlink), Test("container non-closure constructor", testNonClosureConstructor), Test("container test large stdio ingest", testLargeStdioOutput),