ic_host_process/child/gate/
mod.rs1#![allow(
3 unsafe_code,
4 reason = "reviewed pipe, close-on-exec and post-fork descriptor operations imported from Profiler"
5)]
6use std::{
7 ffi::{OsStr, OsString},
8 fs::File,
9 io,
10 process::Command,
11};
12
13#[derive(Debug)]
15pub enum LaunchGateError {
16 Pipe(io::Error),
18 Descriptor(io::Error),
20}
21impl std::fmt::Display for LaunchGateError {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 match self {
24 Self::Pipe(e) | Self::Descriptor(e) => e.fmt(f),
25 }
26 }
27}
28impl std::error::Error for LaunchGateError {
29 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
30 match self {
31 Self::Pipe(e) | Self::Descriptor(e) => Some(e),
32 }
33 }
34}
35
36pub fn gated_command(
44 program: &OsStr,
45 arguments: &[OsString],
46 launcher_name: &OsStr,
47) -> Result<(Command, File), LaunchGateError> {
48 use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
49 use std::os::unix::process::CommandExt;
50
51 let mut descriptors = [-1; 2];
52 if unsafe { libc::pipe(descriptors.as_mut_ptr()) } != 0 {
54 return Err(LaunchGateError::Pipe(std::io::Error::last_os_error()));
55 }
56 let read = unsafe { OwnedFd::from_raw_fd(descriptors[0]) };
58 let write = unsafe { OwnedFd::from_raw_fd(descriptors[1]) };
59 for fd in [read.as_raw_fd(), write.as_raw_fd()] {
60 if unsafe { libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC) } < 0 {
62 return Err(LaunchGateError::Descriptor(std::io::Error::last_os_error()));
63 }
64 }
65 let write_fd = write.as_raw_fd();
66 let mut command = Command::new("/bin/sh");
67 command
68 .args(["-c", "read -r _ <&3 || exit 125; exec 3<&-; exec \"$@\""])
69 .arg(launcher_name)
70 .arg(program)
71 .args(arguments);
72 unsafe {
75 command.pre_exec(move || {
76 let source = read.as_raw_fd();
77 if libc::dup2(source, 3) < 0 || libc::fcntl(3, libc::F_SETFD, 0) < 0 {
78 return Err(std::io::Error::last_os_error());
79 }
80 if source != 3 {
81 libc::close(source);
82 }
83 if write_fd != 3 {
84 libc::close(write_fd);
85 }
86 Ok(())
87 });
88 }
89 Ok((command, std::fs::File::from(write)))
90}