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:
@@ -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
@@ -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<×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<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
|
||||
};
|
||||
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user