mirror of
https://github.com/apple/container.git
synced 2026-09-26 01:25:52 +00:00
vminitd: Proper pty setup / mount /dev/console (#248)
This commit is contained in:
@@ -62,37 +62,68 @@ struct ExecCommand: ParsableCommand {
|
||||
process: ContainerizationOCI.Process,
|
||||
log: Logger
|
||||
) throws {
|
||||
// CLOEXEC the pipe fd that signals process readiness.
|
||||
let syncfd = FileHandle(fileDescriptor: 3)
|
||||
if fcntl(3, F_SETFD, FD_CLOEXEC) == -1 {
|
||||
throw App.Errno(stage: "cloexec(syncfd)")
|
||||
}
|
||||
let syncPipe = FileHandle(fileDescriptor: 3)
|
||||
let ackPipe = FileHandle(fileDescriptor: 4)
|
||||
|
||||
try Self.enterNS(path: "/proc/\(self.parentPid)/ns/cgroup", nsType: CLONE_NEWCGROUP)
|
||||
try Self.enterNS(path: "/proc/\(self.parentPid)/ns/pid", nsType: CLONE_NEWPID)
|
||||
try Self.enterNS(path: "/proc/\(self.parentPid)/ns/uts", nsType: CLONE_NEWUTS)
|
||||
try Self.enterNS(path: "/proc/\(self.parentPid)/ns/mnt", nsType: CLONE_NEWNS)
|
||||
|
||||
let childPipe = Pipe()
|
||||
try childPipe.setCloexec()
|
||||
let processID = fork()
|
||||
|
||||
guard processID != -1 else {
|
||||
try? childPipe.fileHandleForReading.close()
|
||||
try? childPipe.fileHandleForWriting.close()
|
||||
try? syncfd.close()
|
||||
try? syncPipe.close()
|
||||
try? ackPipe.close()
|
||||
|
||||
throw App.Errno(stage: "fork")
|
||||
}
|
||||
|
||||
if processID == 0 { // child
|
||||
try childPipe.fileHandleForReading.close()
|
||||
try syncfd.close()
|
||||
// Wait for the grandparent to tell us that they acked our pid.
|
||||
guard let data = try ackPipe.read(upToCount: App.ackPid.count) else {
|
||||
throw App.Failure(message: "read ack pipe")
|
||||
}
|
||||
guard let pidAckStr = String(data: data, encoding: .utf8) else {
|
||||
throw App.Failure(message: "convert ack pipe data to string")
|
||||
}
|
||||
|
||||
guard pidAckStr == App.ackPid else {
|
||||
throw App.Failure(message: "received invalid acknowledgement string: \(pidAckStr)")
|
||||
}
|
||||
|
||||
guard setsid() != -1 else {
|
||||
throw App.Errno(stage: "setsid()")
|
||||
}
|
||||
|
||||
if process.terminal {
|
||||
let pty = try Console()
|
||||
try pty.configureStdIO()
|
||||
var masterFD = pty.master
|
||||
|
||||
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 {
|
||||
throw App.Failure(message: "read ack pipe")
|
||||
}
|
||||
|
||||
guard let consoleAckStr = String(data: data, encoding: .utf8) else {
|
||||
throw App.Failure(message: "convert ack pipe data to string")
|
||||
}
|
||||
|
||||
guard consoleAckStr == App.ackConsole else {
|
||||
throw App.Failure(message: "received invalid acknowledgement string: \(consoleAckStr)")
|
||||
}
|
||||
|
||||
guard ioctl(0, UInt(TIOCSCTTY), 0) != -1 else {
|
||||
throw App.Errno(stage: "setctty(0)")
|
||||
}
|
||||
try pty.close()
|
||||
}
|
||||
|
||||
// Apply O_CLOEXEC to all file descriptors except stdio.
|
||||
// This ensures that all unwanted fds we may have accidentally
|
||||
// inherited are marked close-on-exec so they stay out of the
|
||||
@@ -106,26 +137,13 @@ struct ExecCommand: ParsableCommand {
|
||||
// Set uid, gid, and supplementary groups
|
||||
try App.setPermissions(user: process.user)
|
||||
|
||||
if process.terminal {
|
||||
guard ioctl(0, UInt(TIOCSCTTY), 0) != -1 else {
|
||||
throw App.Errno(stage: "setctty()")
|
||||
}
|
||||
}
|
||||
|
||||
try App.exec(process: process)
|
||||
} else { // parent process
|
||||
try childPipe.fileHandleForWriting.close()
|
||||
|
||||
// wait until the pipe is closed then carry on.
|
||||
_ = try childPipe.fileHandleForReading.readToEnd()
|
||||
try childPipe.fileHandleForReading.close()
|
||||
|
||||
// send our child's pid to our parent before we exit.
|
||||
// Send our child's pid to our parent before we exit.
|
||||
var childPid = processID
|
||||
let data = Data(bytes: &childPid, count: MemoryLayout.size(ofValue: childPid))
|
||||
|
||||
try syncfd.write(contentsOf: data)
|
||||
try syncfd.close()
|
||||
try syncPipe.write(contentsOf: data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user