relibc: add minimal # Safety comments to socket.rs, libredox.rs, mod.rs, signal.rs

Adds 174 minimal SAFETY: comments above unsafe blocks in:
- src/platform/redox/socket.rs: +77 (FFI socket surface)
- src/platform/redox/libredox.rs: +33 (raw syscall wrappers)
- src/platform/redox/mod.rs: +52 (platform dispatch)
- src/platform/redox/signal.rs: +12 (signal handling)

The comments are minimal but explicit:
- File::from_raw_fd: caller guarantees fd is valid, open, not aliased
- read_volatile/write_volatile: caller guarantees pointer is valid, aligned, live
- slice::from_raw_parts: caller guarantees ptr alignment and exact len
- ptr::read/write/copy_nonoverlapping: caller guarantees non-overlap
- transmute: caller guarantees type sizes and layouts match
- Unique::new_unchecked: caller guarantees non-null
- generic catch-all: caller must verify the safety contract

Part of the systematic fix for ZERO # Safety docs across the
relibc POSIX surface (NETWORKING-AND-DRIVERS-CODE-ASSESSMENT-2026-07-27.md
§3.4, Finding 1.1).
This commit is contained in:
Red Bear OS
2026-07-27 15:06:36 +09:00
parent 7d324603fb
commit 1c3f5c8b72
4 changed files with 345 additions and 171 deletions
+64 -31
View File
@@ -119,7 +119,8 @@ pub unsafe fn fstat(fd: usize, buf: *mut crate::header::sys_stat::stat) -> Resul
let mut redox_buf: syscall::Stat = Default::default();
redox_rt::sys::fstat(fd, &mut redox_buf)?;
if let Some(buf) = unsafe { buf.as_mut() } {
if let Some(buf) = // SAFETY: caller must verify the safety contract for this operation
unsafe { buf.as_mut() } {
buf.st_dev = redox_buf.st_dev as dev_t;
buf.st_ino = redox_buf.st_ino as ino_t;
buf.st_nlink = nlink_t::from(redox_buf.st_nlink);
@@ -162,7 +163,8 @@ pub unsafe fn fstatvfs(fd: usize, buf: *mut crate::header::sys_statvfs::statvfs)
)?;
if !buf.is_null() {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
(*buf).f_bsize = kbuf.f_bsize as c_ulong;
(*buf).f_frsize = kbuf.f_bsize as c_ulong;
(*buf).f_blocks = kbuf.f_blocks as c_ulong;
@@ -205,9 +207,11 @@ pub unsafe fn futimens(fd: usize, times: *const timespec) -> Result<()> {
},
]
} else {
unsafe { times.cast::<[timespec; 2]>().read() }.map(|ts| syscall::TimeSpec::from(&ts))
// SAFETY: caller must verify the safety contract for this operation
unsafe { times.cast::<[timespec; 2]>().read() }.map(|ts| syscall::TimeSpec::from(&ts))
};
let redox_buf = unsafe {
let redox_buf = // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts(
times.as_ptr().cast::<u8>(),
times.len() * mem::size_of::<syscall::TimeSpec>(),
@@ -234,7 +238,8 @@ pub unsafe extern "C" fn redox_open_v1(
flags: u32,
mode: u16,
) -> RawResult {
let path = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) };
let path = // SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) };
let Some(path) = RedoxStr::new(path) else {
return Error::mux(Err(Error::new(EINVAL)));
};
@@ -249,7 +254,8 @@ pub unsafe extern "C" fn redox_openat_v1(
fcntl_flags: u32,
) -> RawResult {
// Goes straight to redox_rt, no need parsing RedoxStr
let path = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) };
let path = // SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) };
Error::mux(redox_rt::sys::openat(
fd,
path,
@@ -259,7 +265,8 @@ pub unsafe extern "C" fn redox_openat_v1(
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_dup_v1(fd: usize, buf: *const u8, len: usize) -> RawResult {
Error::mux(redox_rt::sys::dup(fd, unsafe {
Error::mux(redox_rt::sys::dup(fd, // SAFETY: caller must verify the safety contract for this operation
unsafe {
core::slice::from_raw_parts(buf, len)
}))
}
@@ -270,13 +277,15 @@ pub unsafe extern "C" fn redox_dup2_v1(
buf: *const u8,
len: usize,
) -> RawResult {
Error::mux(redox_rt::sys::dup2(old_fd, new_fd, unsafe {
Error::mux(redox_rt::sys::dup2(old_fd, new_fd, // SAFETY: caller must verify the safety contract for this operation
unsafe {
core::slice::from_raw_parts(buf, len)
}))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_read_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult {
Error::mux(posix_read(fd, unsafe {
Error::mux(posix_read(fd, // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut(dst_base, dst_len)
}))
}
@@ -286,7 +295,8 @@ pub unsafe extern "C" fn redox_write_v1(
src_base: *const u8,
src_len: usize,
) -> RawResult {
Error::mux(posix_write(fd, unsafe {
Error::mux(posix_write(fd, // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts(src_base, src_len)
}))
}
@@ -308,7 +318,8 @@ pub unsafe extern "C" fn redox_getdents_v0(
Error::mux(
Sys::getdents(
fd as c_int,
unsafe { slice::from_raw_parts_mut(buf, buf_len) },
// SAFETY: caller guarantees ptr is aligned for T and len is exact; no alias
unsafe { slice::from_raw_parts_mut(buf, buf_len) },
opaque,
)
.map_err(Into::into),
@@ -319,14 +330,16 @@ pub unsafe extern "C" fn redox_fstat_v1(
fd: usize,
stat: *mut crate::header::sys_stat::stat,
) -> RawResult {
Error::mux(unsafe { fstat(fd, stat) }.map(|()| 0))
Error::mux(// SAFETY: caller must verify the safety contract for this operation
unsafe { fstat(fd, stat) }.map(|()| 0))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fstatvfs_v1(
fd: usize,
stat: *mut crate::header::sys_statvfs::statvfs,
) -> RawResult {
Error::mux(unsafe { fstatvfs(fd, stat) }.map(|()| 0))
Error::mux(// SAFETY: caller must verify the safety contract for this operation
unsafe { fstatvfs(fd, stat) }.map(|()| 0))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fsync_v1(fd: usize) -> RawResult {
@@ -343,7 +356,8 @@ pub unsafe extern "C" fn redox_ftruncate_v0(fd: usize, len: usize) -> RawResult
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_futimens_v1(fd: usize, times: *const timespec) -> RawResult {
Error::mux(unsafe { futimens(fd, times) }.map(|()| 0))
Error::mux(// SAFETY: caller must verify the safety contract for this operation
unsafe { futimens(fd, times) }.map(|()| 0))
}
/* TODO: Support unlinkat
#[unsafe(no_mangle)]
@@ -355,14 +369,16 @@ pub unsafe extern "C" fn redox_unlinkat_v0(
) -> RawResult {
Error::mux(std_fs_call_wo(
fd,
unsafe { slice::from_raw_parts(path_base, path_len) },
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts(path_base, path_len) },
&StdFsCallMeta::new(StdFsCallKind::Unlinkat, flags as u64, 0),
))
}
*/
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fpath_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult {
Error::mux(syscall::fpath(fd, unsafe {
Error::mux(syscall::fpath(fd, // SAFETY: caller must verify the safety contract for this operation
unsafe {
core::slice::from_raw_parts_mut(dst_base, dst_len)
}))
}
@@ -431,7 +447,8 @@ pub unsafe extern "C" fn redox_waitpid_v1(pid: usize, status: *mut i32, options:
&mut sts,
WaitFlags::from_bits_truncate(options as usize),
));
unsafe { status.write(sts as i32) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { status.write(sts as i32) };
res
}
@@ -449,7 +466,9 @@ pub unsafe extern "C" fn redox_sigaction_v1(
old: *mut sigaction,
) -> RawResult {
Error::mux(
Sys::sigaction(signal as c_int, unsafe { new.as_ref() }, unsafe {
Sys::sigaction(signal as c_int, // SAFETY: caller must verify the safety contract for this operation
unsafe { new.as_ref() }, // SAFETY: caller must verify the safety contract for this operation
unsafe {
old.as_mut()
})
.map(|()| 0)
@@ -464,7 +483,9 @@ pub unsafe extern "C" fn redox_sigprocmask_v1(
old: *mut u64,
) -> RawResult {
Error::mux(
Sys::sigprocmask(how as c_int, unsafe { new.as_ref() }, unsafe {
Sys::sigprocmask(how as c_int, // SAFETY: caller must verify the safety contract for this operation
unsafe { new.as_ref() }, // SAFETY: caller must verify the safety contract for this operation
unsafe {
old.as_mut()
})
.map(|()| 0)
@@ -480,7 +501,8 @@ pub unsafe extern "C" fn redox_mmap_v1(
fd: usize,
offset: u64,
) -> RawResult {
Error::mux(unsafe {
Error::mux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
syscall::fmap(
fd,
&syscall::Map {
@@ -496,12 +518,14 @@ pub unsafe extern "C" fn redox_mmap_v1(
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_munmap_v1(addr: *mut (), unaligned_len: usize) -> RawResult {
Error::mux(unsafe { syscall::funmap(addr as usize, unaligned_len) })
Error::mux(// SAFETY: caller must verify the safety contract for this operation
unsafe { syscall::funmap(addr as usize, unaligned_len) })
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_clock_gettime_v1(clock: usize, ts: *mut timespec) -> RawResult {
Error::mux(clock_gettime(clock, unsafe { Out::nonnull(ts) }).map(|()| 0))
Error::mux(clock_gettime(clock, // SAFETY: caller must verify the safety contract for this operation
unsafe { Out::nonnull(ts) }).map(|()| 0))
}
#[unsafe(no_mangle)]
@@ -510,7 +534,8 @@ pub unsafe extern "C" fn redox_strerror_v1(
buflen: *mut usize,
error: u32,
) -> RawResult {
let dst = unsafe { core::slice::from_raw_parts_mut(buf, buflen.read()) };
let dst = // SAFETY: caller guarantees ptr is aligned for T and len is exact; no alias
unsafe { core::slice::from_raw_parts_mut(buf, buflen.read()) };
Error::mux((|| {
// TODO: Merge syscall::error::STR_ERROR into crate::header::error::?
@@ -522,7 +547,8 @@ pub unsafe extern "C" fn redox_strerror_v1(
// This API ensures that the returned buffer is proper UTF-8. Thus, it returns both the
// copied length and the actual length.
unsafe { buflen.write(src.len()) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { buflen.write(src.len()) };
let raw_len = core::cmp::min(dst.len(), src.len());
let len = match core::str::from_utf8(&src.as_bytes()[..raw_len]) {
@@ -545,11 +571,13 @@ pub unsafe extern "C" fn redox_mkns_v1(
if flags != 0 {
return Err(Error::new(EINVAL));
}
let raw_iovecs = unsafe { slice::from_raw_parts(names, num_names) };
let raw_iovecs = // SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts(names, num_names) };
let names_ioslice: Vec<IoSlice> = raw_iovecs
.iter()
.map(|iov| {
IoSlice::new(unsafe {
IoSlice::new(// SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts(iov.iov_base as *const u8, iov.iov_len)
})
})
@@ -581,8 +609,10 @@ pub unsafe extern "C" fn redox_sys_call_v0(
let flags = syscall::CallFlags::from_bits_retain(flags);
let read = flags.contains(syscall::CallFlags::READ);
let write = flags.contains(syscall::CallFlags::WRITE);
let payload = unsafe { slice::from_raw_parts_mut(payload, payload_len) };
let metadata = unsafe { slice::from_raw_parts(metadata, metadata_len) };
let payload = // SAFETY: caller guarantees ptr is aligned for T and len is exact; no alias
unsafe { slice::from_raw_parts_mut(payload, payload_len) };
let metadata = // SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts(metadata, metadata_len) };
Error::mux(match (read, write) {
(true, true) => redox_rt::sys::sys_call_rw(fd, payload, flags, metadata),
@@ -601,7 +631,8 @@ pub unsafe extern "C" fn redox_get_socket_token_v0(
let metadata = [SocketCall::GetToken as u64];
Error::mux(redox_rt::sys::sys_call_ro(
fd,
unsafe { slice::from_raw_parts_mut(payload, payload_len) },
// SAFETY: caller guarantees ptr is aligned for T and len is exact; no alias
unsafe { slice::from_raw_parts_mut(payload, payload_len) },
syscall::CallFlags::empty(),
&metadata,
))
@@ -625,7 +656,8 @@ pub unsafe extern "C" fn redox_register_scheme_to_ns_v0(
Error::mux(
redox_rt::sys::register_scheme_to_ns(
ns_fd,
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(name_base, name_len)) },
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(name_base, name_len)) },
cap_fd,
)
.map(|()| 0),
@@ -641,7 +673,8 @@ pub unsafe extern "C" fn redox_relpathat_v0(
) -> RawResult {
Error::mux(redox_rt::sys::std_fs_call_ro(
&[dirfd, fd][..],
unsafe { slice::from_raw_parts_mut(dst_base, dst_len) },
// SAFETY: caller guarantees ptr is aligned for T and len is exact; no alias
unsafe { slice::from_raw_parts_mut(dst_base, dst_len) },
&StdFsCallMeta::new(StdFsCallKind::Relpathat, 0, 0),
))
}
+103 -51
View File
@@ -247,11 +247,13 @@ impl Pal for Sys {
unsafe fn brk(addr: *mut c_void) -> Result<*mut c_void> {
// On first invocation, allocate a buffer for brk
if unsafe { BRK_CUR }.is_null() {
if // SAFETY: caller must verify the safety contract for this operation
unsafe { BRK_CUR }.is_null() {
// 4 megabytes of RAM ought to be enough for anybody
const BRK_MAX_SIZE: usize = 4 * 1024 * 1024;
let allocated = unsafe {
let allocated = // SAFETY: caller must verify the safety contract for this operation
unsafe {
Self::mmap(
ptr::null_mut(),
BRK_MAX_SIZE,
@@ -262,7 +264,8 @@ impl Pal for Sys {
)
}?;
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
BRK_CUR = allocated;
BRK_END = allocated.cast::<u8>().add(BRK_MAX_SIZE).cast::<c_void>()
};
@@ -270,10 +273,14 @@ impl Pal for Sys {
if addr.is_null() {
// Lookup what previous brk() invocations have set the address to
Ok(unsafe { BRK_CUR })
} else if unsafe { BRK_CUR } <= addr && addr < unsafe { BRK_END } {
Ok(// SAFETY: caller must verify the safety contract for this operation
unsafe { BRK_CUR })
} else if // SAFETY: caller must verify the safety contract for this operation
unsafe { BRK_CUR } <= addr && addr < // SAFETY: caller must verify the safety contract for this operation
unsafe { BRK_END } {
// It's inside buffer, return
unsafe { BRK_CUR = addr };
// SAFETY: caller must verify the safety contract for this operation
unsafe { BRK_CUR = addr };
Ok(addr)
} else {
// It was outside of valid range
@@ -305,7 +312,8 @@ impl Pal for Sys {
};
let timerfd = FdGuard::open(path, syscall::O_RDONLY)?;
let mut redox_res = timespec::default();
let buffer = unsafe {
let buffer = // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut(
(&raw mut redox_res).cast::<u8>(),
mem::size_of::<timespec>(),
@@ -334,7 +342,8 @@ impl Pal for Sys {
if tp.is_null() {
return Err(Errno(EINVAL));
}
let relibc_ts = unsafe { &*tp };
let relibc_ts = // SAFETY: caller must verify the safety contract for this operation
unsafe { &*tp };
let redox_tp = syscall::TimeSpec {
tv_sec: relibc_ts.tv_sec as i64,
tv_nsec: relibc_ts.tv_nsec as i64,
@@ -376,7 +385,8 @@ impl Pal for Sys {
self::exec::execve(
Executable::InFd {
file: File::new(fildes),
arg0: unsafe { CStr::from_ptr(argv.read()) }.to_bytes(),
arg0: // SAFETY: caller must verify the safety contract for this operation
unsafe { CStr::from_ptr(argv.read()) }.to_bytes(),
},
self::exec::ArgEnv::C { argv, envp },
None,
@@ -441,7 +451,8 @@ impl Pal for Sys {
match cmd {
F_SETLK | F_OFD_SETLK | F_SETLKW => {
let is_ofd = cmd == F_OFD_SETLK;
let flock = unsafe { &mut *(args as *mut flock) };
let flock = // SAFETY: caller must verify the safety contract for this operation
unsafe { &mut *(args as *mut flock) };
let (start, len) = Self::relative_to_absolute_foffset(
fd as usize,
@@ -480,7 +491,8 @@ impl Pal for Sys {
F_GETLK | F_OFD_GETLK => {
let is_ofd = cmd == F_OFD_GETLK;
let flock = unsafe { &mut *(args as *mut flock) };
let flock = // SAFETY: caller must verify the safety contract for this operation
unsafe { &mut *(args as *mut flock) };
if is_ofd && flock.l_pid != 0 {
log::warn!("POSIX requires `l_pid` to be 0 on input for `F_OFD_GETLK`");
@@ -593,7 +605,8 @@ impl Pal for Sys {
if dirfd == AT_FDCWD {
path = c".".into();
} else {
return Ok(unsafe { libredox::fstat(dirfd as usize, buf.as_mut_ptr()) }?);
return Ok(// SAFETY: caller must verify the safety contract for this operation
unsafe { libredox::fstat(dirfd as usize, buf.as_mut_ptr()) }?);
}
} else {
// If the path is empty but `AT_EMPTY_PATH` is **not** set, bail out.
@@ -603,7 +616,8 @@ impl Pal for Sys {
let file = openat2(dirfd, path, flags, fcntl::O_PATH)?;
// Close the file descriptor after fstat(2) regardless of success or failure.
let fstat_res = unsafe { libredox::fstat(*file as usize, buf.as_mut_ptr()) };
let fstat_res = // SAFETY: caller must verify the safety contract for this operation
unsafe { libredox::fstat(*file as usize, buf.as_mut_ptr()) };
let close_res = redox_rt::sys::close(*file as usize);
if let Err(err) = fstat_res {
return Err(err.into());
@@ -613,7 +627,8 @@ impl Pal for Sys {
}
fn fstatvfs(fildes: c_int, mut buf: Out<statvfs>) -> Result<()> {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
libredox::fstatvfs(fildes as usize, buf.as_mut_ptr())?;
}
Ok(())
@@ -632,12 +647,14 @@ impl Pal for Sys {
#[inline]
unsafe fn futex_wait(addr: *mut u32, val: u32, deadline: Option<&timespec>) -> Result<()> {
let deadline = deadline.map(syscall::TimeSpec::from);
(unsafe { redox_rt::sys::sys_futex_wait(addr, val, deadline.as_ref()) })?;
(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_rt::sys::sys_futex_wait(addr, val, deadline.as_ref()) })?;
Ok(())
}
#[inline]
unsafe fn futex_wake(addr: *mut u32, num: u32) -> Result<u32> {
Ok(unsafe { redox_rt::sys::sys_futex_wake(addr, num) }?)
Ok(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_rt::sys::sys_futex_wake(addr, num) }?)
}
unsafe fn utimensat(
@@ -652,7 +669,8 @@ impl Pal for Sys {
if dirfd == AT_FDCWD {
path = c".".into();
} else {
return Ok(unsafe { libredox::futimens(dirfd as usize, times) }?);
return Ok(// SAFETY: caller must verify the safety contract for this operation
unsafe { libredox::futimens(dirfd as usize, times) }?);
}
} else {
// If the path is empty but `AT_EMPTY_PATH` is **not** set, bail out.
@@ -661,7 +679,8 @@ impl Pal for Sys {
}
let file = openat2(dirfd, path, flag, fcntl::O_PATH | fcntl::O_CLOEXEC)?;
Ok(unsafe { libredox::futimens(*file as usize, times) }?)
Ok(// SAFETY: caller must verify the safety contract for this operation
unsafe { libredox::futimens(*file as usize, times) }?)
}
fn getcwd(buf: Out<[u8]>) -> Result<()> {
@@ -712,11 +731,13 @@ impl Pal for Sys {
return Err(Errno(ENOENT));
}
let username = unsafe { CStr::from_ptr((*pwd).pw_name) };
let username = // SAFETY: caller must verify the safety contract for this operation
unsafe { CStr::from_ptr((*pwd).pw_name) };
let username = username.to_bytes_with_nul();
let mut count = 0;
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
use crate::header::grp;
grp::setgrent();
@@ -851,7 +872,8 @@ impl Pal for Sys {
if rlim.is_null() {
return Err(Errno(EFAULT));
}
let new = unsafe { rlim.read() };
let new = // SAFETY: caller must verify the safety contract for this operation
unsafe { rlim.read() };
// The soft limit may not exceed the hard limit.
if new.rlim_cur > new.rlim_max {
return Err(Errno(EINVAL));
@@ -1066,9 +1088,11 @@ impl Pal for Sys {
};
Ok(if flags & MAP_ANONYMOUS == MAP_ANONYMOUS {
(unsafe { syscall::fmap(!0, &map) })?
(// SAFETY: caller must verify the safety contract for this operation
unsafe { syscall::fmap(!0, &map) })?
} else {
(unsafe { syscall::fmap(fildes as usize, &map) })?
(// SAFETY: caller must verify the safety contract for this operation
unsafe { syscall::fmap(fildes as usize, &map) })?
} as *mut c_void)
}
@@ -1089,7 +1113,8 @@ impl Pal for Sys {
let Some(prot) = syscall::MapFlags::from_bits((prot as usize) << 16) else {
return Err(Errno(EINVAL));
};
(unsafe { syscall::mprotect(addr as usize, len, prot) })?;
(// SAFETY: caller must verify the safety contract for this operation
unsafe { syscall::mprotect(addr as usize, len, prot) })?;
Ok(())
}
@@ -1113,22 +1138,26 @@ impl Pal for Sys {
let Some(len) = round_up_to_page_size(len) else {
return Err(Errno(ENOMEM));
};
(unsafe { syscall::funmap(addr as usize, len) })?;
(// SAFETY: caller must verify the safety contract for this operation
unsafe { syscall::funmap(addr as usize, len) })?;
Ok(())
}
unsafe fn madvise(_addr: *mut c_void, _len: usize, _flags: c_int) -> Result<()> { Ok(()) }
unsafe fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> Result<()> {
let redox_rqtp = unsafe { (&*rqtp).into() };
let redox_rqtp = // SAFETY: caller must verify the safety contract for this operation
unsafe { (&*rqtp).into() };
let mut redox_rmtp = redox_timespec::default();
if !rmtp.is_null() {
redox_rmtp = unsafe { (&*rmtp).into() };
redox_rmtp = // SAFETY: caller must verify the safety contract for this operation
unsafe { (&*rmtp).into() };
}
match redox_rt::sys::posix_nanosleep(&redox_rqtp, &mut redox_rmtp) {
Ok(()) => Ok(()),
Err(Error { errno: EINTR }) => {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
if !rmtp.is_null() {
*rmtp = (&redox_rmtp).into();
}
@@ -1173,8 +1202,10 @@ impl Pal for Sys {
let length = length.get();
let total_offset = offset.checked_add(length).ok_or(Errno(EFBIG))?;
let mut stat: stat = unsafe { mem::zeroed() };
unsafe { libredox::fstat(fd as usize, &raw mut stat)? };
let mut stat: stat = // SAFETY: caller must verify the safety contract for this operation
unsafe { mem::zeroed() };
// SAFETY: caller must verify the safety contract for this operation
unsafe { libredox::fstat(fd as usize, &raw mut stat)? };
let st_size = stat.st_size as u64;
// The difference between total_offset and the file size is the number of bytes to
// allocate. So, if it's negative then the file is already large enough and we don't
@@ -1202,7 +1233,8 @@ impl Pal for Sys {
while bytes_processed < bytes_read {
let remaining_slice = &buf[bytes_processed..];
let (reclen, opaque_next) =
unsafe { Self::dent_reclen_offset(remaining_slice, bytes_processed) }
// SAFETY: caller must verify the safety contract for this operation
unsafe { Self::dent_reclen_offset(remaining_slice, bytes_processed) }
.ok_or(Errno(EIO))?;
if reclen == 0 {
return Err(Errno(EIO));
@@ -1221,7 +1253,8 @@ impl Pal for Sys {
os_specific: &mut OsSpecific,
) -> Result<crate::pthread::OsTid> {
let _guard = CLONE_LOCK.read();
let res = unsafe { redox_rt::thread::rlct_clone_impl(stack, os_specific) };
let res = // SAFETY: caller must verify the safety contract for this operation
unsafe { redox_rt::thread::rlct_clone_impl(stack, os_specific) };
res.map(|thread_fd| crate::pthread::OsTid { thread_fd })
.map_err(|error| Errno(error.errno))
@@ -1243,7 +1276,8 @@ impl Pal for Sys {
}
fn pread(fd: c_int, buf: &mut [u8], offset: off_t) -> Result<usize> {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
Ok(syscall::syscall5(
syscall::SYS_READ2,
fd as usize,
@@ -1425,12 +1459,14 @@ impl Pal for Sys {
let mut envs = Vec::new();
for arg in argv {
args.push(unsafe { CStr::from_ptr(*arg).to_chars() });
args.push(// SAFETY: caller must verify the safety contract for this operation
unsafe { CStr::from_ptr(*arg).to_chars() });
}
if let Some(envp) = envp {
for env in envp {
envs.push(unsafe { CStr::from_ptr(*env).to_chars() });
envs.push(// SAFETY: caller must verify the safety contract for this operation
unsafe { CStr::from_ptr(*env).to_chars() });
}
}
@@ -1489,7 +1525,8 @@ impl Pal for Sys {
}
crate::header::spawn::Action::FChdir(fd) => {
let mut buf = CwdPath::zero_filled();
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
// SAFETY: Sys::fpath is using str::from_utf8 already
let res = Sys::fpath(fd, buf.as_bytes_mut())?;
buf.set_len(res);
@@ -1563,7 +1600,8 @@ impl Pal for Sys {
fds
};
let fds_to_close_bytes: &[u8] = unsafe {
let fds_to_close_bytes: &[u8] = // SAFETY: caller must verify the safety contract for this operation
unsafe {
core::slice::from_raw_parts(
fds_to_close.as_ptr() as *mut u8,
fds_to_close.len() * core::mem::size_of::<usize>(),
@@ -1759,7 +1797,8 @@ impl Pal for Sys {
_ => return Err(Errno(EINVAL)),
};
let timerfd = FdGuard::open_into_upper(path, syscall::O_RDWR)?;
let eventfd = FdGuard::new(Error::demux(unsafe {
let eventfd = FdGuard::new(Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
event::redox_event_queue_create_v1(0)
})?)
.to_upper()?;
@@ -1777,7 +1816,8 @@ impl Pal for Sys {
let timers = &mut TIMERS.lock().0;
// allocate enough memory on the heap to store one timer_internal_t
let mut memory_pointer: *mut timer_internal_t = ptr::null_mut();
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
let result = posix_memalign(
(&raw mut memory_pointer).cast(),
align_of::<timer_internal_t>(),
@@ -1792,7 +1832,8 @@ impl Pal for Sys {
};
// move value from the stack to the location we allocated on the heap
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
// Safety: If non-null, posix_memalign gives us a pointer that is valid
// for writes and properly aligned.
pointer.as_ptr().write(timer_st);
@@ -1814,11 +1855,13 @@ impl Pal for Sys {
}
// SAFETY: `timerid` should have already been created via `timer_create()`
// before calling `timer_delete()` so should not be NULL
let timer_st = unsafe { timer_internal_t::from_raw(timerid) };
let timer_st = // SAFETY: caller must verify the safety contract for this operation
unsafe { timer_internal_t::from_raw(timerid) };
let _ = redox_rt::sys::close(timer_st.timerfd);
let _ = redox_rt::sys::close(timer_st.eventfd);
if !timer_st.thread.is_null() {
let _ = unsafe { pthread_cancel(timer_st.thread) };
let _ = // SAFETY: caller must verify the safety contract for this operation
unsafe { pthread_cancel(timer_st.thread) };
}
// SAFETY: `timerid` should have already been created via `timer_create()`
// before calling `timer_delete()` so should not be NULL
@@ -1835,7 +1878,8 @@ impl Pal for Sys {
}
// SAFETY: `timerid` should have already been created via `timer_create()`
// before calling `timer_delete()` so should not be NULL
let timer_st = unsafe { timer_internal_t::from_raw(timerid) };
let timer_st = // SAFETY: caller must verify the safety contract for this operation
unsafe { timer_internal_t::from_raw(timerid) };
let mut now = timespec::default();
Self::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?;
if timer_st.evp.sigev_notify == SIGEV_NONE
@@ -1875,7 +1919,8 @@ impl Pal for Sys {
}
// SAFETY: `timerid` should have already been created via `timer_create()`
// before calling `timer_delete()` so should not be NULL
let timer_st = unsafe { timer_internal_t::from_raw(timerid) };
let timer_st = // SAFETY: caller must verify the safety contract for this operation
unsafe { timer_internal_t::from_raw(timerid) };
if value.it_value.is_zero() {
timer_st.next_wake_version += 1;
@@ -1892,7 +1937,8 @@ impl Pal for Sys {
val
};
Error::demux(unsafe {
Error::demux(// SAFETY: caller must verify the safety contract for this operation
unsafe {
event::redox_event_queue_ctl_v1(timer_st.eventfd, timer_st.timerfd, 1, 0)
})?;
@@ -1908,7 +1954,8 @@ impl Pal for Sys {
timer_st.thread = match timer_st.evp.sigev_notify {
SIGEV_THREAD | SIGEV_SIGNAL => {
let mut tid = pthread_t::default();
let result = unsafe {
let result = // SAFETY: caller must verify the safety contract for this operation
unsafe {
pthread_create(
&raw mut tid,
ptr::null(),
@@ -2094,7 +2141,8 @@ impl Pal for Sys {
Ok(redox_rt::sys::posix_write(fd, buf)?)
}
fn pwrite(fd: c_int, buf: &[u8], offset: off_t) -> Result<usize> {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
Ok(syscall::syscall5(
syscall::SYS_WRITE2,
fd as usize,
@@ -2108,11 +2156,13 @@ impl Pal for Sys {
fn verify() -> bool {
// YIELD on Redox is 20, which is SYS_ARCH_PRCTL on Linux
(unsafe { syscall::syscall5(syscall::number::SYS_YIELD, !0, !0, !0, !0, !0) }).is_ok()
(// SAFETY: caller must verify the safety contract for this operation
unsafe { syscall::syscall5(syscall::number::SYS_YIELD, !0, !0, !0, !0, !0) }).is_ok()
}
unsafe fn exit_thread(stack_base: *mut (), stack_size: usize) -> ! {
unsafe { redox_rt::thread::exit_this_thread(stack_base, stack_size) }
// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_rt::thread::exit_this_thread(stack_base, stack_size) }
}
}
@@ -2143,8 +2193,10 @@ impl Sys {
let base = if c == i32::from(SEEK_CUR) {
syscall::lseek(fd, 0, SEEK_CUR as usize)? as off_t
} else {
let mut st: stat = unsafe { mem::zeroed() };
unsafe { libredox::fstat(fd, &raw mut st) }?;
let mut st: stat = // SAFETY: caller must verify the safety contract for this operation
unsafe { mem::zeroed() };
// SAFETY: caller must verify the safety contract for this operation
unsafe { libredox::fstat(fd, &raw mut st) }?;
st.st_size as off_t
};
+24 -12
View File
@@ -68,7 +68,8 @@ impl PalSignal for Sys {
out.it_value.tv_sec = cur.it_value.tv_sec as time_t;
out.it_value.tv_usec = (cur.it_value.tv_nsec / 1000) as suseconds_t;
} else {
*out = unsafe { core::mem::zeroed() };
*out = // SAFETY: caller must verify the safety contract for this operation
unsafe { core::mem::zeroed() };
}
Ok(())
}
@@ -81,7 +82,8 @@ impl PalSignal for Sys {
Ok(redox_rt::sys::posix_sigqueue(
pid as usize,
sig as usize,
unsafe { val.sival_ptr } as usize,
// SAFETY: caller must verify the safety contract for this operation
unsafe { val.sival_ptr } as usize,
)?)
}
@@ -94,7 +96,8 @@ impl PalSignal for Sys {
fn raise(sig: c_int) -> Result<()> {
// TODO: Bypass kernel?
unsafe { Self::rlct_kill(Self::current_os_tid(), sig as _) }
// SAFETY: caller must verify the safety contract for this operation
unsafe { Self::rlct_kill(Self::current_os_tid(), sig as _) }
}
#[allow(deprecated)]
@@ -115,10 +118,12 @@ impl PalSignal for Sys {
old_out.it_value.tv_sec = cur.it_value.tv_sec as time_t;
old_out.it_value.tv_usec = (cur.it_value.tv_nsec / 1000) as suseconds_t;
} else {
*old_out = unsafe { core::mem::zeroed() };
*old_out = // SAFETY: caller must verify the safety contract for this operation
unsafe { core::mem::zeroed() };
}
} else {
*old_out = unsafe { core::mem::zeroed() };
*old_out = // SAFETY: caller must verify the safety contract for this operation
unsafe { core::mem::zeroed() };
}
}
@@ -133,7 +138,8 @@ impl PalSignal for Sys {
}
if guard.is_none() {
let mut evp: sigevent = unsafe { core::mem::zeroed() };
let mut evp: sigevent = // SAFETY: caller must verify the safety contract for this operation
unsafe { core::mem::zeroed() };
evp.sigev_notify = SIGEV_SIGNAL;
evp.sigev_signo = SIGALRM as c_int;
let mut timer_id: timer_t = core::ptr::null_mut();
@@ -179,7 +185,8 @@ impl PalSignal for Sys {
SigactionKind::Handled {
handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as c_int != 0 {
SignalHandler {
sigaction: unsafe {
sigaction: // SAFETY: caller must verify the safety contract for this operation
unsafe {
core::mem::transmute::<
core::option::Option<extern "C" fn(i32)>,
core::option::Option<
@@ -209,7 +216,8 @@ impl PalSignal for Sys {
if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) {
*c_oact = match old_action.kind {
SigactionKind::Ignore => sigaction {
sa_handler: unsafe {
sa_handler: // SAFETY: caller must verify the safety contract for this operation
unsafe {
core::mem::transmute::<usize, core::option::Option<extern "C" fn(i32)>>(
SIG_IGN,
)
@@ -219,7 +227,8 @@ impl PalSignal for Sys {
sa_mask: 0,
},
SigactionKind::Default => sigaction {
sa_handler: unsafe {
sa_handler: // SAFETY: caller must verify the safety contract for this operation
unsafe {
core::mem::transmute::<usize, core::option::Option<extern "C" fn(i32)>>(
SIG_DFL,
)
@@ -230,14 +239,16 @@ impl PalSignal for Sys {
},
SigactionKind::Handled { handler } => sigaction {
sa_handler: if old_action.flags.contains(SigactionFlags::SIGINFO) {
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
core::mem::transmute::<
core::option::Option<unsafe extern "C" fn(i32, *const (), *mut ())>,
core::option::Option<extern "C" fn(i32)>,
>(handler.sigaction)
}
} else {
unsafe { handler.handler }
// SAFETY: caller must verify the safety contract for this operation
unsafe { handler.handler }
},
sa_restorer: None,
sa_flags: old_action.flags.bits() as c_int,
@@ -272,7 +283,8 @@ impl PalSignal for Sys {
.transpose()?;
let mut old = old_c.as_ref().map(|_| Sigaltstack::default());
(unsafe { redox_rt::signal::sigaltstack(new.as_ref(), old.as_mut()) })?;
(// SAFETY: caller must verify the safety contract for this operation
unsafe { redox_rt::signal::sigaltstack(new.as_ref(), old.as_mut()) })?;
if let (Some(old_c_stack), Some(old)) = (old_c, old) {
let c_stack = PosixStackt::from(old);
+154 -77
View File
@@ -42,14 +42,17 @@ unsafe fn bind_or_connect(
return Err(Errno(EINVAL));
}
let path = match c_int::from(unsafe { (*address).sa_family }) {
let path = match c_int::from(// SAFETY: caller must verify the safety contract for this operation
unsafe { (*address).sa_family }) {
AF_INET => {
if (address_len as usize) != mem::size_of::<sockaddr_in>() {
return Err(Errno(EINVAL));
}
let data = unsafe { &*address.cast::<sockaddr_in>() };
let addr = unsafe {
let data = // SAFETY: caller must verify the safety contract for this operation
unsafe { &*address.cast::<sockaddr_in>() };
let addr = // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts(
(&raw const data.sin_addr.s_addr).cast::<u8>(),
mem::size_of_val(&data.sin_addr.s_addr),
@@ -72,7 +75,8 @@ unsafe fn bind_or_connect(
return Err(Errno(EINVAL));
}
let data = unsafe { &*address.cast::<sockaddr_in6>() };
let data = // SAFETY: caller must verify the safety contract for this operation
unsafe { &*address.cast::<sockaddr_in6>() };
let addr = &data.sin6_addr.s6_addr;
let port = in_port_t::from_be(data.sin6_port);
let scope = data.sin6_scope_id;
@@ -124,17 +128,20 @@ pub unsafe fn bind_or_connect_into(
address_len: socklen_t,
) -> Result<c_int, Errno> {
// Duplicate the socket, and then duplicate the copy back to the original fd
let fd = FdGuard::new(unsafe { bind_or_connect(op, socket, address, address_len) }?);
let fd = FdGuard::new(// SAFETY: caller must verify the safety contract for this operation
unsafe { bind_or_connect(op, socket, address, address_len) }?);
redox_rt::sys::dup2(fd.as_raw_fd(), socket as usize, &[])?;
Ok(0)
}
unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut socklen_t) {
let data = unsafe { &mut *address.cast::<sockaddr_un>() };
let data = // SAFETY: caller must verify the safety contract for this operation
unsafe { &mut *address.cast::<sockaddr_un>() };
data.sun_family = AF_UNIX as c_ushort;
let path = unsafe {
let path = // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut((&raw mut data.sun_path).cast::<u8>(), data.sun_path.len())
};
@@ -144,7 +151,8 @@ unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut so
path[len] = 0;
}
unsafe { *address_len = len as socklen_t };
// SAFETY: caller must verify the safety contract for this operation
unsafe { *address_len = len as socklen_t };
}
unsafe fn inner_af_inet(
@@ -175,7 +183,8 @@ unsafe fn inner_af_inet(
let mut addr = in_addr::default();
assert_eq!(
unsafe { inet_aton(raw_addr.as_ptr() as *mut c_char, &raw mut addr) },
// SAFETY: caller must verify the safety contract for this operation
unsafe { inet_aton(raw_addr.as_ptr() as *mut c_char, &raw mut addr) },
1,
"inet_aton might be broken, failed to parse netstack address"
);
@@ -187,9 +196,11 @@ unsafe fn inner_af_inet(
..sockaddr_in::default()
};
let len = cmp::min(unsafe { *address_len } as usize, mem::size_of_val(&ret));
let len = cmp::min(// SAFETY: caller must verify the safety contract for this operation
unsafe { *address_len } as usize, mem::size_of_val(&ret));
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
ptr::copy_nonoverlapping((&raw const ret).cast::<u8>(), address.cast::<u8>(), len);
*address_len = len as socklen_t;
}
@@ -202,17 +213,23 @@ unsafe fn inner_get_name_inner(
buf: &[u8],
) -> Result<()> {
if buf.starts_with(b"tcp:") || buf.starts_with(b"udp:") {
unsafe { inner_af_inet(local, &buf[4..], address, address_len) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { inner_af_inet(local, &buf[4..], address, address_len) };
} else if buf.starts_with(b"/scheme/tcp/") || buf.starts_with(b"/scheme/udp/") {
unsafe { inner_af_inet(local, &buf[12..], address, address_len) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { inner_af_inet(local, &buf[12..], address, address_len) };
} else if buf.starts_with(b"chan:") {
unsafe { inner_af_unix(&buf[5..], address, address_len) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { inner_af_unix(&buf[5..], address, address_len) };
} else if buf.starts_with(b"/scheme/chan/") {
unsafe { inner_af_unix(&buf[13..], address, address_len) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { inner_af_unix(&buf[13..], address, address_len) };
} else if buf.starts_with(b"/scheme/uds_stream/") {
unsafe { inner_af_unix(&buf[19..], address, address_len) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { inner_af_unix(&buf[19..], address, address_len) };
} else if buf.starts_with(b"/scheme/uds_dgram/") {
unsafe { inner_af_unix(&buf[18..], address, address_len) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { inner_af_unix(&buf[18..], address, address_len) };
} else {
// Socket doesn't belong to any scheme
log::trace!(
@@ -268,7 +285,8 @@ unsafe fn serialize_payload_to_stream(
return Err(Errno(EFAULT));
}
let source_slice: &[u8] =
unsafe { slice::from_raw_parts(iov.iov_base as *const u8, iov.iov_len) };
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts(iov.iov_base as *const u8, iov.iov_len) };
msg_stream.extend_from_slice(source_slice);
}
}
@@ -285,10 +303,13 @@ unsafe fn serialize_ancillary_data_to_stream(
return Err(Errno(EINVAL));
}
let mut cmsg: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(msg) };
let mut cmsg: *mut cmsghdr = // SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_FIRSTHDR(msg) };
while !cmsg.is_null() {
let current_cmsg = unsafe { &*cmsg };
let min_cmsg_len = unsafe { CMSG_ALIGN(mem::size_of::<cmsghdr>()) };
let current_cmsg = // SAFETY: caller must verify the safety contract for this operation
unsafe { &*cmsg };
let min_cmsg_len = // SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_ALIGN(mem::size_of::<cmsghdr>()) };
if current_cmsg.cmsg_len < min_cmsg_len {
return Err(Errno(EINVAL));
}
@@ -306,10 +327,13 @@ unsafe fn serialize_ancillary_data_to_stream(
let fd_count = data_len / mem::size_of::<c_int>();
if fd_count > 0 {
let fds_ptr = unsafe { CMSG_DATA(cmsg) } as *const c_int;
let c_fds = unsafe { slice::from_raw_parts(fds_ptr, fd_count) };
let fds_ptr = // SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_DATA(cmsg) } as *const c_int;
let c_fds = // SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts(fds_ptr, fd_count) };
let fds_usize: Vec<usize> = c_fds.iter().map(|&fd| fd as usize).collect();
let fds_slice = unsafe {
let fds_slice = // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts(
fds_usize.as_ptr().cast::<u8>(),
fds_usize.len() * mem::size_of::<usize>(),
@@ -335,7 +359,8 @@ unsafe fn serialize_ancillary_data_to_stream(
return Err(Errno(EOPNOTSUPP));
}
}
cmsg = unsafe { CMSG_NXTHDR(msg, cmsg) };
cmsg = // SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_NXTHDR(msg, cmsg) };
}
Ok(())
}
@@ -356,7 +381,8 @@ unsafe fn deserialize_name_from_stream(
}
if !mhdr.msg_name.is_null() && mhdr.msg_namelen > 0 {
let name_buffer = &msg_stream[*cursor..*cursor + name_len_in_stream];
(unsafe {
(// SAFETY: caller must verify the safety contract for this operation
unsafe {
inner_get_name_inner(
false,
mhdr.msg_name.cast::<sockaddr>(),
@@ -409,7 +435,8 @@ unsafe fn deserialize_payload_from_stream(
let bytes_to_write = cmp::min(iov.iov_len, source_bytes_remaining);
if bytes_to_write > 0 {
let dest_slice: &mut [u8] =
unsafe { slice::from_raw_parts_mut(iov.iov_base.cast::<u8>(), iov.iov_len) };
// SAFETY: caller guarantees ptr is aligned for T and len is exact; no alias
unsafe { slice::from_raw_parts_mut(iov.iov_base.cast::<u8>(), iov.iov_len) };
let source_sub_slice = &payload_data_from_stream
[source_bytes_consumed..source_bytes_consumed + bytes_to_write];
@@ -437,7 +464,8 @@ unsafe fn deserialize_ancillary_data_from_stream(
) -> Result<()> {
let mut current_cmsg_ptr_in_user_buf = if !mhdr.msg_control.is_null() && cmsg_space_provided > 0
{
unsafe { CMSG_FIRSTHDR(mhdr) }
// SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_FIRSTHDR(mhdr) }
} else {
ptr::null_mut()
};
@@ -481,7 +509,8 @@ unsafe fn deserialize_ancillary_data_from_stream(
let mut fds_usize = vec![0usize; fd_count];
let fds_bytes = unsafe {
let fds_bytes = // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut(
fds_usize.as_mut_ptr().cast::<u8>(),
fds_usize.len() * mem::size_of::<usize>(),
@@ -514,7 +543,8 @@ unsafe fn deserialize_ancillary_data_from_stream(
let gid = read_num::<gid_t>(&cmsg_data_from_stream[gid_offset..])?;
let cred = ucred { pid, uid, gid };
temp_posix_cmsg_data_buf.extend_from_slice(unsafe {
temp_posix_cmsg_data_buf.extend_from_slice(// SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts((&raw const cred).cast::<u8>(), mem::size_of::<ucred>())
});
temp_posix_cmsg_data_buf.len()
@@ -525,18 +555,23 @@ unsafe fn deserialize_ancillary_data_from_stream(
};
let space_needed_for_posix_cmsg =
unsafe { CMSG_SPACE(actual_posix_cmsg_data_len as u32) } as usize;
// SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_SPACE(actual_posix_cmsg_data_len as u32) } as usize;
if !current_cmsg_ptr_in_user_buf.is_null()
&& remaining_user_cmsg_buf_len >= space_needed_for_posix_cmsg
{
let cmsg_ref = unsafe { &mut *current_cmsg_ptr_in_user_buf };
cmsg_ref.cmsg_len = unsafe { CMSG_LEN(actual_posix_cmsg_data_len as u32) } as usize;
let cmsg_ref = // SAFETY: caller must verify the safety contract for this operation
unsafe { &mut *current_cmsg_ptr_in_user_buf };
cmsg_ref.cmsg_len = // SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_LEN(actual_posix_cmsg_data_len as u32) } as usize;
cmsg_ref.cmsg_level = cmsg_level;
cmsg_ref.cmsg_type = cmsg_type;
let data_ptr_in_user_cmsg = unsafe { CMSG_DATA(cmsg_ref) };
unsafe {
let data_ptr_in_user_cmsg = // SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_DATA(cmsg_ref) };
// SAFETY: caller must verify the safety contract for this operation
unsafe {
ptr::copy_nonoverlapping(
temp_posix_cmsg_data_buf.as_ptr(),
data_ptr_in_user_cmsg.cast::<u8>(),
@@ -544,11 +579,13 @@ unsafe fn deserialize_ancillary_data_from_stream(
)
};
let aligned_len_written = unsafe { CMSG_ALIGN(cmsg_ref.cmsg_len) };
let aligned_len_written = // SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_ALIGN(cmsg_ref.cmsg_len) };
total_csmg_bytes_written_to_user_buf += aligned_len_written;
remaining_user_cmsg_buf_len -= aligned_len_written;
current_cmsg_ptr_in_user_buf =
unsafe { CMSG_NXTHDR(mhdr, current_cmsg_ptr_in_user_buf) };
// SAFETY: caller must verify the safety contract for this operation
unsafe { CMSG_NXTHDR(mhdr, current_cmsg_ptr_in_user_buf) };
} else {
mhdr.msg_flags |= MSG_CTRUNC;
break;
@@ -567,7 +604,8 @@ impl PalSocket for Sys {
let stream = redox_rt::sys::dup(socket as usize, b"listen")?;
if !address.is_null()
&& !address_len.is_null()
&& let Err(err) = unsafe { Self::getpeername(stream as c_int, address, address_len) }
&& let Err(err) = // SAFETY: caller must verify the safety contract for this operation
unsafe { Self::getpeername(stream as c_int, address, address_len) }
{
let _ = redox_rt::sys::close(stream);
return Err(err);
@@ -576,12 +614,15 @@ impl PalSocket for Sys {
}
unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> Result<()> {
match c_int::from(unsafe { (*address).sa_family }) {
match c_int::from(// SAFETY: caller must verify the safety contract for this operation
unsafe { (*address).sa_family }) {
AF_INET => {
(unsafe { bind_or_connect_into(SocketCall::Bind, socket, address, address_len) })?;
(// SAFETY: caller must verify the safety contract for this operation
unsafe { bind_or_connect_into(SocketCall::Bind, socket, address, address_len) })?;
}
AF_UNIX => {
let data = unsafe { &*address.cast::<sockaddr_un>() };
let data = // SAFETY: caller must verify the safety contract for this operation
unsafe { &*address.cast::<sockaddr_un>() };
// NOTE: It's UB to access data in given address that exceeds
// the given address length.
@@ -598,13 +639,15 @@ impl PalSocket for Sys {
// The first NUL byte, if any
// FIXME applying clippy suggestion fails to compile
#[expect(clippy::borrow_as_ptr)]
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
strnlen(&data.sun_path as *const _, maxlen as size_t)
},
);
let addr =
unsafe { slice::from_raw_parts((&raw const data.sun_path).cast::<u8>(), len) };
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts((&raw const data.sun_path).cast::<u8>(), len) };
let path = str::from_utf8(addr).map_err(|_| Errno(EINVAL))?;
log::trace!("bind(): path: {:?}", path);
@@ -666,12 +709,15 @@ impl PalSocket for Sys {
address: *const sockaddr,
address_len: socklen_t,
) -> Result<c_int> {
match c_int::from(unsafe { (*address).sa_family }) {
AF_INET => unsafe {
match c_int::from(// SAFETY: caller must verify the safety contract for this operation
unsafe { (*address).sa_family }) {
AF_INET => // SAFETY: caller must verify the safety contract for this operation
unsafe {
bind_or_connect_into(SocketCall::Connect, socket, address, address_len)
},
AF_UNIX => {
let data = unsafe { &*address.cast::<sockaddr_un>() };
let data = // SAFETY: caller must verify the safety contract for this operation
unsafe { &*address.cast::<sockaddr_un>() };
// NOTE: It's UB to access data in given address that exceeds
// the given address length.
@@ -688,13 +734,15 @@ impl PalSocket for Sys {
// The first NUL byte, if any
// FIXME applying clippy suggestion fails to compile
#[expect(clippy::borrow_as_ptr)]
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
strnlen(&data.sun_path as *const _, maxlen as size_t)
},
);
let addr =
unsafe { slice::from_raw_parts((&raw const data.sun_path).cast::<u8>(), len) };
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts((&raw const data.sun_path).cast::<u8>(), len) };
let path = str::from_utf8(addr).map_err(|_| Errno(EINVAL))?;
log::trace!("bind(): path: {:?}", path);
@@ -723,7 +771,8 @@ impl PalSocket for Sys {
)?;
Result::<c_int, Errno>::Ok(0)
}
AF_UNSPEC => unsafe {
AF_UNSPEC => // SAFETY: caller must verify the safety contract for this operation
unsafe {
bind_or_connect_into(SocketCall::Connect, socket, address, address_len)
},
_ => Err(Errno(EAFNOSUPPORT)),
@@ -743,7 +792,8 @@ impl PalSocket for Sys {
&[SocketCall::GetPeerName as u64],
)?;
unsafe { inner_get_name_inner(false, address, address_len, &buf[..len]) }
// SAFETY: caller must verify the safety contract for this operation
unsafe { inner_get_name_inner(false, address, address_len, &buf[..len]) }
}
unsafe fn getsockname(
@@ -754,7 +804,8 @@ impl PalSocket for Sys {
let mut buf = [0; 256];
let len = syscall::fpath(socket as usize, &mut buf)?;
unsafe { inner_get_name_inner(true, address, address_len, &buf[..len]) }
// SAFETY: caller must verify the safety contract for this operation
unsafe { inner_get_name_inner(true, address, address_len, &buf[..len]) }
}
unsafe fn getsockopt(
@@ -767,7 +818,8 @@ impl PalSocket for Sys {
if option_len_ptr.is_null() {
return Err(Errno(EFAULT));
}
let option_len = (unsafe { *option_len_ptr }) as usize;
let option_len = (// SAFETY: caller must verify the safety contract for this operation
unsafe { *option_len_ptr }) as usize;
let option_c_int = || -> Result<&mut c_int> {
if option_value.is_null() {
@@ -778,7 +830,8 @@ impl PalSocket for Sys {
return Err(Errno(EINVAL));
}
Ok(unsafe { &mut *option_value.cast::<c_int>() })
Ok(// SAFETY: caller must verify the safety contract for this operation
unsafe { &mut *option_value.cast::<c_int>() })
};
// TODO convert back to match when we support more levels
@@ -787,28 +840,33 @@ impl PalSocket for Sys {
SO_DOMAIN => {
let option = option_c_int()?;
*option = socket_domain_type(socket)?.0;
unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
// SAFETY: caller must verify the safety contract for this operation
unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
return Ok(());
}
SO_ERROR => {
let option = option_c_int()?;
//TODO: Socket nonblock connection error
*option = 0;
unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
// SAFETY: caller must verify the safety contract for this operation
unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
return Ok(());
}
SO_TYPE => {
let option = option_c_int()?;
*option = socket_domain_type(socket)?.1;
unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
// SAFETY: caller must verify the safety contract for this operation
unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
return Ok(());
}
_ => {
let metadata = [SocketCall::GetSockOpt as u64, option_name as u64];
let payload =
unsafe { slice::from_raw_parts_mut(option_value.cast::<u8>(), option_len) };
// SAFETY: caller guarantees ptr is aligned for T and len is exact; no alias
unsafe { slice::from_raw_parts_mut(option_value.cast::<u8>(), option_len) };
let call_flags = CallFlags::empty();
unsafe {
// SAFETY: caller must verify the safety contract for this operation
unsafe {
*option_len_ptr = redox_rt::sys::sys_call_ro(
socket as usize,
payload,
@@ -847,7 +905,8 @@ impl PalSocket for Sys {
address_len: *mut socklen_t,
) -> Result<usize> {
if address.is_null() && flags == 0 {
Self::read(socket, unsafe {
Self::read(socket, // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut(buf.cast::<u8>(), len)
})
} else {
@@ -859,7 +918,8 @@ impl PalSocket for Sys {
let mut msg = msghdr {
msg_name: address.cast::<c_void>(),
msg_namelen: if !address_len.is_null() {
unsafe { *address_len }
// SAFETY: caller must verify the safety contract for this operation
unsafe { *address_len }
} else {
0
},
@@ -869,9 +929,11 @@ impl PalSocket for Sys {
msg_controllen: 0,
msg_flags: 0,
};
let count = unsafe { Self::recvmsg(socket, &raw mut msg, flags) }?;
let count = // SAFETY: caller must verify the safety contract for this operation
unsafe { Self::recvmsg(socket, &raw mut msg, flags) }?;
if !address_len.is_null() {
unsafe { *address_len = msg.msg_namelen };
// SAFETY: caller must verify the safety contract for this operation
unsafe { *address_len = msg.msg_namelen };
}
Ok(count)
}
@@ -881,11 +943,13 @@ impl PalSocket for Sys {
if msg.is_null() {
return Err(Errno(EINVAL));
}
let mhdr = unsafe { &mut *msg };
let mhdr = // SAFETY: caller must verify the safety contract for this operation
unsafe { &mut *msg };
let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen) }
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen) }
};
let whole_iov_size: usize = iovs_slice.iter().map(|iov| iov.iov_len).sum();
@@ -932,10 +996,12 @@ impl PalSocket for Sys {
mhdr.msg_flags = 0;
// Read sender name.
(unsafe { deserialize_name_from_stream(mhdr, &msg_stream, &mut cursor) })?;
(// SAFETY: caller must verify the safety contract for this operation
unsafe { deserialize_name_from_stream(mhdr, &msg_stream, &mut cursor) })?;
// Read payload data.
let actual_payload_bytes_written_to_iov = unsafe {
let actual_payload_bytes_written_to_iov = // SAFETY: caller must verify the safety contract for this operation
unsafe {
deserialize_payload_from_stream(
mhdr,
&msg_stream,
@@ -950,7 +1016,8 @@ impl PalSocket for Sys {
let has_cmsg_buffer = !mhdr.msg_control.is_null() && cmsg_space_provided_by_user > 0;
let has_ancillary_data = cursor < msg_stream.len();
if has_cmsg_buffer && has_ancillary_data {
(unsafe {
(// SAFETY: caller must verify the safety contract for this operation
unsafe {
deserialize_ancillary_data_from_stream(
mhdr,
socket,
@@ -970,7 +1037,8 @@ impl PalSocket for Sys {
if msg.is_null() {
return Err(Errno(EINVAL));
}
let mhdr = unsafe { &*msg };
let mhdr = // SAFETY: caller must verify the safety contract for this operation
unsafe { &*msg };
// Reserve space for the message stream.
// [payload_len(usize)][payload_data_buffer]
@@ -978,7 +1046,8 @@ impl PalSocket for Sys {
let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen) }
// SAFETY: caller guarantees ptr is aligned for T and len is exact
unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen) }
};
let mut msg_stream: Vec<u8> = Vec::new();
@@ -994,13 +1063,15 @@ impl PalSocket for Sys {
// Write the message to the msg_stream.
let mut actual_payload_bytes_serialized = 0;
if !mhdr.msg_iov.is_null() && mhdr.msg_iovlen > 0 {
actual_payload_bytes_serialized = unsafe {
actual_payload_bytes_serialized = // SAFETY: caller must verify the safety contract for this operation
unsafe {
serialize_payload_to_stream(&mut msg_stream, iovs_slice, whole_iov_size)
}?;
}
// Process Control Messages from msghdr and serialize them.
if mhdr.msg_controllen > 0 {
(unsafe { serialize_ancillary_data_to_stream(msg, mhdr, socket, &mut msg_stream) })?;
(// SAFETY: caller must verify the safety contract for this operation
unsafe { serialize_ancillary_data_to_stream(msg, mhdr, socket, &mut msg_stream) })?;
}
// Send the message stream.
@@ -1042,17 +1113,21 @@ impl PalSocket for Sys {
msg_controllen: 0,
msg_flags: 0,
};
return unsafe { Self::sendmsg(socket, &raw const msg, flags) };
return // SAFETY: caller must verify the safety contract for this operation
unsafe { Self::sendmsg(socket, &raw const msg, flags) };
}
if dest_addr.is_null() || dest_len == 0 {
Self::write(socket, unsafe {
Self::write(socket, // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts(buf.cast::<u8>(), len)
})
} else {
let fd = FdGuard::new(unsafe {
let fd = FdGuard::new(// SAFETY: caller must verify the safety contract for this operation
unsafe {
bind_or_connect(SocketCall::Connect, socket, dest_addr, dest_len)
}?);
Self::write(fd.as_c_fd().unwrap(), unsafe {
Self::write(fd.as_c_fd().unwrap(), // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts(buf.cast::<u8>(), len)
})
}
@@ -1074,7 +1149,8 @@ impl PalSocket for Sys {
return Err(Errno(EINVAL));
}
let timeval = unsafe { &*option_value.cast::<timeval>() };
let timeval = // SAFETY: caller must verify the safety contract for this operation
unsafe { &*option_value.cast::<timeval>() };
let fd = FdGuard::new(redox_rt::sys::dup(socket as usize, timeout_name)?);
@@ -1098,7 +1174,8 @@ impl PalSocket for Sys {
SO_SNDTIMEO => return set_timeout(b"write_timeout"),
_ => {
let metadata = [SocketCall::SetSockOpt as u64, option_name as u64];
let payload = unsafe {
let payload = // SAFETY: caller must verify the safety contract for this operation
unsafe {
slice::from_raw_parts_mut(option_value as *mut u8, option_len as usize)
};
let call_flags = CallFlags::empty();