1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 19:38:12 +00:00

Kernel: Partial usage of Userspace<T> for the poll syscall

This change mostly converts poll to Userspace<T> with the caveat
of the fds member of SC_poll_params. It's current usage is a bit
too gnarly for me to take on right now, this appears to need a lot
more love.

In addition to enlightening the syscall to use Userspace<T>, I've
also re-worked most of the handling to use validate_read_and_copy
instead of just directly de-referencing the user pointer. We also
appeared to be missing a re-evaluation of the fds array after the
thread block is awoken.
This commit is contained in:
Brian Gianforcaro 2020-08-04 23:15:42 -07:00 committed by Andreas Kling
parent b4a29113e4
commit 7e6fbef8db
3 changed files with 24 additions and 18 deletions

View file

@ -139,27 +139,29 @@ int Process::sys$select(const Syscall::SC_select_params* params)
return marked_fd_count;
}
int Process::sys$poll(const Syscall::SC_poll_params* params)
int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
{
REQUIRE_PROMISE(stdio);
// FIXME: Return -EINVAL if timeout is invalid.
if (!validate_read_typed(params))
Syscall::SC_poll_params params;
if (!validate_read_and_copy_typed(&params, user_params))
return -EFAULT;
SmapDisabler disabler;
pollfd* fds = params->fds;
unsigned nfds = params->nfds;
const timespec* timeout = params->timeout;
const sigset_t* sigmask = params->sigmask;
pollfd* fds = params.fds;
unsigned nfds = params.nfds;
if (fds && !validate_read_typed(fds, nfds))
return -EFAULT;
if (timeout && !validate_read_typed(timeout))
timespec timeout = {};
if (params.timeout && !validate_read_and_copy_typed(&timeout, params.timeout))
return -EFAULT;
if (sigmask && !validate_read_typed(sigmask))
return -EFAULT;
if (!validate_read_typed(fds))
sigset_t sigmask = {};
if (params.sigmask && !validate_read_and_copy_typed(&sigmask, params.sigmask))
return -EFAULT;
Thread::SelectBlocker::FDVector rfds;
@ -174,27 +176,31 @@ int Process::sys$poll(const Syscall::SC_poll_params* params)
timespec actual_timeout;
bool has_timeout = false;
if (timeout && (timeout->tv_sec || timeout->tv_nsec)) {
if (params.timeout && (timeout.tv_sec || timeout.tv_nsec)) {
timespec ts_since_boot;
timeval_to_timespec(Scheduler::time_since_boot(), ts_since_boot);
timespec_add(ts_since_boot, *timeout, actual_timeout);
timespec_add(ts_since_boot, timeout, actual_timeout);
has_timeout = true;
}
auto current_thread = Thread::current();
ScopedValueRollback scoped_sigmask(current_thread->m_signal_mask);
if (sigmask)
current_thread->m_signal_mask = *sigmask;
if (params.sigmask)
current_thread->m_signal_mask = sigmask;
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
dbg() << "polling on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << timeout;
#endif
if (!timeout || has_timeout) {
if (!params.timeout || has_timeout) {
if (current_thread->block<Thread::SelectBlocker>(has_timeout ? &actual_timeout : nullptr, rfds, wfds, Thread::SelectBlocker::FDVector()).was_interrupted())
return -EINTR;
}
// Validate we can still write after waking up.
if (fds && !validate_write_typed(fds, nfds))
return -EFAULT;
int fds_with_revents = 0;
for (unsigned i = 0; i < nfds; ++i) {