Skip to content

Commit

Permalink
Add methods for reading into unitialized buffers (#944)
Browse files Browse the repository at this point in the history
* Uninitialized slices for getrandom
* Implement uninitialized reads for read syscall
* Add initialized reads for net methods

Signed-off-by: John Nunley <dev@notgull.net>
  • Loading branch information
notgull authored Dec 7, 2023
1 parent 56acc55 commit 748a828
Show file tree
Hide file tree
Showing 14 changed files with 335 additions and 147 deletions.
28 changes: 10 additions & 18 deletions src/backend/libc/io/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,8 @@ use {
crate::io::{IoSlice, IoSliceMut},
};

pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
ret_usize(c::read(
borrowed_fd(fd),
buf.as_mut_ptr().cast(),
min(buf.len(), READ_LIMIT),
))
}
pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: *mut u8, len: usize) -> io::Result<usize> {
ret_usize(c::read(borrowed_fd(fd), buf.cast(), min(len, READ_LIMIT)))
}

pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> {
Expand All @@ -46,8 +40,13 @@ pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> {
}
}

pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], offset: u64) -> io::Result<usize> {
let len = min(buf.len(), READ_LIMIT);
pub(crate) unsafe fn pread(
fd: BorrowedFd<'_>,
buf: *mut u8,
len: usize,
offset: u64,
) -> io::Result<usize> {
let len = min(len, READ_LIMIT);

// Silently cast; we'll get `EINVAL` if the value is negative.
let offset = offset as i64;
Expand All @@ -56,14 +55,7 @@ pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], offset: u64) -> io::Resu
#[cfg(any(target_os = "espidf", target_os = "vita"))]
let offset: i32 = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;

unsafe {
ret_usize(c::pread(
borrowed_fd(fd),
buf.as_mut_ptr().cast(),
len,
offset,
))
}
ret_usize(c::pread(borrowed_fd(fd), buf.cast(), len, offset))
}

pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<usize> {
Expand Down
72 changes: 37 additions & 35 deletions src/backend/libc/net/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,18 @@ use {
};

#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
pub(crate) fn recv(fd: BorrowedFd<'_>, buf: &mut [u8], flags: RecvFlags) -> io::Result<usize> {
unsafe {
ret_send_recv(c::recv(
borrowed_fd(fd),
buf.as_mut_ptr().cast(),
send_recv_len(buf.len()),
bitflags_bits!(flags),
))
}
pub(crate) unsafe fn recv(
fd: BorrowedFd<'_>,
buf: *mut u8,
len: usize,
flags: RecvFlags,
) -> io::Result<usize> {
ret_send_recv(c::recv(
borrowed_fd(fd),
buf.cast(),
send_recv_len(len),
bitflags_bits!(flags),
))
}

#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
Expand All @@ -55,35 +58,34 @@ pub(crate) fn send(fd: BorrowedFd<'_>, buf: &[u8], flags: SendFlags) -> io::Resu
}

#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
pub(crate) fn recvfrom(
pub(crate) unsafe fn recvfrom(
fd: BorrowedFd<'_>,
buf: &mut [u8],
buf: *mut u8,
buf_len: usize,
flags: RecvFlags,
) -> io::Result<(usize, Option<SocketAddrAny>)> {
unsafe {
let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit();
let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t;

// `recvfrom` does not write to the storage if the socket is
// connection-oriented sockets, so we initialize the family field to
// `AF_UNSPEC` so that we can detect this case.
initialize_family_to_unspec(storage.as_mut_ptr());

ret_send_recv(c::recvfrom(
borrowed_fd(fd),
buf.as_mut_ptr().cast(),
send_recv_len(buf.len()),
bitflags_bits!(flags),
storage.as_mut_ptr().cast(),
&mut len,
))
.map(|nread| {
(
nread,
maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()),
)
})
}
let mut storage = MaybeUninit::<c::sockaddr_storage>::uninit();
let mut len = size_of::<c::sockaddr_storage>() as c::socklen_t;

// `recvfrom` does not write to the storage if the socket is
// connection-oriented sockets, so we initialize the family field to
// `AF_UNSPEC` so that we can detect this case.
initialize_family_to_unspec(storage.as_mut_ptr());

ret_send_recv(c::recvfrom(
borrowed_fd(fd),
buf.cast(),
send_recv_len(buf_len),
bitflags_bits!(flags),
storage.as_mut_ptr().cast(),
&mut len,
))
.map(|nread| {
(
nread,
maybe_read_sockaddr_os(storage.as_ptr(), len.try_into().unwrap()),
)
})
}

#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
Expand Down
8 changes: 6 additions & 2 deletions src/backend/libc/rand/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
use {crate::backend::c, crate::backend::conv::ret_usize, crate::io, crate::rand::GetRandomFlags};

#[cfg(linux_kernel)]
pub(crate) fn getrandom(buf: &mut [u8], flags: GetRandomFlags) -> io::Result<usize> {
pub(crate) unsafe fn getrandom(
buf: *mut u8,
cap: usize,
flags: GetRandomFlags,
) -> io::Result<usize> {
// `getrandom` wasn't supported in glibc until 2.25.
weak_or_syscall! {
fn getrandom(buf: *mut c::c_void, buflen: c::size_t, flags: c::c_uint) via SYS_getrandom -> c::ssize_t
}

unsafe { ret_usize(getrandom(buf.as_mut_ptr().cast(), buf.len(), flags.bits())) }
ret_usize(getrandom(buf.cast(), cap, flags.bits()))
}
63 changes: 31 additions & 32 deletions src/backend/linux_raw/io/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::backend::conv::loff_t_from_u64;
use crate::backend::conv::zero;
use crate::backend::conv::{
c_uint, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint, ret_discarded_fd, ret_owned_fd,
ret_usize, slice, slice_mut,
ret_usize, slice,
};
#[cfg(target_pointer_width = "32")]
use crate::backend::conv::{hi, lo};
Expand All @@ -29,27 +29,28 @@ use core::cmp;
use linux_raw_sys::general::{F_DUPFD_CLOEXEC, F_GETFD, F_SETFD};

#[inline]
pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> {
let (buf_addr_mut, buf_len) = slice_mut(buf);

unsafe { ret_usize(syscall!(__NR_read, fd, buf_addr_mut, buf_len)) }
pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: *mut u8, len: usize) -> io::Result<usize> {
ret_usize(syscall!(__NR_read, fd, buf, pass_usize(len)))
}

#[inline]
pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], pos: u64) -> io::Result<usize> {
let (buf_addr_mut, buf_len) = slice_mut(buf);

pub(crate) unsafe fn pread(
fd: BorrowedFd<'_>,
buf: *mut u8,
len: usize,
pos: u64,
) -> io::Result<usize> {
// <https://github.com/torvalds/linux/blob/fcadab740480e0e0e9fa9bd272acd409884d431a/arch/arm64/kernel/sys32.c#L75>
#[cfg(all(
target_pointer_width = "32",
any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6"),
))]
unsafe {
{
ret_usize(syscall!(
__NR_pread64,
fd,
buf_addr_mut,
buf_len,
buf,
pass_usize(len),
zero(),
hi(pos),
lo(pos)
Expand All @@ -59,26 +60,24 @@ pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], pos: u64) -> io::Result<
target_pointer_width = "32",
not(any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6")),
))]
unsafe {
{
ret_usize(syscall!(
__NR_pread64,
fd,
buf_addr_mut,
buf_len,
buf,
pass_usize(len),
hi(pos),
lo(pos)
))
}
#[cfg(target_pointer_width = "64")]
unsafe {
ret_usize(syscall!(
__NR_pread64,
fd,
buf_addr_mut,
buf_len,
loff_t_from_u64(pos)
))
}
ret_usize(syscall!(
__NR_pread64,
fd,
buf,
pass_usize(len),
loff_t_from_u64(pos)
))
}

#[inline]
Expand Down Expand Up @@ -268,15 +267,15 @@ pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> {
// Do a `recv` with `PEEK` and `DONTWAIT` for 1 byte. A 0 indicates
// the read side is shut down; an `EWOULDBLOCK` indicates the read
// side is still open.
//
// TODO: This code would benefit from having a better way to read into
// uninitialized memory.
let mut buf = [0];
match crate::backend::net::syscalls::recv(
fd,
&mut buf,
RecvFlags::PEEK | RecvFlags::DONTWAIT,
) {
let mut buf = [core::mem::MaybeUninit::<u8>::uninit()];
match unsafe {
crate::backend::net::syscalls::recv(
fd,
buf.as_mut_ptr() as *mut u8,
1,
RecvFlags::PEEK | RecvFlags::DONTWAIT,
)
} {
Ok(0) => read = false,
Err(err) => {
#[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK`
Expand Down
Loading

0 comments on commit 748a828

Please sign in to comment.