From 6ac9cbccf431dabfdf5b18192d2d1c7834985629 Mon Sep 17 00:00:00 2001 From: yasinlex <146157109+yasinlex@users.noreply.github.com> Date: Wed, 5 Aug 2026 03:29:47 +0700 Subject: [PATCH] fix: dup() fd before from_raw_fd to prevent double-close MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UnixStream::from_raw_fd() takes ownership of the file descriptor. When Host is dropped, Rust closes the fd — but the caller that constructed the "fd://" address still holds the original fd, expecting it to remain open. This causes a double-close: the fd is closed out from under the original holder, and if both sides later use it, one operates on a recycled fd assigned to an unrelated resource (use-after-close). Call libc::dup(fd) first to create an independent copy that this Host owns and can safely close, leaving the original fd untouched. Also add an error check for dup() failure instead of panicking on EBADF. --- executor/src/host/mod.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/executor/src/host/mod.rs b/executor/src/host/mod.rs index 01360777a..bbca61468 100644 --- a/executor/src/host/mod.rs +++ b/executor/src/host/mod.rs @@ -49,7 +49,18 @@ impl Host { let fd: i32 = fd_str .parse() .with_context(|| format!("parsing fd number from '{fd_str}'"))?; - let stream = unsafe { std::os::unix::net::UnixStream::from_raw_fd(fd) }; + // SAFETY: The caller owns `fd` and expects us to use it, not + // consume it. `from_raw_fd` takes ownership and would close the + // original fd on drop, so we must dup() first to get an + // independent copy that this Host can safely own and close. + let duped = unsafe { libc::dup(fd) }; + if duped < 0 { + anyhow::bail!( + "failed to dup fd {fd}: {}", + std::io::Error::last_os_error() + ); + } + let stream = unsafe { std::os::unix::net::UnixStream::from_raw_fd(duped) }; Box::new(bufreaderwriter::seq::BufReaderWriterSeq::new_writer(stream)) } else { Box::new(bufreaderwriter::seq::BufReaderWriterSeq::new_writer(