Fix a possible overflow due to use of fionread in poll_oneoff on Unix. (#881)
Closes #578.
This commit is contained in:
committed by
GitHub
parent
5bed47631a
commit
150a3e588b
@@ -124,9 +124,24 @@ fn poll_oneoff_handle_fd_event<'a>(
|
|||||||
ready_events: impl Iterator<Item = (FdEventData<'a>, yanix::poll::PollFd)>,
|
ready_events: impl Iterator<Item = (FdEventData<'a>, yanix::poll::PollFd)>,
|
||||||
events: &mut Vec<wasi::__wasi_event_t>,
|
events: &mut Vec<wasi::__wasi_event_t>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
use crate::fdentry::Descriptor;
|
||||||
use std::{convert::TryInto, os::unix::prelude::AsRawFd};
|
use std::{convert::TryInto, os::unix::prelude::AsRawFd};
|
||||||
use yanix::{file::fionread, poll::PollFlags};
|
use yanix::{file::fionread, poll::PollFlags};
|
||||||
|
|
||||||
|
fn query_nbytes(fd: &Descriptor) -> Result<u64> {
|
||||||
|
// fionread may overflow for large files, so use another way for regular files.
|
||||||
|
if let Descriptor::OsHandle(os_handle) = fd {
|
||||||
|
let meta = os_handle.metadata()?;
|
||||||
|
if meta.file_type().is_file() {
|
||||||
|
use yanix::file::tell;
|
||||||
|
let len = meta.len();
|
||||||
|
let host_offset = unsafe { tell(os_handle.as_raw_fd())? };
|
||||||
|
return Ok(len - host_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe { Ok(fionread(fd.as_raw_fd())?.into()) }
|
||||||
|
}
|
||||||
|
|
||||||
for (fd_event, poll_fd) in ready_events {
|
for (fd_event, poll_fd) in ready_events {
|
||||||
log::debug!("poll_oneoff_handle_fd_event fd_event = {:?}", fd_event);
|
log::debug!("poll_oneoff_handle_fd_event fd_event = {:?}", fd_event);
|
||||||
log::debug!("poll_oneoff_handle_fd_event poll_fd = {:?}", poll_fd);
|
log::debug!("poll_oneoff_handle_fd_event poll_fd = {:?}", poll_fd);
|
||||||
@@ -139,7 +154,7 @@ fn poll_oneoff_handle_fd_event<'a>(
|
|||||||
log::debug!("poll_oneoff_handle_fd_event revents = {:?}", revents);
|
log::debug!("poll_oneoff_handle_fd_event revents = {:?}", revents);
|
||||||
|
|
||||||
let nbytes = if fd_event.r#type == wasi::__WASI_EVENTTYPE_FD_READ {
|
let nbytes = if fd_event.r#type == wasi::__WASI_EVENTTYPE_FD_READ {
|
||||||
unsafe { fionread(fd_event.descriptor.as_raw_fd())? }
|
query_nbytes(fd_event.descriptor)?
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -235,8 +235,15 @@ pub unsafe fn fstat(fd: RawFd) -> Result<libc::stat> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`.
|
/// `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`.
|
||||||
pub unsafe fn fionread(fd: RawFd) -> Result<usize> {
|
pub unsafe fn fionread(fd: RawFd) -> Result<u32> {
|
||||||
let mut nread: libc::c_int = 0;
|
let mut nread: libc::c_int = 0;
|
||||||
Errno::from_result(libc::ioctl(fd, libc::FIONREAD, &mut nread as *mut _))?;
|
Errno::from_result(libc::ioctl(fd, libc::FIONREAD, &mut nread as *mut _))?;
|
||||||
Ok(nread.try_into()?)
|
Ok(nread.try_into()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function is unsafe because it operates on a raw file descriptor.
|
||||||
|
/// It's provided, because std::io::Seek requires a mutable borrow.
|
||||||
|
pub unsafe fn tell(fd: RawFd) -> Result<u64> {
|
||||||
|
let offset: i64 = Errno::from_result(libc::lseek(fd, 0, libc::SEEK_CUR))?;
|
||||||
|
Ok(offset.try_into()?)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user