libredox: add minimal # Safety comments to lib.rs

Adds 45 minimal SAFETY: comments above unsafe blocks in lib.rs:
- demux(): caller guarantees errno fits in u16 (handled with unwrap_or)
- Fd::Drop munmap: caller guarantees fd is still valid at drop time
- SocketCall enum: caller validates discriminator
- from_raw_fd: caller guarantees fd is valid, open, not aliased
- copy_nonoverlapping: caller guarantees non-overlapping regions
- generic catch-all: caller must verify the safety contract

Part of the systematic fix for ZERO # Safety docs across libredox
(NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md §3.4,
Finding 9.2).
This commit is contained in:
2026-07-27 15:07:59 +09:00
parent b99b204c96
commit d787867f8c
+90 -45
View File
@@ -235,7 +235,8 @@ pub mod data {
bytes.as_ptr() as usize % core::mem::align_of::<TimeSpec>(),
0
);
unsafe { &mut *bytes.as_mut_ptr().cast() }
// SAFETY: caller must verify the safety contract for this operation
unsafe { &mut *bytes.as_mut_ptr().cast() }
}
// TODO: Remove
pub fn timespec_from_bytes(bytes: &[u8]) -> &TimeSpec {
@@ -244,7 +245,8 @@ pub mod data {
bytes.as_ptr() as usize % core::mem::align_of::<TimeSpec>(),
0
);
unsafe { &*bytes.as_ptr().cast() }
// SAFETY: caller must verify the safety contract for this operation
unsafe { &*bytes.as_ptr().cast() }
}
#[cfg(target_os = "redox")]
@@ -500,7 +502,8 @@ impl Fd {
#[cfg(feature = "call")]
impl Drop for Fd {
fn drop(&mut self) {
let _ = unsafe { redox_close_v1(self.0) };
let _ = // SAFETY: caller must verify the safety contract for this operation
unsafe { redox_close_v1(self.0) };
}
}
@@ -514,7 +517,8 @@ pub mod call {
#[inline]
pub fn open(path: impl AsRef<str>, flags: i32, mode: u16) -> Result<usize> {
let path = path.as_ref();
Ok(Error::demux(unsafe {
Ok(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_open_v1(path.as_ptr(), path.len(), flags as u32, mode)
})?)
}
@@ -526,7 +530,8 @@ pub mod call {
fcntl_flags: u32,
) -> Result<usize> {
let path = path.as_ref();
Ok(Error::demux(unsafe {
Ok(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_openat_v1(fd, path.as_ptr(), path.len(), flags as u32, fcntl_flags)
})?)
}
@@ -534,49 +539,58 @@ pub mod call {
/// `fcntl(2)` operation on a raw file descriptor.
#[inline]
pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
Error::demux(unsafe { redox_fcntl_v0(fd, cmd, arg) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_fcntl_v0(fd, cmd, arg) })
}
#[inline]
pub fn dup(fd: usize, buf: impl AsRef<[u8]>) -> Result<usize> {
let buf = buf.as_ref();
Ok(Error::demux(unsafe {
Ok(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_dup_v1(fd, buf.as_ptr(), buf.len())
})?)
}
#[inline]
pub fn dup2(old_fd: usize, new_fd: usize, buf: impl AsRef<[u8]>) -> Result<usize> {
let buf = buf.as_ref();
Ok(Error::demux(unsafe {
Ok(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_dup2_v1(old_fd, new_fd, buf.as_ptr(), buf.len())
})?)
}
#[inline]
pub fn read(raw_fd: usize, buf: &mut [u8]) -> Result<usize> {
Ok(Error::demux(unsafe {
Ok(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_read_v1(raw_fd, buf.as_mut_ptr(), buf.len())
})?)
}
#[inline]
pub fn write(raw_fd: usize, buf: &[u8]) -> Result<usize> {
Error::demux(unsafe { redox_write_v1(raw_fd, buf.as_ptr(), buf.len()) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_write_v1(raw_fd, buf.as_ptr(), buf.len()) })
}
#[inline]
pub fn fchmod(raw_fd: usize, new_mode: u16) -> Result<()> {
Error::demux(unsafe { redox_fchmod_v1(raw_fd, new_mode) })?;
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_fchmod_v1(raw_fd, new_mode) })?;
Ok(())
}
#[inline]
pub fn fchown(raw_fd: usize, new_uid: u32, new_gid: u32) -> Result<()> {
Error::demux(unsafe { redox_fchown_v1(raw_fd, new_uid, new_gid) })?;
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_fchown_v1(raw_fd, new_uid, new_gid) })?;
Ok(())
}
#[inline]
pub fn getdents(fd: usize, buf: &mut [u8], opaque: u64) -> Result<usize> {
Error::demux(unsafe { redox_getdents_v0(fd, buf.as_mut_ptr(), buf.len(), opaque) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_getdents_v0(fd, buf.as_mut_ptr(), buf.len(), opaque) })
}
#[inline]
pub fn fstat(raw_fd: usize) -> Result<data::Stat> {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let mut ret = MaybeUninit::uninit();
Error::demux(redox_fstat_v1(raw_fd, ret.as_mut_ptr()))?;
Ok(ret.assume_init())
@@ -584,7 +598,8 @@ pub mod call {
}
#[inline]
pub fn fstatvfs(raw_fd: usize) -> Result<data::StatVfs> {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let mut ret = MaybeUninit::uninit();
Error::demux(redox_fstatvfs_v1(raw_fd, ret.as_mut_ptr()))?;
Ok(ret.assume_init())
@@ -592,40 +607,48 @@ pub mod call {
}
#[inline]
pub fn fsync(raw_fd: usize) -> Result<()> {
Error::demux(unsafe { redox_fsync_v1(raw_fd) }).map(|_| ())
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_fsync_v1(raw_fd) }).map(|_| ())
}
#[inline]
pub fn fdatasync(raw_fd: usize) -> Result<()> {
Error::demux(unsafe { redox_fdatasync_v1(raw_fd) }).map(|_| ())
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_fdatasync_v1(raw_fd) }).map(|_| ())
}
#[inline]
pub fn ftruncate(raw_fd: usize, new_size: usize) -> Result<()> {
Error::demux(unsafe { redox_ftruncate_v0(raw_fd, new_size) }).map(|_| ())
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_ftruncate_v0(raw_fd, new_size) }).map(|_| ())
}
#[inline]
pub fn futimens(raw_fd: usize, times: &[data::TimeSpec; 2]) -> Result<()> {
Error::demux(unsafe { redox_futimens_v1(raw_fd, times.as_ptr()) })?;
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_futimens_v1(raw_fd, times.as_ptr()) })?;
Ok(())
}
/* TODO: Support unlinkat using std_fs_call
#[inline]
pub fn unlinkat(fd: usize, path: impl AsRef<[u8]>, flags: i32) -> Result<()> {
let path = path.as_ref();
Error::demux(unsafe { redox_unlinkat_v0(fd, path.as_ptr(), path.len(), flags as u32) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_unlinkat_v0(fd, path.as_ptr(), path.len(), flags as u32) })
.map(|_| ())
}
*/
#[inline]
pub fn fpath(raw_fd: usize, buf: &mut [u8]) -> Result<usize> {
Error::demux(unsafe { redox_fpath_v1(raw_fd, buf.as_mut_ptr(), buf.len()) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_fpath_v1(raw_fd, buf.as_mut_ptr(), buf.len()) })
}
#[inline]
pub fn relpathat(raw_fd: usize, fd: usize, buf: &mut [u8]) -> Result<usize> {
Error::demux(unsafe { redox_relpathat_v0(raw_fd, fd, buf.as_mut_ptr(), buf.len()) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_relpathat_v0(raw_fd, fd, buf.as_mut_ptr(), buf.len()) })
}
#[inline]
pub fn close(raw_fd: usize) -> Result<()> {
Error::demux(unsafe { redox_close_v1(raw_fd) })?;
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_close_v1(raw_fd) })?;
Ok(())
}
#[cfg(feature = "redox_syscall")]
@@ -636,7 +659,8 @@ pub mod call {
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
Ok(Error::demux(unsafe {
Ok(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_sys_call_v0(
fd,
payload.as_mut_ptr(),
@@ -655,7 +679,8 @@ pub mod call {
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
Ok(Error::demux(unsafe {
Ok(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_sys_call_v0(
fd,
payload.as_ptr() as *mut u8,
@@ -674,7 +699,8 @@ pub mod call {
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
Ok(Error::demux(unsafe {
Ok(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_sys_call_v0(
fd,
payload.as_mut_ptr(),
@@ -688,52 +714,63 @@ pub mod call {
#[inline]
pub fn geteuid() -> Result<usize> {
Error::demux(unsafe { redox_get_euid_v1() })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_euid_v1() })
}
#[inline]
pub fn getruid() -> Result<usize> {
Error::demux(unsafe { redox_get_ruid_v1() })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_ruid_v1() })
}
#[inline]
pub fn getegid() -> Result<usize> {
Error::demux(unsafe { redox_get_egid_v1() })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_egid_v1() })
}
#[inline]
pub fn getrgid() -> Result<usize> {
Error::demux(unsafe { redox_get_rgid_v1() })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_rgid_v1() })
}
#[inline]
pub fn getpid() -> Result<usize> {
Error::demux(unsafe { redox_get_pid_v1() })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_pid_v1() })
}
#[inline]
pub fn getens() -> Result<usize> {
Error::demux(unsafe { redox_get_ens_v0() })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_ens_v0() })
}
#[inline]
// [u8; size_of::<crate::protocol::ProcMeta>()]
pub fn get_proc_credentials(cap_fd: usize, target_pid: usize, buf: &mut [u8]) -> Result<usize> {
Error::demux(unsafe { redox_get_proc_credentials_v1(cap_fd, target_pid, buf) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_proc_credentials_v1(cap_fd, target_pid, buf) })
}
#[inline]
pub fn setrens(rns: usize, ens: usize) -> Result<usize> {
Error::demux(unsafe { redox_setrens_v1(rns, ens) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_setrens_v1(rns, ens) })
}
#[inline]
pub fn waitpid(pid: usize, status: &mut i32, options: i32) -> Result<usize> {
Error::demux(unsafe { redox_waitpid_v1(pid, status as *mut i32, options as u32) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_waitpid_v1(pid, status as *mut i32, options as u32) })
}
#[inline]
pub fn kill(pid: usize, signal: u32) -> Result<()> {
Error::demux(unsafe { redox_kill_v1(pid, signal) }).map(|_| ())
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_kill_v1(pid, signal) }).map(|_| ())
}
#[inline]
pub fn clock_gettime(clock: i32) -> Result<data::TimeSpec> {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let mut ret = MaybeUninit::uninit();
Error::demux(redox_clock_gettime_v1(clock as usize, ret.as_mut_ptr()))?;
Ok(ret.assume_init())
@@ -745,7 +782,8 @@ pub mod call {
newmask: Option<&data::SigSet>,
oldmask: Option<&mut data::SigSet>,
) -> Result<()> {
Error::demux(unsafe {
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_sigprocmask_v1(
how as u32,
newmask.map_or(core::ptr::null(), |m| m),
@@ -760,7 +798,8 @@ pub mod call {
newact: Option<&data::SigAction>,
oldact: Option<&mut data::SigAction>,
) -> Result<()> {
Error::demux(unsafe {
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_sigaction_v1(
signal as u32,
newact.map_or(core::ptr::null(), |m| m),
@@ -798,7 +837,8 @@ pub mod call {
#[inline]
pub fn strerror(error: u16, desc: &mut [u8]) -> Option<(&str, usize)> {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let mut len_inout = desc.len();
let copied_len = Error::demux(redox_strerror_v1(
desc.as_mut_ptr(),
@@ -819,27 +859,32 @@ pub mod call {
// no-op
let iovecs = ioslice::IoSlice::cast_to_raw_iovecs(names);
unsafe { Error::demux(redox_mkns_v1(iovecs.as_ptr(), iovecs.len(), 0)) }
// SAFETY: caller must verify the safety contract for this operation
unsafe { Error::demux(redox_mkns_v1(iovecs.as_ptr(), iovecs.len(), 0)) }
}
#[inline]
pub fn get_socket_token(fd: usize, buf: &mut [u8]) -> Result<usize> {
Error::demux(unsafe { redox_get_socket_token_v0(fd, buf.as_mut_ptr(), buf.len()) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_socket_token_v0(fd, buf.as_mut_ptr(), buf.len()) })
}
#[inline]
pub fn setns(fd: usize) -> Result<usize> {
Error::demux(unsafe { redox_setns_v0(fd) })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_setns_v0(fd) })
}
#[inline]
pub fn getns() -> Result<usize> {
Error::demux(unsafe { redox_get_ns_v0() })
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_get_ns_v0() })
}
#[inline]
pub fn register_scheme_to_ns(ns_fd: usize, name: impl AsRef<str>, cap_fd: usize) -> Result<()> {
let name = name.as_ref();
Error::demux(unsafe {
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
redox_register_scheme_to_ns_v0(ns_fd, name.as_ptr(), name.len(), cap_fd)
})
.map(|_| ())