diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index a782e34708..e6b0f6c4f2 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -275,8 +275,8 @@ struct SC_select_params { struct SC_poll_params { struct pollfd* fds; unsigned nfds; - const struct timespec* timeout; - const u32* sigmask; + Userspace timeout; + Userspace sigmask; }; struct SC_clock_nanosleep_params { diff --git a/Kernel/Process.h b/Kernel/Process.h index 58e81487c6..abf213aa06 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -231,7 +231,7 @@ public: int sys$minherit(void*, size_t, int inherit); int sys$purge(int mode); int sys$select(const Syscall::SC_select_params*); - int sys$poll(const Syscall::SC_poll_params*); + int sys$poll(Userspace); ssize_t sys$get_dir_entries(int fd, void*, ssize_t); int sys$getcwd(Userspace, ssize_t); int sys$chdir(Userspace, size_t); diff --git a/Kernel/Syscalls/select.cpp b/Kernel/Syscalls/select.cpp index 1308af4d7b..fc742210f4 100644 --- a/Kernel/Syscalls/select.cpp +++ b/Kernel/Syscalls/select.cpp @@ -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 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(¶ms, 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(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) {