mirror of
https://github.com/apple/container.git
synced 2026-09-11 02:05:45 +00:00
vminitd: Wait for execvpe to return to continue (#275)
Today, because we don't wait for execvpe to finish to continue onwards, it's possible that if you did an exec quick enough after starting an init process for a container, that you could join the init processes namespaces before pivot_root has taken place which is quite fun. Let's wait for exec to finish (or an error to occur) to prevent this.
This commit is contained in:
@@ -101,7 +101,6 @@ struct ExecCommand: ParsableCommand {
|
||||
|
||||
let data = Data(bytes: &masterFD, count: MemoryLayout.size(ofValue: masterFD))
|
||||
try syncPipe.write(contentsOf: data)
|
||||
try syncPipe.close()
|
||||
|
||||
// Wait for the grandparent to tell us that they acked our console.
|
||||
guard let data = try ackPipe.read(upToCount: App.ackConsole.count) else {
|
||||
|
||||
@@ -91,7 +91,6 @@ struct RunCommand: ParsableCommand {
|
||||
|
||||
let data = Data(bytes: &masterFD, count: MemoryLayout.size(ofValue: masterFD))
|
||||
try syncPipe.write(contentsOf: data)
|
||||
try syncPipe.close()
|
||||
|
||||
// Wait for the grandparent to tell us that they acked our console.
|
||||
guard let data = try ackPipe.read(upToCount: App.ackConsole.count) else {
|
||||
|
||||
@@ -30,8 +30,8 @@ final class ManagedProcess: Sendable {
|
||||
private let process: Command
|
||||
private let state: Mutex<State>
|
||||
private let owningPid: Int32?
|
||||
private let ackPipe: FileHandle
|
||||
private let syncPipe: FileHandle
|
||||
private let ackPipe: Pipe
|
||||
private let syncPipe: Pipe
|
||||
private let terminal: Bool
|
||||
private let bundle: ContainerizationOCI.Bundle
|
||||
private let cgroupManager: Cgroup2Manager?
|
||||
@@ -87,11 +87,11 @@ final class ManagedProcess: Sendable {
|
||||
|
||||
let syncPipe = Pipe()
|
||||
try syncPipe.setCloexec()
|
||||
self.syncPipe = syncPipe.fileHandleForReading
|
||||
self.syncPipe = syncPipe
|
||||
|
||||
let ackPipe = Pipe()
|
||||
try ackPipe.setCloexec()
|
||||
self.ackPipe = ackPipe.fileHandleForWriting
|
||||
self.ackPipe = ackPipe
|
||||
|
||||
let args: [String]
|
||||
if let owningPid {
|
||||
@@ -157,15 +157,19 @@ extension ManagedProcess {
|
||||
// Start the underlying process.
|
||||
try process.start()
|
||||
defer {
|
||||
try? self.ackPipe.close()
|
||||
try? self.syncPipe.close()
|
||||
try? self.ackPipe.fileHandleForWriting.close()
|
||||
try? self.syncPipe.fileHandleForReading.close()
|
||||
try? self.ackPipe.fileHandleForReading.close()
|
||||
try? self.syncPipe.fileHandleForWriting.close()
|
||||
}
|
||||
|
||||
// Close our side of any pipes.
|
||||
try $0.io.closeAfterExec()
|
||||
try self.ackPipe.fileHandleForReading.close()
|
||||
try self.syncPipe.fileHandleForWriting.close()
|
||||
|
||||
let size = MemoryLayout<Int32>.size
|
||||
guard let piddata = try syncPipe.read(upToCount: size) else {
|
||||
guard let piddata = try syncPipe.fileHandleForReading.read(upToCount: size) else {
|
||||
throw ContainerizationError(.internalError, message: "no pid data from sync pipe")
|
||||
}
|
||||
|
||||
@@ -201,7 +205,7 @@ extension ManagedProcess {
|
||||
metadata: [
|
||||
"pid": "\(pid)"
|
||||
])
|
||||
try self.ackPipe.write(contentsOf: Self.ackPid.data(using: .utf8)!)
|
||||
try self.ackPipe.fileHandleForWriting.write(contentsOf: Self.ackPid.data(using: .utf8)!)
|
||||
|
||||
if self.terminal {
|
||||
log.info(
|
||||
@@ -211,7 +215,7 @@ extension ManagedProcess {
|
||||
])
|
||||
|
||||
// Wait for a new write that will contain the pty fd if we asked for one.
|
||||
guard let ptyFd = try syncPipe.read(upToCount: size) else {
|
||||
guard let ptyFd = try self.syncPipe.fileHandleForReading.read(upToCount: size) else {
|
||||
throw ContainerizationError(
|
||||
.internalError,
|
||||
message: "no pty data from sync pipe"
|
||||
@@ -227,9 +231,12 @@ extension ManagedProcess {
|
||||
])
|
||||
|
||||
try $0.io.attach(pid: pid, fd: fd)
|
||||
try self.ackPipe.write(contentsOf: Self.ackConsole.data(using: .utf8)!)
|
||||
try self.ackPipe.fileHandleForWriting.write(contentsOf: Self.ackConsole.data(using: .utf8)!)
|
||||
}
|
||||
|
||||
// Wait for the syncPipe to close (after exec).
|
||||
_ = try self.syncPipe.fileHandleForReading.readToEnd()
|
||||
|
||||
log.info(
|
||||
"started managed process",
|
||||
metadata: [
|
||||
|
||||
Reference in New Issue
Block a user