mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:47:44 +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:
parent
b4a29113e4
commit
7e6fbef8db
3 changed files with 24 additions and 18 deletions
|
@ -275,8 +275,8 @@ struct SC_select_params {
|
||||||
struct SC_poll_params {
|
struct SC_poll_params {
|
||||||
struct pollfd* fds;
|
struct pollfd* fds;
|
||||||
unsigned nfds;
|
unsigned nfds;
|
||||||
const struct timespec* timeout;
|
Userspace<const struct timespec*> timeout;
|
||||||
const u32* sigmask;
|
Userspace<const u32*> sigmask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_clock_nanosleep_params {
|
struct SC_clock_nanosleep_params {
|
||||||
|
|
|
@ -231,7 +231,7 @@ public:
|
||||||
int sys$minherit(void*, size_t, int inherit);
|
int sys$minherit(void*, size_t, int inherit);
|
||||||
int sys$purge(int mode);
|
int sys$purge(int mode);
|
||||||
int sys$select(const Syscall::SC_select_params*);
|
int sys$select(const Syscall::SC_select_params*);
|
||||||
int sys$poll(const Syscall::SC_poll_params*);
|
int sys$poll(Userspace<const Syscall::SC_poll_params*>);
|
||||||
ssize_t sys$get_dir_entries(int fd, void*, ssize_t);
|
ssize_t sys$get_dir_entries(int fd, void*, ssize_t);
|
||||||
int sys$getcwd(Userspace<char*>, ssize_t);
|
int sys$getcwd(Userspace<char*>, ssize_t);
|
||||||
int sys$chdir(Userspace<const char*>, size_t);
|
int sys$chdir(Userspace<const char*>, size_t);
|
||||||
|
|
|
@ -139,27 +139,29 @@ int Process::sys$select(const Syscall::SC_select_params* params)
|
||||||
return marked_fd_count;
|
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);
|
REQUIRE_PROMISE(stdio);
|
||||||
|
|
||||||
// FIXME: Return -EINVAL if timeout is invalid.
|
// 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;
|
return -EFAULT;
|
||||||
|
|
||||||
SmapDisabler disabler;
|
SmapDisabler disabler;
|
||||||
|
|
||||||
pollfd* fds = params->fds;
|
pollfd* fds = params.fds;
|
||||||
unsigned nfds = params->nfds;
|
unsigned nfds = params.nfds;
|
||||||
const timespec* timeout = params->timeout;
|
|
||||||
const sigset_t* sigmask = params->sigmask;
|
|
||||||
|
|
||||||
if (fds && !validate_read_typed(fds, nfds))
|
if (fds && !validate_read_typed(fds, nfds))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (timeout && !validate_read_typed(timeout))
|
|
||||||
|
timespec timeout = {};
|
||||||
|
if (params.timeout && !validate_read_and_copy_typed(&timeout, params.timeout))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (sigmask && !validate_read_typed(sigmask))
|
|
||||||
return -EFAULT;
|
sigset_t sigmask = {};
|
||||||
if (!validate_read_typed(fds))
|
if (params.sigmask && !validate_read_and_copy_typed(&sigmask, params.sigmask))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
Thread::SelectBlocker::FDVector rfds;
|
Thread::SelectBlocker::FDVector rfds;
|
||||||
|
@ -174,27 +176,31 @@ int Process::sys$poll(const Syscall::SC_poll_params* params)
|
||||||
|
|
||||||
timespec actual_timeout;
|
timespec actual_timeout;
|
||||||
bool has_timeout = false;
|
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;
|
timespec ts_since_boot;
|
||||||
timeval_to_timespec(Scheduler::time_since_boot(), 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;
|
has_timeout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto current_thread = Thread::current();
|
auto current_thread = Thread::current();
|
||||||
ScopedValueRollback scoped_sigmask(current_thread->m_signal_mask);
|
ScopedValueRollback scoped_sigmask(current_thread->m_signal_mask);
|
||||||
if (sigmask)
|
if (params.sigmask)
|
||||||
current_thread->m_signal_mask = *sigmask;
|
current_thread->m_signal_mask = sigmask;
|
||||||
|
|
||||||
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
|
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
|
||||||
dbg() << "polling on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << timeout;
|
dbg() << "polling on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << timeout;
|
||||||
#endif
|
#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())
|
if (current_thread->block<Thread::SelectBlocker>(has_timeout ? &actual_timeout : nullptr, rfds, wfds, Thread::SelectBlocker::FDVector()).was_interrupted())
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate we can still write after waking up.
|
||||||
|
if (fds && !validate_write_typed(fds, nfds))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
int fds_with_revents = 0;
|
int fds_with_revents = 0;
|
||||||
|
|
||||||
for (unsigned i = 0; i < nfds; ++i) {
|
for (unsigned i = 0; i < nfds; ++i) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue