diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index 91be7a78ef..1a17771aad 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -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::(), times.len() * mem::size_of::(), @@ -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 = 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), )) } diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 80b8a0595a..7d1d23fe8c 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -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::().add(BRK_MAX_SIZE).cast::() }; @@ -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::(), mem::size_of::(), @@ -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) -> 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<×pec>) -> 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 { - 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 { 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 { - 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::(), @@ -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::(), @@ -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 { - 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 }; diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs index 6885c131ba..f115287ea8 100644 --- a/src/platform/redox/signal.rs +++ b/src/platform/redox/signal.rs @@ -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, 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::>( 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::>( 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, core::option::Option, >(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); diff --git a/src/platform/redox/socket.rs b/src/platform/redox/socket.rs index 1e120887e7..753a33a672 100644 --- a/src/platform/redox/socket.rs +++ b/src/platform/redox/socket.rs @@ -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::() { return Err(Errno(EINVAL)); } - let data = unsafe { &*address.cast::() }; - let addr = unsafe { + let data = // SAFETY: caller must verify the safety contract for this operation +unsafe { &*address.cast::() }; + 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::(), 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::() }; + let data = // SAFETY: caller must verify the safety contract for this operation +unsafe { &*address.cast::() }; 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 { // 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::() }; + let data = // SAFETY: caller must verify the safety contract for this operation +unsafe { &mut *address.cast::() }; 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::(), 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::(), address.cast::(), 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::()) }; + 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::()) }; 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::(); 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 = 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::(), fds_usize.len() * mem::size_of::(), @@ -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::(), @@ -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::(), 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::(), 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::(), fds_usize.len() * mem::size_of::(), @@ -514,7 +543,8 @@ unsafe fn deserialize_ancillary_data_from_stream( let gid = read_num::(&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::(), mem::size_of::()) }); 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::(), @@ -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::() }; + let data = // SAFETY: caller must verify the safety contract for this operation +unsafe { &*address.cast::() }; // 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::(), len) }; + // SAFETY: caller guarantees ptr is aligned for T and len is exact +unsafe { slice::from_raw_parts((&raw const data.sun_path).cast::(), 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 { - 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::() }; + let data = // SAFETY: caller must verify the safety contract for this operation +unsafe { &*address.cast::() }; // 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::(), len) }; + // SAFETY: caller guarantees ptr is aligned for T and len is exact +unsafe { slice::from_raw_parts((&raw const data.sun_path).cast::(), 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::::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::() }) + Ok(// SAFETY: caller must verify the safety contract for this operation +unsafe { &mut *option_value.cast::() }) }; // 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::() as socklen_t }; + // SAFETY: caller must verify the safety contract for this operation +unsafe { *option_len_ptr = mem::size_of::() 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::() as socklen_t }; + // SAFETY: caller must verify the safety contract for this operation +unsafe { *option_len_ptr = mem::size_of::() 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::() as socklen_t }; + // SAFETY: caller must verify the safety contract for this operation +unsafe { *option_len_ptr = mem::size_of::() 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::(), 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::(), 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 { 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::(), len) }) } else { @@ -859,7 +918,8 @@ impl PalSocket for Sys { let mut msg = msghdr { msg_name: address.cast::(), 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 = 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::(), 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::(), len) }) } @@ -1074,7 +1149,8 @@ impl PalSocket for Sys { return Err(Errno(EINVAL)); } - let timeval = unsafe { &*option_value.cast::() }; + let timeval = // SAFETY: caller must verify the safety contract for this operation +unsafe { &*option_value.cast::() }; 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();