Isolate interactive terminal session ownership

This commit is contained in:
ms2k 2026-08-01 00:00:47 +09:00
commit 690738d846

View file

@ -16,6 +16,7 @@ use super::{
use crate::ipc::private_stream_pair;
use crate::user_namespace::UserNamespaceMap;
use std::io::{Read as _, Write as _};
use std::os::unix::process::CommandExt as _;
impl ChildBroker {
/// Spawns the private Host Coordinator bootstrap with exact pipe ownership and pidfd reaping.
@ -44,7 +45,8 @@ impl ChildBroker {
.args(&target.arguments)
.stdin(Stdio::from(lifetime_reader))
.stdout(Stdio::piped())
.stderr(Stdio::inherit());
.stderr(Stdio::inherit())
.process_group(0);
let mut child = command.spawn()?;
let status = child
.stdout
@ -743,6 +745,7 @@ fn run_mapped_wrapper_role(arguments: Vec<OsString>) -> io::Result<()> {
rustix::process::Uid::ROOT,
rustix::process::Uid::ROOT,
)?;
establish_controlling_terminal(&target)?;
if let Some(stdin) = target.stdin.as_ref() {
rustix::stdio::dup2_stdin(stdin)?;
}
@ -761,12 +764,27 @@ fn run_wrapper_role(arguments: Vec<OsString>) -> io::Result<()> {
require_lifetime_pipe_and_recheck(expected_parent)?;
}
}
establish_controlling_terminal(&target)?;
if let Some(stdin) = target.stdin.as_ref() {
rustix::stdio::dup2_stdin(stdin)?;
}
Err(exec_target(target))
}
fn establish_controlling_terminal(target: &TargetCommand) -> io::Result<()> {
if !target.terminal {
return Ok(());
}
let stdin = target
.stdin
.as_ref()
.ok_or_else(|| io::Error::other("terminal target stdin is missing"))?;
rustix::process::setsid()?;
rustix::process::ioctl_tiocsctty(stdin)?;
rustix::termios::tcsetpgrp(stdin, rustix::process::getpgrp())?;
Ok(())
}
fn require_lifetime_pipe_and_recheck(
expected_parent: PidfsProcessIdentityV1,
) -> io::Result<RetainedProcess> {