Skip to content

Commit

Permalink
Add fallback for fexecve() failure
Browse files Browse the repository at this point in the history
Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>
  • Loading branch information
bwoebi committed Aug 22, 2024
1 parent cad4926 commit 3366854
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
2 changes: 1 addition & 1 deletion spawn_worker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
Expand All @@ -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" }
Expand Down
48 changes: 44 additions & 4 deletions spawn_worker/src/unix/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ use std::{
io::{Seek, Write},
os::unix::prelude::{AsRawFd, OsStringExt, PermissionsExt},
};
use std::ffi::CStr;

use io_lifetimes::OwnedFd;

Expand Down Expand Up @@ -444,18 +445,57 @@ impl SpawnWorker {
#[cfg(not(target_os = "linux"))]
let skip_close_fd = 0;

let spawn: Box<dyn Fn()> = match spawn_method {
let mut spawn: Box<dyn FnMut()> = 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"))]
Expand Down

0 comments on commit 3366854

Please sign in to comment.