Skip to content

Commit a09115f

Browse files
authored
Rollup merge of #89930 - cuviper:avoid-clone3, r=joshtriplett
Only use `clone3` when needed for pidfd In #89522 we learned that `clone3` is interacting poorly with Gentoo's `sandbox` tool. We only need that for the unstable pidfd extensions, so otherwise avoid that and use a normal `fork`. This is a re-application of beta #89924, now that we're aware that we need more than just a temporary release fix. I also reverted 12fbabd, as that was just fallout from using `clone3` instead of `fork`. r? `@Mark-Simulacrum` cc `@joshtriplett`
2 parents 68ca579 + e96a0a8 commit a09115f

File tree

3 files changed

+17
-44
lines changed

3 files changed

+17
-44
lines changed

library/std/src/sys/unix/process/process_unix.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -166,21 +166,22 @@ impl Command {
166166
fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
167167
}
168168

169+
// Bypassing libc for `clone3` can make further libc calls unsafe,
170+
// so we use it sparingly for now. See #89522 for details.
171+
// Some tools (e.g. sandboxing tools) may also expect `fork`
172+
// rather than `clone3`.
173+
let want_clone3_pidfd = self.get_create_pidfd();
174+
169175
// If we fail to create a pidfd for any reason, this will
170176
// stay as -1, which indicates an error.
171177
let mut pidfd: pid_t = -1;
172178

173179
// Attempt to use the `clone3` syscall, which supports more arguments
174180
// (in particular, the ability to create a pidfd). If this fails,
175181
// we will fall through this block to a call to `fork()`
176-
if HAS_CLONE3.load(Ordering::Relaxed) {
177-
let mut flags = 0;
178-
if self.get_create_pidfd() {
179-
flags |= CLONE_PIDFD;
180-
}
181-
182+
if want_clone3_pidfd && HAS_CLONE3.load(Ordering::Relaxed) {
182183
let mut args = clone_args {
183-
flags,
184+
flags: CLONE_PIDFD,
184185
pidfd: &mut pidfd as *mut pid_t as u64,
185186
child_tid: 0,
186187
parent_tid: 0,
@@ -212,8 +213,8 @@ impl Command {
212213
}
213214
}
214215

215-
// If we get here, the 'clone3' syscall does not exist
216-
// or we do not have permission to call it
216+
// Generally, we just call `fork`. If we get here after wanting `clone3`,
217+
// then the syscall does not exist or we do not have permission to call it.
217218
cvt(libc::fork()).map(|res| (res, pidfd))
218219
}
219220

src/test/ui/command/command-pre-exec.rs

+6-19
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,15 @@
88
// ignore-sgx no processes
99
#![feature(process_exec, rustc_private)]
1010

11+
extern crate libc;
12+
1113
use std::env;
1214
use std::io::Error;
1315
use std::os::unix::process::CommandExt;
1416
use std::process::Command;
1517
use std::sync::atomic::{AtomicUsize, Ordering};
1618
use std::sync::Arc;
1719

18-
#[cfg(not(target_os = "linux"))]
19-
fn getpid() -> u32 {
20-
use std::process;
21-
process::id()
22-
}
23-
24-
/// We need to directly use the getpid syscall instead of using `process::id()`
25-
/// because the libc wrapper might return incorrect values after a process was
26-
/// forked.
27-
#[cfg(target_os = "linux")]
28-
fn getpid() -> u32 {
29-
extern crate libc;
30-
unsafe {
31-
libc::syscall(libc::SYS_getpid) as _
32-
}
33-
}
34-
3520
fn main() {
3621
if let Some(arg) = env::args().nth(1) {
3722
match &arg[..] {
@@ -83,12 +68,14 @@ fn main() {
8368
};
8469
assert_eq!(output.raw_os_error(), Some(102));
8570

86-
let pid = getpid();
71+
let pid = unsafe { libc::getpid() };
72+
assert!(pid >= 0);
8773
let output = unsafe {
8874
Command::new(&me)
8975
.arg("empty")
9076
.pre_exec(move || {
91-
let child = getpid();
77+
let child = libc::getpid();
78+
assert!(child >= 0);
9279
assert!(pid != child);
9380
Ok(())
9481
})

src/test/ui/process/process-panic-after-fork.rs

+1-16
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,6 @@ use std::sync::atomic::{AtomicU32, Ordering};
2323

2424
use libc::c_int;
2525

26-
#[cfg(not(target_os = "linux"))]
27-
fn getpid() -> u32 {
28-
process::id()
29-
}
30-
31-
/// We need to directly use the getpid syscall instead of using `process::id()`
32-
/// because the libc wrapper might return incorrect values after a process was
33-
/// forked.
34-
#[cfg(target_os = "linux")]
35-
fn getpid() -> u32 {
36-
unsafe {
37-
libc::syscall(libc::SYS_getpid) as _
38-
}
39-
}
40-
4126
/// This stunt allocator allows us to spot heap allocations in the child.
4227
struct PidChecking<A> {
4328
parent: A,
@@ -59,7 +44,7 @@ impl<A> PidChecking<A> {
5944
fn check(&self) {
6045
let require_pid = self.require_pid.load(Ordering::Acquire);
6146
if require_pid != 0 {
62-
let actual_pid = getpid();
47+
let actual_pid = process::id();
6348
if require_pid != actual_pid {
6449
unsafe {
6550
libc::raise(libc::SIGUSR1);

0 commit comments

Comments
 (0)