From 3366854d2c6f1c66d9efffdc79631cc8aad447c1 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Thu, 22 Aug 2024 20:45:37 +0200 Subject: [PATCH] Add fallback for fexecve() failure Signed-off-by: Bob Weinand --- spawn_worker/Cargo.toml | 2 +- spawn_worker/src/unix/spawn.rs | 48 +++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/spawn_worker/Cargo.toml b/spawn_worker/Cargo.toml index c6b74422a1..404526e9dc 100644 --- a/spawn_worker/Cargo.toml +++ b/spawn_worker/Cargo.toml @@ -9,6 +9,7 @@ bench = false [dependencies] anyhow = { version = "1.0" } io-lifetimes = { version = "1.0" } +fastrand = "2.0.1" [build-dependencies] cc_utils = {path = "../tools/cc_utils"} @@ -27,7 +28,6 @@ version = "0.48" [target.'cfg(windows)'.dependencies] winapi = { version = "=0.2.8" } kernel32-sys = "0.2.2" -fastrand = "2.0.1" [target.'cfg(not(windows))'.dependencies] memfd = { version = "0.6" } diff --git a/spawn_worker/src/unix/spawn.rs b/spawn_worker/src/unix/spawn.rs index 344d8aba80..1c589c5617 100644 --- a/spawn_worker/src/unix/spawn.rs +++ b/spawn_worker/src/unix/spawn.rs @@ -86,6 +86,7 @@ use std::{ io::{Seek, Write}, os::unix::prelude::{AsRawFd, OsStringExt, PermissionsExt}, }; +use std::ffi::CStr; use io_lifetimes::OwnedFd; @@ -444,18 +445,57 @@ impl SpawnWorker { #[cfg(not(target_os = "linux"))] let skip_close_fd = 0; - let spawn: Box = match spawn_method { + let mut spawn: Box = match spawn_method { #[cfg(target_os = "linux")] SpawnMethod::FdExec => { let fd = linux::write_trampoline()?; skip_close_fd = fd.as_raw_fd(); - Box::new(move || { + Box::new(move || unsafe { // not using nix crate here, as it would allocate args after fork, which will // lead to crashes on systems where allocator is not // fork+thread safe - unsafe { libc::fexecve(fd.as_raw_fd(), argv.as_ptr(), envp.as_ptr()) }; + libc::fexecve(fd.as_raw_fd(), argv.as_ptr(), envp.as_ptr()); + // if we're here then exec has failed - panic!("{}", std::io::Error::last_os_error()); + let fexecve_error = std::io::Error::last_os_error(); + + let mut temp_path = [0u8; 256]; + let tmpdir = libc::getenv("TMPDIR".as_ptr() as *const libc::c_char) as *const libc::c_char; + let tmpdir = if tmpdir.is_null() { + b"/tmp" + } else { + CStr::from_ptr(tmpdir).to_bytes() + }; + if tmpdir.len() < 220 { + temp_path[..tmpdir.len()].copy_from_slice(tmpdir); + let mut off = tmpdir.len(); + let spawn_prefix = b"/dd-ipc-spawn_"; + temp_path[off..off + spawn_prefix.len()].copy_from_slice(spawn_prefix); + off += spawn_prefix.len(); + for _ in 0..8 { + temp_path[off] = fastrand::alphanumeric() as u8; + off += 1; + } + + let path = CString::from_vec_with_nul_unchecked( + Vec::from_raw_parts(temp_path.as_mut_ptr(), off, off)); + let path_ptr = path.as_ptr(); + let tmpfd = libc::open(path_ptr, libc::O_CREAT | libc::O_RDWR, libc::S_IRWXU as libc::c_uint); + if tmpfd < 0 { + // We'll leak it, executing Drop of path is forbidden. + std::mem::forget(path); + } else { + libc::sendfile(tmpfd, fd.as_raw_fd(), std::ptr::null_mut(), crate::TRAMPOLINE_BIN.len()); + libc::close(tmpfd); + argv.set(1, path); + + libc::execve(path_ptr, argv.as_ptr(), envp.as_ptr()); + + libc::unlink(temp_path.as_ptr() as *const libc::c_char); + } + } + + panic!("Failed lauching via fexecve(): {fexecve_error}"); }) } #[cfg(not(target_os = "macos"))]