1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker //! Provides [fork_process] to fork a process.
6*bb4ee6a4SAndroid Build Coastguard Worker
7*bb4ee6a4SAndroid Build Coastguard Worker #![deny(missing_docs)]
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::CString;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::ManuallyDrop;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::process::ExitStatusExt;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::process;
13*bb4ee6a4SAndroid Build Coastguard Worker
14*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::linux::wait_for_pid;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::Pid;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
18*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "seccomp_trace")]
19*bb4ee6a4SAndroid Build Coastguard Worker use log::debug;
20*bb4ee6a4SAndroid Build Coastguard Worker use log::warn;
21*bb4ee6a4SAndroid Build Coastguard Worker use minijail::Minijail;
22*bb4ee6a4SAndroid Build Coastguard Worker
23*bb4ee6a4SAndroid Build Coastguard Worker /// Child represents the forked process.
24*bb4ee6a4SAndroid Build Coastguard Worker pub struct Child {
25*bb4ee6a4SAndroid Build Coastguard Worker /// The pid of the child process.
26*bb4ee6a4SAndroid Build Coastguard Worker pub pid: Pid,
27*bb4ee6a4SAndroid Build Coastguard Worker }
28*bb4ee6a4SAndroid Build Coastguard Worker
29*bb4ee6a4SAndroid Build Coastguard Worker impl Child {
30*bb4ee6a4SAndroid Build Coastguard Worker /// Wait for the child process exit using `waitpid(2)`.
wait(self) -> base::Result<u8>31*bb4ee6a4SAndroid Build Coastguard Worker pub fn wait(self) -> base::Result<u8> {
32*bb4ee6a4SAndroid Build Coastguard Worker // Suppress warning from the drop().
33*bb4ee6a4SAndroid Build Coastguard Worker let pid = self.into_pid();
34*bb4ee6a4SAndroid Build Coastguard Worker let (_, status) = wait_for_pid(pid, 0)?;
35*bb4ee6a4SAndroid Build Coastguard Worker if let Some(exit_code) = status.code() {
36*bb4ee6a4SAndroid Build Coastguard Worker Ok(exit_code as u8)
37*bb4ee6a4SAndroid Build Coastguard Worker } else if let Some(signal) = status.signal() {
38*bb4ee6a4SAndroid Build Coastguard Worker let exit_code = if signal >= 128 {
39*bb4ee6a4SAndroid Build Coastguard Worker warn!("wait for child: unexpected signal({:?})", signal);
40*bb4ee6a4SAndroid Build Coastguard Worker 255
41*bb4ee6a4SAndroid Build Coastguard Worker } else {
42*bb4ee6a4SAndroid Build Coastguard Worker 128 + signal as u8
43*bb4ee6a4SAndroid Build Coastguard Worker };
44*bb4ee6a4SAndroid Build Coastguard Worker Ok(exit_code)
45*bb4ee6a4SAndroid Build Coastguard Worker } else {
46*bb4ee6a4SAndroid Build Coastguard Worker unreachable!("waitpid with option 0 only waits for exited and signaled status");
47*bb4ee6a4SAndroid Build Coastguard Worker }
48*bb4ee6a4SAndroid Build Coastguard Worker }
49*bb4ee6a4SAndroid Build Coastguard Worker
50*bb4ee6a4SAndroid Build Coastguard Worker /// Convert [Child] into [Pid].
51*bb4ee6a4SAndroid Build Coastguard Worker ///
52*bb4ee6a4SAndroid Build Coastguard Worker /// If [Child] is dropped without `Child::wait()`, it logs warning message. Users who wait
53*bb4ee6a4SAndroid Build Coastguard Worker /// processes in other ways should suppress the warning by unwrapping [Child] into [Pid].
54*bb4ee6a4SAndroid Build Coastguard Worker ///
55*bb4ee6a4SAndroid Build Coastguard Worker /// The caller of this method now owns the process and is responsible for managing the
56*bb4ee6a4SAndroid Build Coastguard Worker /// termination of the process.
into_pid(self) -> Pid57*bb4ee6a4SAndroid Build Coastguard Worker pub fn into_pid(self) -> Pid {
58*bb4ee6a4SAndroid Build Coastguard Worker let pid = self.pid;
59*bb4ee6a4SAndroid Build Coastguard Worker // Suppress warning from the drop().
60*bb4ee6a4SAndroid Build Coastguard Worker let _ = ManuallyDrop::new(self);
61*bb4ee6a4SAndroid Build Coastguard Worker pid
62*bb4ee6a4SAndroid Build Coastguard Worker }
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker
65*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for Child {
drop(&mut self)66*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) {
67*bb4ee6a4SAndroid Build Coastguard Worker warn!("the child process have not been waited.: {}", self.pid);
68*bb4ee6a4SAndroid Build Coastguard Worker }
69*bb4ee6a4SAndroid Build Coastguard Worker }
70*bb4ee6a4SAndroid Build Coastguard Worker
71*bb4ee6a4SAndroid Build Coastguard Worker /// Forks this process using [Minijail] and calls a closure in the new process.
72*bb4ee6a4SAndroid Build Coastguard Worker ///
73*bb4ee6a4SAndroid Build Coastguard Worker /// After `post_fork_cb` returns, the new process exits with `0` code. If `post_fork_cb` panics, the
74*bb4ee6a4SAndroid Build Coastguard Worker /// new process exits with `101` code.
75*bb4ee6a4SAndroid Build Coastguard Worker ///
76*bb4ee6a4SAndroid Build Coastguard Worker /// This function never returns in the forked process.
77*bb4ee6a4SAndroid Build Coastguard Worker ///
78*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
79*bb4ee6a4SAndroid Build Coastguard Worker ///
80*bb4ee6a4SAndroid Build Coastguard Worker /// * `jail` - [Minijail] instance to fork.
81*bb4ee6a4SAndroid Build Coastguard Worker /// * `keep_rds` - [RawDescriptor]s to be kept in the forked process. other file descriptors will be
82*bb4ee6a4SAndroid Build Coastguard Worker /// closed by [Minijail] in the forked process.
83*bb4ee6a4SAndroid Build Coastguard Worker /// * `debug_label` - (optional) thread name. this will be trimmed to 15 charactors.
84*bb4ee6a4SAndroid Build Coastguard Worker /// * `post_fork_cb` - Callback to run in the new process.
fork_process<F>( jail: Minijail, mut keep_rds: Vec<RawDescriptor>, debug_label: Option<String>, post_fork_cb: F, ) -> minijail::Result<Child> where F: FnOnce(),85*bb4ee6a4SAndroid Build Coastguard Worker pub fn fork_process<F>(
86*bb4ee6a4SAndroid Build Coastguard Worker jail: Minijail,
87*bb4ee6a4SAndroid Build Coastguard Worker mut keep_rds: Vec<RawDescriptor>,
88*bb4ee6a4SAndroid Build Coastguard Worker debug_label: Option<String>,
89*bb4ee6a4SAndroid Build Coastguard Worker post_fork_cb: F,
90*bb4ee6a4SAndroid Build Coastguard Worker ) -> minijail::Result<Child>
91*bb4ee6a4SAndroid Build Coastguard Worker where
92*bb4ee6a4SAndroid Build Coastguard Worker F: FnOnce(),
93*bb4ee6a4SAndroid Build Coastguard Worker {
94*bb4ee6a4SAndroid Build Coastguard Worker // Deduplicate the FDs since minijail expects this.
95*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.sort_unstable();
96*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.dedup();
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
99*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the program is still single threaded.
100*bb4ee6a4SAndroid Build Coastguard Worker // We own the jail object and nobody else will try to reuse it.
101*bb4ee6a4SAndroid Build Coastguard Worker let pid = match unsafe { jail.fork(Some(&keep_rds)) }? {
102*bb4ee6a4SAndroid Build Coastguard Worker 0 => {
103*bb4ee6a4SAndroid Build Coastguard Worker struct ExitGuard;
104*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for ExitGuard {
105*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) {
106*bb4ee6a4SAndroid Build Coastguard Worker // Rust exits with 101 when panics.
107*bb4ee6a4SAndroid Build Coastguard Worker process::exit(101);
108*bb4ee6a4SAndroid Build Coastguard Worker }
109*bb4ee6a4SAndroid Build Coastguard Worker }
110*bb4ee6a4SAndroid Build Coastguard Worker // Prevents a panic in post_fork_cb from bypassing the process::exit.
111*bb4ee6a4SAndroid Build Coastguard Worker let _exit_guard = ExitGuard {};
112*bb4ee6a4SAndroid Build Coastguard Worker
113*bb4ee6a4SAndroid Build Coastguard Worker if let Some(debug_label) = debug_label {
114*bb4ee6a4SAndroid Build Coastguard Worker // pthread_setname_np() limit on Linux
115*bb4ee6a4SAndroid Build Coastguard Worker const MAX_THREAD_LABEL_LEN: usize = 15;
116*bb4ee6a4SAndroid Build Coastguard Worker let debug_label_trimmed = &debug_label.as_bytes()
117*bb4ee6a4SAndroid Build Coastguard Worker [..std::cmp::min(MAX_THREAD_LABEL_LEN, debug_label.len())];
118*bb4ee6a4SAndroid Build Coastguard Worker match CString::new(debug_label_trimmed) {
119*bb4ee6a4SAndroid Build Coastguard Worker Ok(thread_name) => {
120*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
121*bb4ee6a4SAndroid Build Coastguard Worker // Safe because thread_name is a valid pointer and setting name of this
122*bb4ee6a4SAndroid Build Coastguard Worker // thread should be safe.
123*bb4ee6a4SAndroid Build Coastguard Worker let _ = unsafe {
124*bb4ee6a4SAndroid Build Coastguard Worker libc::pthread_setname_np(libc::pthread_self(), thread_name.as_ptr())
125*bb4ee6a4SAndroid Build Coastguard Worker };
126*bb4ee6a4SAndroid Build Coastguard Worker }
127*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
128*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to compile thread name: {:?}", e);
129*bb4ee6a4SAndroid Build Coastguard Worker }
130*bb4ee6a4SAndroid Build Coastguard Worker }
131*bb4ee6a4SAndroid Build Coastguard Worker }
132*bb4ee6a4SAndroid Build Coastguard Worker
133*bb4ee6a4SAndroid Build Coastguard Worker post_fork_cb();
134*bb4ee6a4SAndroid Build Coastguard Worker // ! Never returns
135*bb4ee6a4SAndroid Build Coastguard Worker process::exit(0);
136*bb4ee6a4SAndroid Build Coastguard Worker }
137*bb4ee6a4SAndroid Build Coastguard Worker pid => pid,
138*bb4ee6a4SAndroid Build Coastguard Worker };
139*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "seccomp_trace")]
140*bb4ee6a4SAndroid Build Coastguard Worker debug!(
141*bb4ee6a4SAndroid Build Coastguard Worker // Proxy and swap devices fork here
142*bb4ee6a4SAndroid Build Coastguard Worker "seccomp_trace {{\"event\": \"minijail_fork\", \"pid\": \"{}\", \"name\": \"{}\", \"jail_addr\": \"0x{:x}\"}}",
143*bb4ee6a4SAndroid Build Coastguard Worker pid,
144*bb4ee6a4SAndroid Build Coastguard Worker match debug_label {
145*bb4ee6a4SAndroid Build Coastguard Worker Some(debug_label) => debug_label,
146*bb4ee6a4SAndroid Build Coastguard Worker None => "process.rs: no debug label".to_owned(),
147*bb4ee6a4SAndroid Build Coastguard Worker },
148*bb4ee6a4SAndroid Build Coastguard Worker // Can't use safe wrapper because jail crate depends on base
149*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
150*bb4ee6a4SAndroid Build Coastguard Worker // Safe because it's only doing a read within bound checked by static assert
151*bb4ee6a4SAndroid Build Coastguard Worker unsafe {*(&jail as *const Minijail as *const usize)}
152*bb4ee6a4SAndroid Build Coastguard Worker );
153*bb4ee6a4SAndroid Build Coastguard Worker Ok(Child { pid })
154*bb4ee6a4SAndroid Build Coastguard Worker }
155