Isolate interactive terminal session ownership
This commit is contained in:
parent
b240bc1d12
commit
690738d846
3 changed files with 280 additions and 24 deletions
|
|
@ -33,6 +33,7 @@ pub struct TargetCommand {
|
|||
parent_edge: ParentEdge,
|
||||
executable: Option<OwnedFd>,
|
||||
stdin: Option<File>,
|
||||
terminal: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
|
|
@ -106,6 +107,7 @@ impl TargetCommand {
|
|||
parent_edge: ParentEdge::ParentDeathKill,
|
||||
executable: None,
|
||||
stdin: None,
|
||||
terminal: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,6 +126,7 @@ impl TargetCommand {
|
|||
parent_edge: ParentEdge::ParentDeathKill,
|
||||
executable: Some(executable),
|
||||
stdin: None,
|
||||
terminal: false,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +159,12 @@ impl TargetCommand {
|
|||
Ok(self)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_controlling_terminal(mut self) -> Self {
|
||||
self.terminal = true;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn parent_edge(&self) -> ParentEdge {
|
||||
self.parent_edge
|
||||
|
|
@ -180,6 +189,7 @@ impl TargetCommand {
|
|||
ParentEdge::ParentDeathKill => "kill",
|
||||
ParentEdge::LifetimePipe => "lifetime-pipe",
|
||||
})
|
||||
.args(self.terminal.then_some("--target-terminal"))
|
||||
.args(
|
||||
self.stdin
|
||||
.as_ref()
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,11 @@ pub fn parse_wrapper_arguments(
|
|||
Some("lifetime-pipe") => ParentEdge::LifetimePipe,
|
||||
_ => return Err(io::Error::other("wrapper parent action is invalid")),
|
||||
};
|
||||
let next = arguments.next();
|
||||
let mut next = arguments.next();
|
||||
let terminal = next.as_deref() == Some(OsStr::new("--target-terminal"));
|
||||
if terminal {
|
||||
next = arguments.next();
|
||||
}
|
||||
let stdin = if next.as_deref() == Some(OsStr::new("--target-stdin-fd")) {
|
||||
let descriptor = arguments
|
||||
.next()
|
||||
|
|
@ -117,6 +121,7 @@ pub fn parse_wrapper_arguments(
|
|||
parent_edge,
|
||||
executable: None,
|
||||
stdin,
|
||||
terminal,
|
||||
};
|
||||
let boot = parse_boot_hex(&boot)?;
|
||||
Ok((
|
||||
|
|
|
|||
Loading…
Reference in a new issue