1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 21:47:43 +00:00

Kernel: Sanitize all user-supplied timeval's/timespec's

This also removes a bunch of unnecessary EINVAL. Most of them weren't even
recommended by POSIX.
This commit is contained in:
Ben Wiederhake 2021-02-21 20:28:20 +01:00 committed by Andreas Kling
parent 649abc01bc
commit 8598240193
4 changed files with 42 additions and 28 deletions

View file

@ -106,14 +106,24 @@ KResult Socket::setsockopt(int level, int option, Userspace<const void*> user_va
case SO_SNDTIMEO: case SO_SNDTIMEO:
if (user_value_size != sizeof(timeval)) if (user_value_size != sizeof(timeval))
return EINVAL; return EINVAL;
if (!copy_from_user(&m_send_timeout, static_ptr_cast<const timeval*>(user_value))) {
return EFAULT; auto timeout = copy_time_from_user(static_ptr_cast<const timeval*>(user_value));
if (!timeout.has_value())
return EFAULT;
// FIXME: Should use AK::Time internally
m_send_timeout = timeout->to_timeval();
}
return KSuccess; return KSuccess;
case SO_RCVTIMEO: case SO_RCVTIMEO:
if (user_value_size != sizeof(timeval)) if (user_value_size != sizeof(timeval))
return EINVAL; return EINVAL;
if (!copy_from_user(&m_receive_timeout, static_ptr_cast<const timeval*>(user_value))) {
return EFAULT; auto timeout = copy_time_from_user(static_ptr_cast<const timeval*>(user_value));
if (!timeout.has_value())
return EFAULT;
// FIXME: Should use AK::Time internally
m_receive_timeout = timeout->to_timeval();
}
return KSuccess; return KSuccess;
case SO_BINDTODEVICE: { case SO_BINDTODEVICE: {
if (user_value_size != IFNAMSIZ) if (user_value_size != IFNAMSIZ)

View file

@ -50,13 +50,14 @@ KResultOr<int> Process::sys$clock_settime(clockid_t clock_id, Userspace<const ti
if (!is_superuser()) if (!is_superuser())
return EPERM; return EPERM;
timespec ts; auto ts = copy_time_from_user(user_ts);
if (!copy_from_user(&ts, user_ts)) if (!ts.has_value())
return EFAULT; return EFAULT;
switch (clock_id) { switch (clock_id) {
case CLOCK_REALTIME: case CLOCK_REALTIME:
TimeManagement::the().set_epoch_time(ts); // FIXME: Should use AK::Time internally
TimeManagement::the().set_epoch_time(ts->to_timespec());
break; break;
default: default:
return EINVAL; return EINVAL;
@ -72,9 +73,9 @@ KResultOr<int> Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_na
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return EFAULT; return EFAULT;
timespec requested_sleep; Optional<Time> requested_sleep = copy_time_from_user(params.requested_sleep);
if (!copy_from_user(&requested_sleep, params.requested_sleep)) if (!requested_sleep.has_value())
return EFAULT; return -EFAULT;
bool is_absolute; bool is_absolute;
switch (params.flags) { switch (params.flags) {
@ -93,10 +94,12 @@ KResultOr<int> Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_na
bool was_interrupted; bool was_interrupted;
if (is_absolute) { if (is_absolute) {
was_interrupted = Thread::current()->sleep_until(params.clock_id, requested_sleep).was_interrupted(); // FIXME: Should use AK::Time internally
was_interrupted = Thread::current()->sleep_until(params.clock_id, requested_sleep->to_timespec()).was_interrupted();
} else { } else {
timespec remaining_sleep; timespec remaining_sleep;
was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep, &remaining_sleep).was_interrupted(); // FIXME: Should use AK::Time internally
was_interrupted = Thread::current()->sleep(params.clock_id, requested_sleep->to_timespec(), &remaining_sleep).was_interrupted();
if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep)) if (was_interrupted && params.remaining_sleep && !copy_to_user(params.remaining_sleep, &remaining_sleep))
return EFAULT; return EFAULT;
} }
@ -119,16 +122,12 @@ KResultOr<int> Process::sys$adjtime(Userspace<const timeval*> user_delta, Usersp
REQUIRE_PROMISE(settime); REQUIRE_PROMISE(settime);
if (!is_superuser()) if (!is_superuser())
return EPERM; return EPERM;
timeval delta; auto delta = copy_time_from_user(user_delta);
if (!copy_from_user(&delta, user_delta)) if (!delta.has_value())
return EFAULT; return EFAULT;
if (delta.tv_usec < 0 || delta.tv_usec >= 1'000'000) // FIXME: Should use AK::Time internally
return EINVAL; TimeManagement::the().set_remaining_epoch_time_adjustment(delta->to_timespec());
timespec delta_ts;
timeval_to_timespec(delta, delta_ts);
TimeManagement::the().set_remaining_epoch_time_adjustment(delta_ts);
} }
return 0; return 0;

View file

@ -118,12 +118,14 @@ KResultOr<int> Process::sys$futex(Userspace<const Syscall::SC_futex_params*> use
case FUTEX_REQUEUE: case FUTEX_REQUEUE:
case FUTEX_CMP_REQUEUE: { case FUTEX_CMP_REQUEUE: {
if (params.timeout) { if (params.timeout) {
timespec ts_stimeout { 0, 0 }; auto timeout_time = copy_time_from_user(params.timeout);
if (!copy_from_user(&ts_stimeout, params.timeout)) if (!timeout_time.has_value())
return EFAULT; return EFAULT;
clockid_t clock_id = (params.futex_op & FUTEX_CLOCK_REALTIME) ? CLOCK_REALTIME_COARSE : CLOCK_MONOTONIC_COARSE; clockid_t clock_id = (params.futex_op & FUTEX_CLOCK_REALTIME) ? CLOCK_REALTIME_COARSE : CLOCK_MONOTONIC_COARSE;
bool is_absolute = cmd != FUTEX_WAIT; bool is_absolute = cmd != FUTEX_WAIT;
timeout = Thread::BlockTimeout(is_absolute, &ts_stimeout, nullptr, clock_id); // FIXME: Should use AK::Time internally
timespec timeout_copy = timeout_time->to_timespec();
timeout = Thread::BlockTimeout(is_absolute, &timeout_copy, nullptr, clock_id);
} }
if (cmd == FUTEX_WAIT_BITSET && params.val3 == FUTEX_BITSET_MATCH_ANY) if (cmd == FUTEX_WAIT_BITSET && params.val3 == FUTEX_BITSET_MATCH_ANY)
cmd = FUTEX_WAIT; cmd = FUTEX_WAIT;

View file

@ -45,9 +45,11 @@ KResultOr<int> Process::sys$select(Userspace<const Syscall::SC_select_params*> u
Thread::BlockTimeout timeout; Thread::BlockTimeout timeout;
if (params.timeout) { if (params.timeout) {
timespec timeout_copy; Optional<Time> timeout_time = copy_time_from_user(params.timeout);
if (!copy_from_user(&timeout_copy, params.timeout)) if (!timeout_time.has_value())
return EFAULT; return EFAULT;
auto timeout_copy = timeout_time->to_timespec();
// FIXME: Should use AK::Time internally
timeout = Thread::BlockTimeout(false, &timeout_copy); timeout = Thread::BlockTimeout(false, &timeout_copy);
} }
@ -142,7 +144,6 @@ KResultOr<int> Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
// FIXME: Return -EINVAL if timeout is invalid.
Syscall::SC_poll_params params; Syscall::SC_poll_params params;
if (!copy_from_user(&params, user_params)) if (!copy_from_user(&params, user_params))
return EFAULT; return EFAULT;
@ -152,9 +153,11 @@ KResultOr<int> Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_
Thread::BlockTimeout timeout; Thread::BlockTimeout timeout;
if (params.timeout) { if (params.timeout) {
timespec timeout_copy; auto timeout_time = copy_time_from_user(params.timeout);
if (!copy_from_user(&timeout_copy, params.timeout)) if (!timeout_time.has_value())
return EFAULT; return EFAULT;
timespec timeout_copy = timeout_time->to_timespec();
// FIXME: Should use AK::Time internally
timeout = Thread::BlockTimeout(false, &timeout_copy); timeout = Thread::BlockTimeout(false, &timeout_copy);
} }