Make all receive functions in storefd-listen unsafe
They all rely on a contract that cannot be checked by the compiler so they are all unsafe.
This commit is contained in:
parent
4e1266c877
commit
45d7fbb36e
|
@ -1,22 +1,27 @@
|
||||||
//! Support for file descriptor passing with `LISTEN_FD`
|
//! Support for file descriptor passing with `LISTEN_FD`
|
||||||
//!
|
//!
|
||||||
//! The entrypoints of this module are [`FileDescriptor::receive()`] and [`FileDescriptor::receive_with_names()`]. (And their **`unsafe`** `*_no_dup` variants.)
|
//! The entrypoints of this module are [`FileDescriptor::receive()`] and [`FileDescriptor::receive_with_names()`]. (And their `*_no_dup` variants.)
|
||||||
|
//!
|
||||||
|
//! **All the `receive` functions are unsafe as they rely on states that cannot be checked by the
|
||||||
|
//! rust compiler** (namely that the raw filedescriptors passed to the program (that aren't known
|
||||||
|
//! to the compiler) haven't been taken or closed already).
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! # main() -> Result<(), Box<dyn std::error::Error>> {
|
//! main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
//! let received_fd: Vec<FileDescriptor> = FileDescriptor::receive_with_names(true)
|
//! // SAFETY: First thing we are doing so the file descriptors shouldn't have changed since they were passed to us.
|
||||||
//! .into_iter()
|
//! let received_fd: Vec<FileDescriptor> = unsafe { FileDescriptor::receive_with_names(true) }
|
||||||
//! .filter_map(|(name, res)| {
|
//! .into_iter()
|
||||||
//! if name == "<expected_filename>" {
|
//! .filter_map(|(name, res)| {
|
||||||
//! Some(res)
|
//! if name == "<expected_filename>" {
|
||||||
//! } else {
|
//! Some(res)
|
||||||
//! None
|
//! } else {
|
||||||
//! }
|
//! None
|
||||||
//! })
|
//! }
|
||||||
//! .collect()?
|
//! })
|
||||||
//! // Use the received file descriptors.
|
//! .collect()?
|
||||||
//! # Ok(())
|
//! // Use the received file descriptors.
|
||||||
//! # }
|
//! Ok(())
|
||||||
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
@ -105,7 +110,13 @@ impl FileDescriptor {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// This function will fail if no file descriptor could be received which might not actually be an error. See [`ReceiveError`] for details.
|
/// This function will fail if no file descriptor could be received which might not actually be an error. See [`ReceiveError`] for details.
|
||||||
pub fn receive(
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct or closed.
|
||||||
|
/// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)).
|
||||||
|
/// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors.
|
||||||
|
pub unsafe fn receive(
|
||||||
unset_env: bool,
|
unset_env: bool,
|
||||||
) -> Result<impl IntoIterator<Item = Result<Self, DupError>>, ReceiveError> {
|
) -> Result<impl IntoIterator<Item = Result<Self, DupError>>, ReceiveError> {
|
||||||
log::trace!("Receiving file descriptors.");
|
log::trace!("Receiving file descriptors.");
|
||||||
|
@ -129,7 +140,7 @@ impl FileDescriptor {
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct.
|
/// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct or closed.
|
||||||
/// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)).
|
/// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)).
|
||||||
/// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors.
|
/// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors.
|
||||||
pub unsafe fn receive_no_dup() -> Result<impl IntoIterator<Item = Self>, ReceiveError> {
|
pub unsafe fn receive_no_dup() -> Result<impl IntoIterator<Item = Self>, ReceiveError> {
|
||||||
|
@ -139,7 +150,7 @@ impl FileDescriptor {
|
||||||
Self::from_fds_no_dup(fds).map_err(ReceiveError::GetFds)
|
Self::from_fds_no_dup(fds).map_err(ReceiveError::GetFds)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_receive(unset_env: bool) -> Result<usize, ReceiveError> {
|
unsafe fn inner_receive(unset_env: bool) -> Result<usize, ReceiveError> {
|
||||||
let pid = env::var_os(PID_VAR).ok_or(ReceiveError::NoListenPID)?;
|
let pid = env::var_os(PID_VAR).ok_or(ReceiveError::NoListenPID)?;
|
||||||
let fds = env::var_os(FD_NUMBER_VAR).ok_or(ReceiveError::NoListenFD)?;
|
let fds = env::var_os(FD_NUMBER_VAR).ok_or(ReceiveError::NoListenFD)?;
|
||||||
log::trace!("{PID_VAR} = {pid:?}; {FD_NUMBER_VAR} = {fds:?}");
|
log::trace!("{PID_VAR} = {pid:?}; {FD_NUMBER_VAR} = {fds:?}");
|
||||||
|
@ -181,7 +192,13 @@ impl FileDescriptor {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// This function will fail if no file descriptors could be obtained or the names associated with them couldn't be obtained. See [`ReceiveNameError`] for details.
|
/// This function will fail if no file descriptors could be obtained or the names associated with them couldn't be obtained. See [`ReceiveNameError`] for details.
|
||||||
pub fn receive_with_names(
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct or closed.
|
||||||
|
/// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)).
|
||||||
|
/// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors.
|
||||||
|
pub unsafe fn receive_with_names(
|
||||||
unset_env: bool,
|
unset_env: bool,
|
||||||
) -> Result<impl IntoIterator<Item = (OsString, Result<Self, DupError>)>, ReceiveNameError>
|
) -> Result<impl IntoIterator<Item = (OsString, Result<Self, DupError>)>, ReceiveNameError>
|
||||||
{
|
{
|
||||||
|
@ -203,7 +220,7 @@ impl FileDescriptor {
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct.
|
/// This function is safe if (and only if) the received file descriptors weren't already taken into a owned rust struct or closed.
|
||||||
/// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)).
|
/// (In short it needs to follow the safety constraints of [`OwnedFd::from_raw_fd`](std::os::fd::FromRawFd)).
|
||||||
/// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors.
|
/// The simplest way to insure that it is so is to only use functions from this crate to get these file descriptors.
|
||||||
pub unsafe fn receive_with_names_no_dup(
|
pub unsafe fn receive_with_names_no_dup(
|
||||||
|
@ -228,7 +245,7 @@ impl FileDescriptor {
|
||||||
.collect::<Vec<_>>())
|
.collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_fd_offset(fd_offset: usize) -> Result<Self, DupError> {
|
unsafe fn from_fd_offset(fd_offset: usize) -> Result<Self, DupError> {
|
||||||
SD_LISTEN_FDS_START
|
SD_LISTEN_FDS_START
|
||||||
.checked_add(fd_offset as RawFd)
|
.checked_add(fd_offset as RawFd)
|
||||||
.map(|fd| {
|
.map(|fd| {
|
||||||
|
@ -240,14 +257,14 @@ impl FileDescriptor {
|
||||||
.map(Self::from_fd)
|
.map(Self::from_fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_fds(
|
unsafe fn from_fds(
|
||||||
num_fds: usize,
|
num_fds: usize,
|
||||||
) -> Result<impl IntoIterator<Item = Result<Self, DupError>>, GetFdsError> {
|
) -> Result<impl IntoIterator<Item = Result<Self, DupError>>, GetFdsError> {
|
||||||
if SD_LISTEN_FDS_START.checked_add(num_fds as RawFd).is_none() {
|
if SD_LISTEN_FDS_START.checked_add(num_fds as RawFd).is_none() {
|
||||||
return Err(GetFdsError::TooManyFDs(num_fds));
|
return Err(GetFdsError::TooManyFDs(num_fds));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = (0..num_fds).map(Self::from_fd_offset);
|
let ret = (0..num_fds).map(|fd_offset| unsafe { Self::from_fd_offset(fd_offset) });
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue