mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:17:44 +00:00
Kernel: Make copy_to/from_user safe and remove unnecessary checks
Since the CPU already does almost all necessary validation steps for us, we don't really need to attempt to do this. Doing it ourselves doesn't really work very reliably, because we'd have to account for other processors modifying virtual memory, and we'd have to account for e.g. pages not being able to be allocated due to insufficient resources. So change the copy_to/from_user (and associated helper functions) to use the new safe_memcpy, which will return whether it succeeded or not. The only manual validation step needed (which the CPU can't perform for us) is making sure the pointers provided by user mode aren't pointing to kernel mappings. To make it easier to read/write from/to either kernel or user mode data add the UserOrKernelBuffer helper class, which will internally either use copy_from/to_user or directly memcpy, or pass the data through directly using a temporary buffer on the stack. Last but not least we need to keep syscall params trivial as we need to copy them from/to user mode using copy_from/to_user.
This commit is contained in:
parent
7d1b8417bd
commit
c8d9f1b9c9
149 changed files with 1585 additions and 1244 deletions
|
@ -66,12 +66,11 @@ int Process::sys$getcwd(Userspace<char*> buffer, ssize_t size)
|
|||
REQUIRE_PROMISE(rpath);
|
||||
if (size < 0)
|
||||
return -EINVAL;
|
||||
if (!validate_write(buffer, size))
|
||||
return -EFAULT;
|
||||
auto path = current_directory().absolute_path();
|
||||
if ((size_t)size < path.length() + 1)
|
||||
return -ERANGE;
|
||||
copy_to_user(buffer, path.characters(), path.length() + 1);
|
||||
if (!copy_to_user(buffer, path.characters(), path.length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ int Process::sys$chown(Userspace<const Syscall::SC_chown_params*> user_params)
|
|||
{
|
||||
REQUIRE_PROMISE(chown);
|
||||
Syscall::SC_chown_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
auto path = get_syscall_path_argument(params.path);
|
||||
if (path.is_error())
|
||||
|
|
|
@ -32,8 +32,6 @@ namespace Kernel {
|
|||
int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(user_ts))
|
||||
return -EFAULT;
|
||||
|
||||
timespec ts = {};
|
||||
|
||||
|
@ -49,7 +47,8 @@ int Process::sys$clock_gettime(clockid_t clock_id, Userspace<timespec*> user_ts)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
copy_to_user(user_ts, &ts);
|
||||
if (!copy_to_user(user_ts, &ts))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -61,7 +60,7 @@ int Process::sys$clock_settime(clockid_t clock_id, Userspace<const timespec*> us
|
|||
return -EPERM;
|
||||
|
||||
timespec ts;
|
||||
if (!validate_read_and_copy_typed(&ts, user_ts))
|
||||
if (!copy_from_user(&ts, user_ts))
|
||||
return -EFAULT;
|
||||
|
||||
switch (clock_id) {
|
||||
|
@ -79,16 +78,11 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
|
|||
REQUIRE_PROMISE(stdio);
|
||||
|
||||
Syscall::SC_clock_nanosleep_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (params.requested_sleep && !validate_read_typed(params.requested_sleep))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
timespec requested_sleep;
|
||||
copy_from_user(&requested_sleep, params.requested_sleep);
|
||||
|
||||
if (params.remaining_sleep && !validate_write_typed(params.remaining_sleep))
|
||||
if (!copy_from_user(&requested_sleep, params.requested_sleep))
|
||||
return -EFAULT;
|
||||
|
||||
bool is_absolute = params.flags & TIMER_ABSTIME;
|
||||
|
@ -109,18 +103,12 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
|
|||
if (wakeup_time > g_uptime) {
|
||||
u64 ticks_left = wakeup_time - g_uptime;
|
||||
if (!is_absolute && params.remaining_sleep) {
|
||||
if (!validate_write_typed(params.remaining_sleep)) {
|
||||
// This can happen because the lock is dropped while
|
||||
// sleeping, thus giving other threads the opportunity
|
||||
// to make the region unwritable.
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
timespec remaining_sleep = {};
|
||||
remaining_sleep.tv_sec = ticks_left / TimeManagement::the().ticks_per_second();
|
||||
ticks_left -= remaining_sleep.tv_sec * TimeManagement::the().ticks_per_second();
|
||||
remaining_sleep.tv_nsec = ticks_left * 1000000000 / TimeManagement::the().ticks_per_second();
|
||||
copy_to_user(params.remaining_sleep, &remaining_sleep);
|
||||
if (!copy_to_user(params.remaining_sleep, &remaining_sleep))
|
||||
return -EFAULT;
|
||||
}
|
||||
return -EINTR;
|
||||
}
|
||||
|
@ -134,10 +122,9 @@ int Process::sys$clock_nanosleep(Userspace<const Syscall::SC_clock_nanosleep_par
|
|||
int Process::sys$gettimeofday(Userspace<timeval*> user_tv)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(user_tv))
|
||||
return -EFAULT;
|
||||
auto tv = kgettimeofday();
|
||||
copy_to_user(user_tv, &tv);
|
||||
if (!copy_to_user(user_tv, &tv))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <Kernel/IO.h>
|
||||
#include <Kernel/KSyms.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/UserOrKernelBuffer.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
@ -44,13 +45,20 @@ int Process::sys$dbgputch(u8 ch)
|
|||
|
||||
int Process::sys$dbgputstr(Userspace<const u8*> characters, int length)
|
||||
{
|
||||
if (!length)
|
||||
if (length <= 0)
|
||||
return 0;
|
||||
if (!validate_read(characters, length))
|
||||
return -EFAULT;
|
||||
|
||||
SmapDisabler disabler;
|
||||
for (int i = 0; i < length; ++i)
|
||||
IO::out8(0xe9, characters.unsafe_userspace_ptr()[i]);
|
||||
auto buffer = UserOrKernelBuffer::for_user_buffer(characters, length);
|
||||
if (!buffer.has_value())
|
||||
return -EFAULT;
|
||||
ssize_t nread = buffer.value().read_buffered<1024>(length, [&](const u8* buffer, size_t buffer_size) {
|
||||
for (size_t i = 0; i < buffer_size; ++i)
|
||||
IO::out8(0xe9, buffer[i]);
|
||||
return (ssize_t)buffer_size;
|
||||
});
|
||||
if (nread < 0)
|
||||
return (int)nread;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -423,7 +423,8 @@ KResultOr<NonnullRefPtr<FileDescription>> Process::find_elf_interpreter_for_exec
|
|||
return KResult(-ENOEXEC);
|
||||
|
||||
memset(first_page, 0, sizeof(first_page));
|
||||
auto nread_or_error = interpreter_description->read((u8*)&first_page, sizeof(first_page));
|
||||
auto first_page_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&first_page);
|
||||
auto nread_or_error = interpreter_description->read(first_page_buffer, sizeof(first_page));
|
||||
if (nread_or_error.is_error())
|
||||
return KResult(-ENOEXEC);
|
||||
nread = nread_or_error.value();
|
||||
|
@ -490,7 +491,8 @@ int Process::exec(String path, Vector<String> arguments, Vector<String> environm
|
|||
|
||||
// Read the first page of the program into memory so we can validate the binfmt of it
|
||||
char first_page[PAGE_SIZE];
|
||||
auto nread_or_error = description->read((u8*)&first_page, sizeof(first_page));
|
||||
auto first_page_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&first_page);
|
||||
auto nread_or_error = description->read(first_page_buffer, sizeof(first_page));
|
||||
if (nread_or_error.is_error())
|
||||
return -ENOEXEC;
|
||||
|
||||
|
@ -554,7 +556,7 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
|
|||
// NOTE: Be extremely careful with allocating any kernel memory in exec().
|
||||
// On success, the kernel stack will be lost.
|
||||
Syscall::SC_execve_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (params.arguments.length > ARG_MAX || params.environment.length > ARG_MAX)
|
||||
|
@ -574,13 +576,16 @@ int Process::sys$execve(Userspace<const Syscall::SC_execve_params*> user_params)
|
|||
auto copy_user_strings = [this](const auto& list, auto& output) {
|
||||
if (!list.length)
|
||||
return true;
|
||||
if (!validate_read_typed(list.strings, list.length))
|
||||
Checked size = sizeof(list.length);
|
||||
size *= list.length;
|
||||
if (size.has_overflow())
|
||||
return false;
|
||||
Vector<Syscall::StringArgument, 32> strings;
|
||||
strings.resize(list.length);
|
||||
copy_from_user(strings.data(), list.strings.unsafe_userspace_ptr(), list.length * sizeof(Syscall::StringArgument));
|
||||
if (!copy_from_user(strings.data(), list.strings, list.length * sizeof(Syscall::StringArgument)))
|
||||
return false;
|
||||
for (size_t i = 0; i < list.length; ++i) {
|
||||
auto string = validate_and_copy_string_from_user(strings[i]);
|
||||
auto string = copy_string_from_user(strings[i]);
|
||||
if (string.is_null())
|
||||
return false;
|
||||
output.append(move(string));
|
||||
|
|
|
@ -55,21 +55,19 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
|
|||
REQUIRE_PROMISE(thread);
|
||||
|
||||
Syscall::SC_futex_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (!validate_read_typed(params.userspace_address))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
switch (params.futex_op) {
|
||||
case FUTEX_WAIT: {
|
||||
i32 user_value;
|
||||
copy_from_user(&user_value, params.userspace_address);
|
||||
if (!copy_from_user(&user_value, params.userspace_address))
|
||||
return -EFAULT;
|
||||
if (user_value != params.val)
|
||||
return -EAGAIN;
|
||||
|
||||
timespec ts_abstimeout { 0, 0 };
|
||||
if (params.timeout && !validate_read_and_copy_typed(&ts_abstimeout, params.timeout))
|
||||
if (params.timeout && !copy_from_user(&ts_abstimeout, params.timeout))
|
||||
return -EFAULT;
|
||||
|
||||
timeval* optional_timeout = nullptr;
|
||||
|
@ -80,7 +78,7 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
|
|||
}
|
||||
|
||||
// FIXME: This is supposed to be interruptible by a signal, but right now WaitQueue cannot be interrupted.
|
||||
WaitQueue& wait_queue = futex_queue(params.userspace_address);
|
||||
WaitQueue& wait_queue = futex_queue((FlatPtr)params.userspace_address);
|
||||
Thread::BlockResult result = Thread::current()->wait_on(wait_queue, "Futex", optional_timeout);
|
||||
if (result == Thread::BlockResult::InterruptedByTimeout) {
|
||||
return -ETIMEDOUT;
|
||||
|
@ -92,9 +90,9 @@ int Process::sys$futex(Userspace<const Syscall::SC_futex_params*> user_params)
|
|||
if (params.val == 0)
|
||||
return 0;
|
||||
if (params.val == 1) {
|
||||
futex_queue(params.userspace_address).wake_one();
|
||||
futex_queue((FlatPtr)params.userspace_address).wake_one();
|
||||
} else {
|
||||
futex_queue(params.userspace_address).wake_n(params.val);
|
||||
futex_queue((FlatPtr)params.userspace_address).wake_n(params.val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -34,12 +34,13 @@ ssize_t Process::sys$get_dir_entries(int fd, void* buffer, ssize_t size)
|
|||
REQUIRE_PROMISE(stdio);
|
||||
if (size < 0)
|
||||
return -EINVAL;
|
||||
if (!validate_write(buffer, size))
|
||||
return -EFAULT;
|
||||
auto description = file_description(fd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
return description->get_dir_entries((u8*)buffer, size);
|
||||
auto user_buffer = UserOrKernelBuffer::for_user_buffer((u8*)buffer, size);
|
||||
if (!user_buffer.has_value())
|
||||
return -EFAULT;
|
||||
return description->get_dir_entries(user_buffer.value(), size);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,11 +31,6 @@ namespace Kernel {
|
|||
|
||||
int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_size)
|
||||
{
|
||||
if (!validate_write_typed(user_stack_base))
|
||||
return -EFAULT;
|
||||
if (!validate_write_typed(user_stack_size))
|
||||
return -EFAULT;
|
||||
|
||||
FlatPtr stack_pointer = Thread::current()->get_register_dump_from_stack().userspace_esp;
|
||||
auto* stack_region = MM.find_region_from_vaddr(*this, VirtualAddress(stack_pointer));
|
||||
if (!stack_region) {
|
||||
|
@ -45,8 +40,10 @@ int Process::sys$get_stack_bounds(FlatPtr* user_stack_base, size_t* user_stack_s
|
|||
|
||||
FlatPtr stack_base = stack_region->range().base().get();
|
||||
size_t stack_size = stack_region->size();
|
||||
copy_to_user(user_stack_base, &stack_base);
|
||||
copy_to_user(user_stack_size, &stack_size);
|
||||
if (!copy_to_user(user_stack_base, &stack_base))
|
||||
return -EFAULT;
|
||||
if (!copy_to_user(user_stack_size, &stack_size))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/Random.h>
|
||||
#include <Kernel/UserOrKernelBuffer.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
@ -38,13 +39,15 @@ ssize_t Process::sys$getrandom(Userspace<void*> buffer, size_t buffer_size, [[ma
|
|||
if (buffer_size <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!validate_write(buffer, buffer_size))
|
||||
return -EFAULT;
|
||||
|
||||
SmapDisabler disabler;
|
||||
// FIXME: We should really push Userspace<T> down through the interface.
|
||||
get_good_random_bytes((u8*)buffer.ptr(), buffer_size);
|
||||
return 0;
|
||||
auto data_buffer = UserOrKernelBuffer::for_user_buffer(buffer, buffer_size);
|
||||
if (!data_buffer.has_value())
|
||||
return -EFAULT;
|
||||
ssize_t nwritten = data_buffer.value().write_buffered<1024>(buffer_size, [&](u8* buffer, size_t buffer_bytes) {
|
||||
get_good_random_bytes(buffer, buffer_bytes);
|
||||
return (ssize_t)buffer_bytes;
|
||||
});
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,22 +55,16 @@ gid_t Process::sys$getegid()
|
|||
int Process::sys$getresuid(Userspace<uid_t*> ruid, Userspace<uid_t*> euid, Userspace<uid_t*> suid)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(ruid) || !validate_write_typed(euid) || !validate_write_typed(suid))
|
||||
if (!copy_to_user(ruid, &m_uid) || !copy_to_user(euid, &m_euid) || !copy_to_user(suid, &m_suid))
|
||||
return -EFAULT;
|
||||
copy_to_user(ruid, &m_uid);
|
||||
copy_to_user(euid, &m_euid);
|
||||
copy_to_user(suid, &m_suid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$getresgid(Userspace<gid_t*> rgid, Userspace<gid_t*> egid, Userspace<gid_t*> sgid)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(rgid) || !validate_write_typed(egid) || !validate_write_typed(sgid))
|
||||
if (!copy_to_user(rgid, &m_gid) || !copy_to_user(egid, &m_egid) || !copy_to_user(sgid, &m_sgid))
|
||||
return -EFAULT;
|
||||
copy_to_user(rgid, &m_gid);
|
||||
copy_to_user(egid, &m_egid);
|
||||
copy_to_user(sgid, &m_sgid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -83,10 +77,9 @@ int Process::sys$getgroups(ssize_t count, Userspace<gid_t*> user_gids)
|
|||
return m_extra_gids.size();
|
||||
if (count != (int)m_extra_gids.size())
|
||||
return -EINVAL;
|
||||
if (!validate_write_typed(user_gids, m_extra_gids.size()))
|
||||
return -EFAULT;
|
||||
|
||||
copy_to_user(user_gids, m_extra_gids.data(), sizeof(gid_t) * count);
|
||||
if (!copy_to_user(user_gids, m_extra_gids.data(), sizeof(gid_t) * count))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,12 +36,11 @@ int Process::sys$gethostname(Userspace<char*> buffer, ssize_t size)
|
|||
REQUIRE_PROMISE(stdio);
|
||||
if (size < 0)
|
||||
return -EINVAL;
|
||||
if (!validate_write(buffer, size))
|
||||
return -EFAULT;
|
||||
LOCKER(*g_hostname_lock, Lock::Mode::Shared);
|
||||
if ((size_t)size < (g_hostname->length() + 1))
|
||||
return -ENAMETOOLONG;
|
||||
copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1);
|
||||
if (!copy_to_user(buffer, g_hostname->characters(), g_hostname->length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -55,7 +54,10 @@ int Process::sys$sethostname(Userspace<const char*> hostname, ssize_t length)
|
|||
LOCKER(*g_hostname_lock, Lock::Mode::Exclusive);
|
||||
if (length > 64)
|
||||
return -ENAMETOOLONG;
|
||||
*g_hostname = validate_and_copy_string_from_user(hostname, length);
|
||||
auto copied_hostname = copy_string_from_user(hostname, length);
|
||||
if (copied_hostname.is_null())
|
||||
return -EFAULT;
|
||||
*g_hostname = move(copied_hostname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,11 +34,13 @@ int Process::sys$link(Userspace<const Syscall::SC_link_params*> user_params)
|
|||
{
|
||||
REQUIRE_PROMISE(cpath);
|
||||
Syscall::SC_link_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
auto old_path = validate_and_copy_string_from_user(params.old_path);
|
||||
auto new_path = validate_and_copy_string_from_user(params.new_path);
|
||||
if (old_path.is_null() || new_path.is_null())
|
||||
auto old_path = copy_string_from_user(params.old_path);
|
||||
if (old_path.is_null())
|
||||
return -EFAULT;
|
||||
auto new_path = copy_string_from_user(params.new_path);
|
||||
if (new_path.is_null())
|
||||
return -EFAULT;
|
||||
return VFS::the().link(old_path, new_path, current_directory());
|
||||
}
|
||||
|
@ -47,7 +49,7 @@ int Process::sys$symlink(Userspace<const Syscall::SC_symlink_params*> user_param
|
|||
{
|
||||
REQUIRE_PROMISE(cpath);
|
||||
Syscall::SC_symlink_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
auto target = get_syscall_path_argument(params.target);
|
||||
if (target.is_error())
|
||||
|
|
|
@ -34,7 +34,7 @@ int Process::sys$mknod(Userspace<const Syscall::SC_mknod_params*> user_params)
|
|||
{
|
||||
REQUIRE_PROMISE(dpath);
|
||||
Syscall::SC_mknod_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
if (!is_superuser() && !is_regular_file(params.mode) && !is_fifo(params.mode) && !is_socket(params.mode))
|
||||
return -EPERM;
|
||||
|
|
|
@ -81,7 +81,7 @@ void* Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
|
|||
REQUIRE_PROMISE(stdio);
|
||||
|
||||
Syscall::SC_mmap_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return (void*)-EFAULT;
|
||||
|
||||
void* addr = (void*)params.addr;
|
||||
|
@ -102,7 +102,7 @@ void* Process::sys$mmap(Userspace<const Syscall::SC_mmap_params*> user_params)
|
|||
if (params.name.characters) {
|
||||
if (params.name.length > PATH_MAX)
|
||||
return (void*)-ENAMETOOLONG;
|
||||
name = validate_and_copy_string_from_user(params.name);
|
||||
name = copy_string_from_user(params.name);
|
||||
if (name.is_null())
|
||||
return (void*)-EFAULT;
|
||||
}
|
||||
|
@ -336,13 +336,13 @@ int Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*
|
|||
REQUIRE_PROMISE(stdio);
|
||||
|
||||
Syscall::SC_set_mmap_name_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (params.name.length > PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
auto name = validate_and_copy_string_from_user(params.name);
|
||||
auto name = copy_string_from_user(params.name);
|
||||
if (name.is_null())
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -351,7 +351,7 @@ int Process::sys$set_mmap_name(Userspace<const Syscall::SC_set_mmap_name_params*
|
|||
return -EINVAL;
|
||||
if (!region->is_mmap())
|
||||
return -EPERM;
|
||||
region->set_name(name);
|
||||
region->set_name(move(name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ int Process::sys$module_unload(Userspace<const char*> user_name, size_t name_len
|
|||
|
||||
REQUIRE_NO_PROMISES;
|
||||
|
||||
auto module_name = validate_and_copy_string_from_user(user_name, name_length);
|
||||
auto module_name = copy_string_from_user(user_name, name_length);
|
||||
if (module_name.is_null())
|
||||
return -EFAULT;
|
||||
|
||||
|
|
|
@ -43,15 +43,16 @@ int Process::sys$mount(Userspace<const Syscall::SC_mount_params*> user_params)
|
|||
REQUIRE_NO_PROMISES;
|
||||
|
||||
Syscall::SC_mount_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
auto source_fd = params.source_fd;
|
||||
auto target = validate_and_copy_string_from_user(params.target);
|
||||
auto fs_type = validate_and_copy_string_from_user(params.fs_type);
|
||||
|
||||
auto target = copy_string_from_user(params.target);
|
||||
if (target.is_null())
|
||||
return -EFAULT;
|
||||
auto fs_type = copy_string_from_user(params.fs_type);
|
||||
if (fs_type.is_null())
|
||||
return -EFAULT;
|
||||
|
||||
auto description = file_description(source_fd);
|
||||
if (!description.is_null())
|
||||
|
@ -129,9 +130,6 @@ int Process::sys$umount(Userspace<const char*> user_mountpoint, size_t mountpoin
|
|||
|
||||
REQUIRE_NO_PROMISES;
|
||||
|
||||
if (!validate_read(user_mountpoint, mountpoint_length))
|
||||
return -EFAULT;
|
||||
|
||||
auto mountpoint = get_syscall_path_argument(user_mountpoint, mountpoint_length);
|
||||
if (mountpoint.is_error())
|
||||
return mountpoint.error();
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace Kernel {
|
|||
int Process::sys$open(Userspace<const Syscall::SC_open_params*> user_params)
|
||||
{
|
||||
Syscall::SC_open_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
int dirfd = params.dirfd;
|
||||
|
|
|
@ -33,8 +33,6 @@ namespace Kernel {
|
|||
int Process::sys$pipe(int pipefd[2], int flags)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(pipefd))
|
||||
return -EFAULT;
|
||||
if (number_of_open_file_descriptors() + 2 > max_open_file_descriptors())
|
||||
return -EMFILE;
|
||||
// Reject flags other than O_CLOEXEC.
|
||||
|
@ -47,12 +45,14 @@ int Process::sys$pipe(int pipefd[2], int flags)
|
|||
int reader_fd = alloc_fd();
|
||||
m_fds[reader_fd].set(fifo->open_direction(FIFO::Direction::Reader), fd_flags);
|
||||
m_fds[reader_fd].description()->set_readable(true);
|
||||
copy_to_user(&pipefd[0], &reader_fd);
|
||||
if (!copy_to_user(&pipefd[0], &reader_fd))
|
||||
return -EFAULT;
|
||||
|
||||
int writer_fd = alloc_fd();
|
||||
m_fds[writer_fd].set(fifo->open_direction(FIFO::Direction::Writer), fd_flags);
|
||||
m_fds[writer_fd].description()->set_writable(true);
|
||||
copy_to_user(&pipefd[1], &writer_fd);
|
||||
if (!copy_to_user(&pipefd[1], &writer_fd))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Kernel {
|
|||
int Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*> user_params)
|
||||
{
|
||||
Syscall::SC_pledge_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (params.promises.length > 1024 || params.execpromises.length > 1024)
|
||||
|
@ -40,14 +40,14 @@ int Process::sys$pledge(Userspace<const Syscall::SC_pledge_params*> user_params)
|
|||
|
||||
String promises;
|
||||
if (params.promises.characters) {
|
||||
promises = validate_and_copy_string_from_user(params.promises);
|
||||
auto promises = copy_string_from_user(params.promises);
|
||||
if (promises.is_null())
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
String execpromises;
|
||||
if (params.execpromises.characters) {
|
||||
execpromises = validate_and_copy_string_from_user(params.execpromises);
|
||||
execpromises = copy_string_from_user(params.execpromises);
|
||||
if (execpromises.is_null())
|
||||
return -EFAULT;
|
||||
}
|
||||
|
|
|
@ -58,13 +58,11 @@ int Process::sys$set_process_icon(int icon_id)
|
|||
int Process::sys$get_process_name(Userspace<char*> buffer, size_t buffer_size)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write(buffer, buffer_size))
|
||||
return -EFAULT;
|
||||
|
||||
if (m_name.length() + 1 > buffer_size)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
copy_to_user(buffer, m_name.characters(), m_name.length() + 1);
|
||||
if (!copy_to_user(buffer, m_name.characters(), m_name.length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -73,7 +71,7 @@ int Process::sys$set_process_name(Userspace<const char*> user_name, size_t user_
|
|||
REQUIRE_PROMISE(proc);
|
||||
if (user_name_length > 256)
|
||||
return -ENAMETOOLONG;
|
||||
auto name = validate_and_copy_string_from_user(user_name, user_name_length);
|
||||
auto name = copy_string_from_user(user_name, user_name_length);
|
||||
if (name.is_null())
|
||||
return -EFAULT;
|
||||
m_name = move(name);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <AK/ScopeGuard.h>
|
||||
#include <Kernel/Process.h>
|
||||
#include <Kernel/Ptrace.h>
|
||||
#include <Kernel/VM/MemoryManager.h>
|
||||
|
@ -38,7 +39,7 @@ int Process::sys$ptrace(Userspace<const Syscall::SC_ptrace_params*> user_params)
|
|||
{
|
||||
REQUIRE_PROMISE(proc);
|
||||
Syscall::SC_ptrace_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
auto result = Ptrace::handle_syscall(params, *this);
|
||||
return result.is_error() ? result.error() : result.value();
|
||||
|
@ -63,28 +64,21 @@ bool Process::has_tracee_thread(ProcessID tracer_pid) const
|
|||
|
||||
KResultOr<u32> Process::peek_user_data(Userspace<const u32*> address)
|
||||
{
|
||||
if (!MM.validate_user_read(*this, VirtualAddress(address), sizeof(u32))) {
|
||||
dbg() << "Invalid address for peek_user_data: " << address.ptr();
|
||||
return KResult(-EFAULT);
|
||||
}
|
||||
uint32_t result;
|
||||
|
||||
// This function can be called from the context of another
|
||||
// process that called PT_PEEK
|
||||
ProcessPagingScope scope(*this);
|
||||
copy_from_user(&result, address);
|
||||
if (!copy_from_user(&result, address)) {
|
||||
dbg() << "Invalid address for peek_user_data: " << address.ptr();
|
||||
return KResult(-EFAULT);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
KResult Process::poke_user_data(Userspace<u32*> address, u32 data)
|
||||
{
|
||||
// We validate for read (rather than write) because PT_POKE can write to readonly pages.
|
||||
// So we effectively only care that the poke operation is trying to write to user pages.
|
||||
if (!MM.validate_user_read(*this, VirtualAddress(address), sizeof(u32))) {
|
||||
dbg() << "Invalid address for poke_user_data: " << address.ptr();
|
||||
return KResult(-EFAULT);
|
||||
}
|
||||
ProcessPagingScope scope(*this);
|
||||
Range range = { VirtualAddress(address), sizeof(u32) };
|
||||
auto* region = find_region_containing(range);
|
||||
|
@ -97,18 +91,23 @@ KResult Process::poke_user_data(Userspace<u32*> address, u32 data)
|
|||
region->set_shared(false);
|
||||
}
|
||||
const bool was_writable = region->is_writable();
|
||||
if (!was_writable) //TODO refactor into scopeguard
|
||||
if (!was_writable)
|
||||
{
|
||||
region->set_writable(true);
|
||||
region->remap();
|
||||
}
|
||||
ScopeGuard rollback([&]() {
|
||||
if (!was_writable) {
|
||||
region->set_writable(false);
|
||||
region->remap();
|
||||
}
|
||||
});
|
||||
|
||||
copy_to_user(address, &data);
|
||||
|
||||
if (!was_writable) {
|
||||
region->set_writable(false);
|
||||
region->remap();
|
||||
if (!copy_to_user(address, &data)) {
|
||||
dbg() << "Invalid address for poke_user_data: " << address.ptr();
|
||||
return KResult(-EFAULT);
|
||||
}
|
||||
|
||||
return KResult(KSuccess);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,6 @@ ssize_t Process::sys$read(int fd, Userspace<u8*> buffer, ssize_t size)
|
|||
return -EINVAL;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
if (!validate_write(buffer, size))
|
||||
return -EFAULT;
|
||||
#ifdef DEBUG_IO
|
||||
dbg() << "sys$read(" << fd << ", " << (const void*)buffer.ptr() << ", " << size << ")";
|
||||
#endif
|
||||
|
@ -58,7 +56,10 @@ ssize_t Process::sys$read(int fd, Userspace<u8*> buffer, ssize_t size)
|
|||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
auto result = description->read(buffer.unsafe_userspace_ptr(), size);
|
||||
auto user_buffer = UserOrKernelBuffer::for_user_buffer(buffer, size);
|
||||
if (!user_buffer.has_value())
|
||||
return -EFAULT;
|
||||
auto result = description->read(user_buffer.value(), size);
|
||||
if (result.is_error())
|
||||
return result.error();
|
||||
return result.value();
|
||||
|
|
|
@ -36,10 +36,7 @@ int Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_par
|
|||
REQUIRE_PROMISE(rpath);
|
||||
|
||||
Syscall::SC_readlink_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (!validate(params.buffer))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
auto path = get_syscall_path_argument(params.path);
|
||||
|
@ -60,7 +57,8 @@ int Process::sys$readlink(Userspace<const Syscall::SC_readlink_params*> user_par
|
|||
|
||||
auto& link_target = contents.value();
|
||||
auto size_to_copy = min(link_target.size(), params.buffer.size);
|
||||
copy_to_user(params.buffer.data, link_target.data(), size_to_copy);
|
||||
if (!copy_to_user(params.buffer.data, link_target.data(), size_to_copy))
|
||||
return -EFAULT;
|
||||
// Note: we return the whole size here, not the copied size.
|
||||
return link_target.size();
|
||||
}
|
||||
|
|
|
@ -36,10 +36,7 @@ int Process::sys$realpath(Userspace<const Syscall::SC_realpath_params*> user_par
|
|||
REQUIRE_PROMISE(rpath);
|
||||
|
||||
Syscall::SC_realpath_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (!validate_write(params.buffer.data, params.buffer.size))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
auto path = get_syscall_path_argument(params.path);
|
||||
|
@ -55,7 +52,8 @@ int Process::sys$realpath(Userspace<const Syscall::SC_realpath_params*> user_par
|
|||
if (absolute_path.length() + 1 > params.buffer.size)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
copy_to_user(params.buffer.data, absolute_path.characters(), absolute_path.length() + 1);
|
||||
if (!copy_to_user(params.buffer.data, absolute_path.characters(), absolute_path.length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ int Process::sys$rename(Userspace<const Syscall::SC_rename_params*> user_params)
|
|||
{
|
||||
REQUIRE_PROMISE(cpath);
|
||||
Syscall::SC_rename_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
auto old_path = get_syscall_path_argument(params.old_path);
|
||||
if (old_path.is_error())
|
||||
|
|
|
@ -51,11 +51,9 @@ int Process::sys$donate(pid_t tid)
|
|||
int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> user_param)
|
||||
{
|
||||
REQUIRE_PROMISE(proc);
|
||||
if (!validate_read_typed(user_param))
|
||||
return -EFAULT;
|
||||
|
||||
struct sched_param desired_param;
|
||||
copy_from_user(&desired_param, user_param);
|
||||
if (!copy_from_user(&desired_param, user_param))
|
||||
return -EFAULT;
|
||||
|
||||
InterruptDisabler disabler;
|
||||
auto* peer = Thread::current();
|
||||
|
@ -78,9 +76,6 @@ int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> us
|
|||
int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_param)
|
||||
{
|
||||
REQUIRE_PROMISE(proc);
|
||||
if (!validate_write_typed(user_param))
|
||||
return -EFAULT;
|
||||
|
||||
InterruptDisabler disabler;
|
||||
auto* peer = Thread::current();
|
||||
if (pid != 0) {
|
||||
|
@ -98,7 +93,8 @@ int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_p
|
|||
struct sched_param param {
|
||||
(int)peer->priority()
|
||||
};
|
||||
copy_to_user(user_param, ¶m);
|
||||
if (!copy_to_user(user_param, ¶m))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,51 +34,43 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
int Process::sys$select(const Syscall::SC_select_params* params)
|
||||
int Process::sys$select(const Syscall::SC_select_params* user_params)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
// FIXME: Return -EINVAL if timeout is invalid.
|
||||
if (!validate_read_typed(params))
|
||||
return -EFAULT;
|
||||
Syscall::SC_select_params params;
|
||||
|
||||
SmapDisabler disabler;
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
int nfds = params->nfds;
|
||||
fd_set* readfds = params->readfds;
|
||||
fd_set* writefds = params->writefds;
|
||||
fd_set* exceptfds = params->exceptfds;
|
||||
const timespec* timeout = params->timeout;
|
||||
const sigset_t* sigmask = params->sigmask;
|
||||
|
||||
if (writefds && !validate_write_typed(writefds))
|
||||
return -EFAULT;
|
||||
if (readfds && !validate_write_typed(readfds))
|
||||
return -EFAULT;
|
||||
if (exceptfds && !validate_write_typed(exceptfds))
|
||||
return -EFAULT;
|
||||
if (timeout && !validate_read_typed(timeout))
|
||||
return -EFAULT;
|
||||
if (sigmask && !validate_read_typed(sigmask))
|
||||
return -EFAULT;
|
||||
if (nfds < 0)
|
||||
if (params.nfds < 0)
|
||||
return -EINVAL;
|
||||
|
||||
timespec computed_timeout;
|
||||
bool select_has_timeout = false;
|
||||
if (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, computed_timeout);
|
||||
select_has_timeout = true;
|
||||
if (params.timeout) {
|
||||
timespec timeout_copy;
|
||||
if (!copy_from_user(&timeout_copy, params.timeout))
|
||||
return -EFAULT;
|
||||
if (timeout_copy.tv_sec || timeout_copy.tv_nsec) {
|
||||
timespec ts_since_boot;
|
||||
timeval_to_timespec(Scheduler::time_since_boot(), ts_since_boot);
|
||||
timespec_add(ts_since_boot, timeout_copy, computed_timeout);
|
||||
select_has_timeout = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto current_thread = Thread::current();
|
||||
|
||||
u32 previous_signal_mask = 0;
|
||||
if (sigmask)
|
||||
previous_signal_mask = current_thread->update_signal_mask(*sigmask);
|
||||
if (params.sigmask) {
|
||||
sigset_t sigmask_copy;
|
||||
if (!copy_from_user(&sigmask_copy, params.sigmask))
|
||||
return -EFAULT;
|
||||
previous_signal_mask = current_thread->update_signal_mask(sigmask_copy);
|
||||
}
|
||||
ScopeGuard rollback_signal_mask([&]() {
|
||||
if (sigmask)
|
||||
if (params.sigmask)
|
||||
current_thread->update_signal_mask(previous_signal_mask);
|
||||
});
|
||||
|
||||
|
@ -86,12 +78,15 @@ int Process::sys$select(const Syscall::SC_select_params* params)
|
|||
Thread::SelectBlocker::FDVector wfds;
|
||||
Thread::SelectBlocker::FDVector efds;
|
||||
|
||||
auto transfer_fds = [&](auto* fds, auto& vector) -> int {
|
||||
auto transfer_fds = [&](auto* fds_unsafe, auto& vector) -> int {
|
||||
vector.clear_with_capacity();
|
||||
if (!fds)
|
||||
if (!fds_unsafe)
|
||||
return 0;
|
||||
for (int fd = 0; fd < nfds; ++fd) {
|
||||
if (FD_ISSET(fd, fds)) {
|
||||
fd_set fds;
|
||||
if (!copy_from_user(&fds, fds_unsafe))
|
||||
return -EFAULT;
|
||||
for (int fd = 0; fd < params.nfds; ++fd) {
|
||||
if (FD_ISSET(fd, &fds)) {
|
||||
if (!file_description(fd)) {
|
||||
dbg() << "sys$select: Bad fd number " << fd;
|
||||
return -EBADF;
|
||||
|
@ -101,47 +96,42 @@ int Process::sys$select(const Syscall::SC_select_params* params)
|
|||
}
|
||||
return 0;
|
||||
};
|
||||
if (int error = transfer_fds(writefds, wfds))
|
||||
if (int error = transfer_fds(params.writefds, wfds))
|
||||
return error;
|
||||
if (int error = transfer_fds(readfds, rfds))
|
||||
if (int error = transfer_fds(params.readfds, rfds))
|
||||
return error;
|
||||
if (int error = transfer_fds(exceptfds, efds))
|
||||
if (int error = transfer_fds(params.exceptfds, efds))
|
||||
return error;
|
||||
|
||||
#if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT)
|
||||
dbg() << "selecting on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << timeout;
|
||||
dbg() << "selecting on (read:" << rfds.size() << ", write:" << wfds.size() << "), timeout=" << params.timeout;
|
||||
#endif
|
||||
|
||||
if (!timeout || select_has_timeout) {
|
||||
if (!params.timeout || select_has_timeout) {
|
||||
if (current_thread->block<Thread::SelectBlocker>(select_has_timeout ? &computed_timeout : nullptr, rfds, wfds, efds).was_interrupted())
|
||||
return -EINTR;
|
||||
// While we blocked, the process lock was dropped. This gave other threads
|
||||
// the opportunity to mess with the memory. For example, it could free the
|
||||
// region, and map it to a region to which it has no write permissions.
|
||||
// Therefore, we need to re-validate all pointers.
|
||||
if (writefds && !validate_write_typed(writefds))
|
||||
return -EFAULT;
|
||||
if (readfds && !validate_write_typed(readfds))
|
||||
return -EFAULT;
|
||||
// See the fixme below.
|
||||
if (exceptfds && !validate_write_typed(exceptfds))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int marked_fd_count = 0;
|
||||
auto mark_fds = [&](auto* fds, auto& vector, auto should_mark) {
|
||||
if (!fds)
|
||||
return;
|
||||
FD_ZERO(fds);
|
||||
auto mark_fds = [&](auto* fds_unsafe, auto& vector, auto should_mark) {
|
||||
if (!fds_unsafe)
|
||||
return 0;
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
for (int fd : vector) {
|
||||
if (auto description = file_description(fd); description && should_mark(*description)) {
|
||||
FD_SET(fd, fds);
|
||||
FD_SET(fd, &fds);
|
||||
++marked_fd_count;
|
||||
}
|
||||
}
|
||||
if (!copy_to_user(fds_unsafe, &fds))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
};
|
||||
mark_fds(readfds, rfds, [](auto& description) { return description.can_read(); });
|
||||
mark_fds(writefds, wfds, [](auto& description) { return description.can_write(); });
|
||||
if (int error = mark_fds(params.readfds, rfds, [](auto& description) { return description.can_read(); }))
|
||||
return error;
|
||||
if (int error = mark_fds(params.writefds, wfds, [](auto& description) { return description.can_write(); }))
|
||||
return error;
|
||||
// FIXME: We should also mark exceptfds as appropriate.
|
||||
|
||||
return marked_fd_count;
|
||||
|
@ -153,33 +143,39 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
|
|||
|
||||
// FIXME: Return -EINVAL if timeout is invalid.
|
||||
Syscall::SC_poll_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
SmapDisabler disabler;
|
||||
|
||||
pollfd* fds = params.fds;
|
||||
unsigned nfds = params.nfds;
|
||||
|
||||
if (fds && !validate_read_typed(fds, nfds))
|
||||
return -EFAULT;
|
||||
|
||||
timespec timeout = {};
|
||||
if (params.timeout && !validate_read_and_copy_typed(&timeout, params.timeout))
|
||||
if (params.timeout && !copy_from_user(&timeout, params.timeout))
|
||||
return -EFAULT;
|
||||
|
||||
sigset_t sigmask = {};
|
||||
if (params.sigmask && !validate_read_and_copy_typed(&sigmask, params.sigmask))
|
||||
if (params.sigmask && !copy_from_user(&sigmask, params.sigmask))
|
||||
return -EFAULT;
|
||||
|
||||
Vector<pollfd> fds_copy;
|
||||
if (params.nfds > 0) {
|
||||
Checked nfds_checked = sizeof(pollfd);
|
||||
nfds_checked *= params.nfds;
|
||||
if (nfds_checked.has_overflow())
|
||||
return -EFAULT;
|
||||
fds_copy.resize(params.nfds);
|
||||
if (!copy_from_user(&fds_copy[0], ¶ms.fds[0], params.nfds * sizeof(pollfd)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
Thread::SelectBlocker::FDVector rfds;
|
||||
Thread::SelectBlocker::FDVector wfds;
|
||||
|
||||
for (unsigned i = 0; i < nfds; ++i) {
|
||||
if (fds[i].events & POLLIN)
|
||||
rfds.append(fds[i].fd);
|
||||
if (fds[i].events & POLLOUT)
|
||||
wfds.append(fds[i].fd);
|
||||
for (unsigned i = 0; i < params.nfds; ++i) {
|
||||
auto& pfd = fds_copy[i];
|
||||
if (pfd.events & POLLIN)
|
||||
rfds.append(pfd.fd);
|
||||
if (pfd.events & POLLOUT)
|
||||
wfds.append(pfd.fd);
|
||||
}
|
||||
|
||||
timespec actual_timeout;
|
||||
|
@ -195,7 +191,7 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
|
|||
|
||||
u32 previous_signal_mask = 0;
|
||||
if (params.sigmask)
|
||||
previous_signal_mask = current_thread->update_signal_mask(params.sigmask);
|
||||
previous_signal_mask = current_thread->update_signal_mask(sigmask);
|
||||
ScopeGuard rollback_signal_mask([&]() {
|
||||
if (params.sigmask)
|
||||
current_thread->update_signal_mask(previous_signal_mask);
|
||||
|
@ -210,28 +206,28 @@ int Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
|
|||
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) {
|
||||
auto description = file_description(fds[i].fd);
|
||||
for (unsigned i = 0; i < params.nfds; ++i) {
|
||||
auto& pfd = fds_copy[i];
|
||||
auto description = file_description(pfd.fd);
|
||||
if (!description) {
|
||||
fds[i].revents = POLLNVAL;
|
||||
continue;
|
||||
}
|
||||
fds[i].revents = 0;
|
||||
if (fds[i].events & POLLIN && description->can_read())
|
||||
fds[i].revents |= POLLIN;
|
||||
if (fds[i].events & POLLOUT && description->can_write())
|
||||
fds[i].revents |= POLLOUT;
|
||||
pfd.revents = POLLNVAL;
|
||||
} else {
|
||||
pfd.revents = 0;
|
||||
if (pfd.events & POLLIN && description->can_read())
|
||||
pfd.revents |= POLLIN;
|
||||
if (pfd.events & POLLOUT && description->can_write())
|
||||
pfd.revents |= POLLOUT;
|
||||
|
||||
if (fds[i].revents)
|
||||
++fds_with_revents;
|
||||
if (pfd.revents)
|
||||
++fds_with_revents;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.nfds > 0 && !copy_to_user(¶ms.fds[0], &fds_copy[0], params.nfds * sizeof(pollfd)))
|
||||
return -EFAULT;
|
||||
|
||||
return fds_with_revents;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,25 +37,20 @@ int Process::sys$setkeymap(Userspace<const Syscall::SC_setkeymap_params*> user_p
|
|||
return -EPERM;
|
||||
|
||||
Syscall::SC_setkeymap_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
Keyboard::CharacterMapData character_map_data;
|
||||
|
||||
if (!validate_read(params.map, CHAR_MAP_SIZE))
|
||||
if (!copy_from_user(character_map_data.map, params.map, CHAR_MAP_SIZE * sizeof(u32)))
|
||||
return -EFAULT;
|
||||
if (!validate_read(params.shift_map, CHAR_MAP_SIZE))
|
||||
if (!copy_from_user(character_map_data.shift_map, params.shift_map, CHAR_MAP_SIZE * sizeof(u32)))
|
||||
return -EFAULT;
|
||||
if (!validate_read(params.alt_map, CHAR_MAP_SIZE))
|
||||
if (!copy_from_user(character_map_data.alt_map, params.alt_map, CHAR_MAP_SIZE * sizeof(u32)))
|
||||
return -EFAULT;
|
||||
if (!validate_read(params.altgr_map, CHAR_MAP_SIZE))
|
||||
if (!copy_from_user(character_map_data.altgr_map, params.altgr_map, CHAR_MAP_SIZE * sizeof(u32)))
|
||||
return -EFAULT;
|
||||
|
||||
copy_from_user(character_map_data.map, params.map, CHAR_MAP_SIZE * sizeof(u32));
|
||||
copy_from_user(character_map_data.shift_map, params.shift_map, CHAR_MAP_SIZE * sizeof(u32));
|
||||
copy_from_user(character_map_data.alt_map, params.alt_map, CHAR_MAP_SIZE * sizeof(u32));
|
||||
copy_from_user(character_map_data.altgr_map, params.altgr_map, CHAR_MAP_SIZE * sizeof(u32));
|
||||
|
||||
auto map_name = get_syscall_path_argument(params.map_name);
|
||||
if (map_name.is_error()) {
|
||||
return map_name.error();
|
||||
|
|
|
@ -125,8 +125,6 @@ int Process::sys$setgroups(ssize_t count, Userspace<const gid_t*> user_gids)
|
|||
return -EINVAL;
|
||||
if (!is_superuser())
|
||||
return -EPERM;
|
||||
if (count && !validate_read(user_gids, count))
|
||||
return -EFAULT;
|
||||
|
||||
if (!count) {
|
||||
m_extra_gids.clear();
|
||||
|
@ -135,7 +133,8 @@ int Process::sys$setgroups(ssize_t count, Userspace<const gid_t*> user_gids)
|
|||
|
||||
Vector<gid_t> gids;
|
||||
gids.resize(count);
|
||||
copy_from_user(gids.data(), user_gids, sizeof(gid_t) * count);
|
||||
if (!copy_from_user(gids.data(), user_gids.unsafe_userspace_ptr(), sizeof(gid_t) * count))
|
||||
return -EFAULT;
|
||||
|
||||
HashTable<gid_t> unique_extra_gids;
|
||||
for (auto& gid : gids) {
|
||||
|
|
|
@ -47,8 +47,6 @@ int Process::sys$shbuf_create(int size, void** buffer)
|
|||
if (!size || size < 0)
|
||||
return -EINVAL;
|
||||
size = PAGE_ROUND_UP(size);
|
||||
if (!validate_write_typed(buffer))
|
||||
return -EFAULT;
|
||||
|
||||
LOCKER(shared_buffers().lock());
|
||||
static int s_next_shbuf_id;
|
||||
|
@ -57,7 +55,8 @@ int Process::sys$shbuf_create(int size, void** buffer)
|
|||
shared_buffer->share_with(m_pid);
|
||||
|
||||
void* address = shared_buffer->ref_for_process_and_get_address(*this);
|
||||
copy_to_user(buffer, &address);
|
||||
if (!copy_to_user(buffer, &address))
|
||||
return -EFAULT;
|
||||
ASSERT((int)shared_buffer->size() >= size);
|
||||
#ifdef SHARED_BUFFER_DEBUG
|
||||
klog() << "Created shared buffer " << shbuf_id << " @ " << buffer << " (" << size << " bytes, vmobject is " << shared_buffer->size() << ")";
|
||||
|
@ -123,8 +122,6 @@ int Process::sys$shbuf_release(int shbuf_id)
|
|||
void* Process::sys$shbuf_get(int shbuf_id, Userspace<size_t*> user_size)
|
||||
{
|
||||
REQUIRE_PROMISE(shared_buffer);
|
||||
if (user_size && !validate_write_typed(user_size))
|
||||
return (void*)-EFAULT;
|
||||
LOCKER(shared_buffers().lock());
|
||||
auto it = shared_buffers().resource().find(shbuf_id);
|
||||
if (it == shared_buffers().resource().end())
|
||||
|
@ -137,7 +134,8 @@ void* Process::sys$shbuf_get(int shbuf_id, Userspace<size_t*> user_size)
|
|||
#endif
|
||||
if (user_size) {
|
||||
size_t size = shared_buffer.size();
|
||||
copy_to_user(user_size, &size);
|
||||
if (!copy_to_user(user_size, &size))
|
||||
return (void*)-EFAULT;
|
||||
}
|
||||
return shared_buffer.ref_for_process_and_get_address(*this);
|
||||
}
|
||||
|
|
|
@ -34,10 +34,9 @@ int Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<
|
|||
auto current_thread = Thread::current();
|
||||
u32 previous_signal_mask;
|
||||
if (set) {
|
||||
if (!validate_read_typed(set))
|
||||
return -EFAULT;
|
||||
sigset_t set_value;
|
||||
copy_from_user(&set_value, set);
|
||||
if (!copy_from_user(&set_value, set))
|
||||
return -EFAULT;
|
||||
switch (how) {
|
||||
case SIG_BLOCK:
|
||||
previous_signal_mask = current_thread->signal_mask_block(set_value, true);
|
||||
|
@ -54,21 +53,17 @@ int Process::sys$sigprocmask(int how, Userspace<const sigset_t*> set, Userspace<
|
|||
} else {
|
||||
previous_signal_mask = current_thread->signal_mask();
|
||||
}
|
||||
if (old_set) {
|
||||
if (!validate_write_typed(old_set))
|
||||
return -EFAULT;
|
||||
copy_to_user(old_set, &previous_signal_mask);
|
||||
}
|
||||
if (old_set && !copy_to_user(old_set, &previous_signal_mask))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$sigpending(Userspace<sigset_t*> set)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(set))
|
||||
return -EFAULT;
|
||||
auto pending_signals = Thread::current()->pending_signals();
|
||||
copy_to_user(set, &pending_signals);
|
||||
if (!copy_to_user(set, &pending_signals))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -77,18 +72,18 @@ int Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act)
|
|||
REQUIRE_PROMISE(sigaction);
|
||||
if (signum < 1 || signum >= 32 || signum == SIGKILL || signum == SIGSTOP)
|
||||
return -EINVAL;
|
||||
if (!validate_read_typed(act))
|
||||
return -EFAULT;
|
||||
InterruptDisabler disabler; // FIXME: This should use a narrower lock. Maybe a way to ignore signals temporarily?
|
||||
auto& action = Thread::current()->m_signal_action_data[signum];
|
||||
if (old_act) {
|
||||
if (!validate_write_typed(old_act))
|
||||
if (!copy_to_user(&old_act->sa_flags, &action.flags))
|
||||
return -EFAULT;
|
||||
if (!copy_to_user(&old_act->sa_sigaction, &action.handler_or_sigaction, sizeof(action.handler_or_sigaction)))
|
||||
return -EFAULT;
|
||||
copy_to_user(&old_act->sa_flags, &action.flags);
|
||||
copy_to_user(&old_act->sa_sigaction, &action.handler_or_sigaction, sizeof(action.handler_or_sigaction));
|
||||
}
|
||||
copy_from_user(&action.flags, &act->sa_flags);
|
||||
copy_from_user(&action.handler_or_sigaction, &act->sa_sigaction, sizeof(action.handler_or_sigaction));
|
||||
if (!copy_from_user(&action.flags, &act->sa_flags))
|
||||
return -EFAULT;
|
||||
if (!copy_from_user(&action.handler_or_sigaction, &act->sa_sigaction, sizeof(action.handler_or_sigaction)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,6 @@ int Process::sys$socket(int domain, int type, int protocol)
|
|||
|
||||
int Process::sys$bind(int sockfd, Userspace<const sockaddr*> address, socklen_t address_length)
|
||||
{
|
||||
if (!validate_read(address, address_length))
|
||||
return -EFAULT;
|
||||
auto description = file_description(sockfd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
|
@ -98,14 +96,8 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
|
|||
REQUIRE_PROMISE(accept);
|
||||
|
||||
socklen_t address_size = 0;
|
||||
if (user_address) {
|
||||
if (!validate_write_typed(user_address_size))
|
||||
return -EFAULT;
|
||||
if (!validate_read_and_copy_typed(&address_size, user_address_size))
|
||||
return -EFAULT;
|
||||
if (!validate_write(user_address, address_size))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (user_address && !copy_from_user(&address_size, static_ptr_cast<const socklen_t*>(user_address_size)))
|
||||
return -EFAULT;
|
||||
|
||||
int accepted_socket_fd = alloc_fd();
|
||||
if (accepted_socket_fd < 0)
|
||||
|
@ -132,8 +124,10 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
|
|||
u8 address_buffer[sizeof(sockaddr_un)];
|
||||
address_size = min(sizeof(sockaddr_un), static_cast<size_t>(address_size));
|
||||
accepted_socket->get_peer_address((sockaddr*)address_buffer, &address_size);
|
||||
copy_to_user(user_address, address_buffer, address_size);
|
||||
copy_to_user(user_address_size, &address_size);
|
||||
if (!copy_to_user(user_address, address_buffer, address_size))
|
||||
return -EFAULT;
|
||||
if (!copy_to_user(user_address_size, &address_size))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
auto accepted_socket_description = FileDescription::create(*accepted_socket);
|
||||
|
@ -151,8 +145,6 @@ int Process::sys$accept(int accepting_socket_fd, Userspace<sockaddr*> user_addre
|
|||
|
||||
int Process::sys$connect(int sockfd, Userspace<const sockaddr*> user_address, socklen_t user_address_size)
|
||||
{
|
||||
if (!validate_read(user_address, user_address_size))
|
||||
return -EFAULT;
|
||||
int fd = alloc_fd();
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
@ -165,11 +157,7 @@ int Process::sys$connect(int sockfd, Userspace<const sockaddr*> user_address, so
|
|||
auto& socket = *description->socket();
|
||||
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
|
||||
|
||||
u8 address[sizeof(sockaddr_un)];
|
||||
size_t address_size = min(sizeof(address), static_cast<size_t>(user_address_size));
|
||||
copy_from_user(address, user_address, address_size);
|
||||
|
||||
return socket.connect(*description, (const sockaddr*)address, address_size, description->is_blocking() ? ShouldBlock::Yes : ShouldBlock::No);
|
||||
return socket.connect(*description, user_address, user_address_size, description->is_blocking() ? ShouldBlock::Yes : ShouldBlock::No);
|
||||
}
|
||||
|
||||
int Process::sys$shutdown(int sockfd, int how)
|
||||
|
@ -192,17 +180,13 @@ ssize_t Process::sys$sendto(Userspace<const Syscall::SC_sendto_params*> user_par
|
|||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
Syscall::SC_sendto_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
int flags = params.flags;
|
||||
Userspace<const sockaddr*> addr = params.addr;
|
||||
Userspace<const sockaddr*> addr((FlatPtr)params.addr);
|
||||
socklen_t addr_length = params.addr_length;
|
||||
|
||||
if (!validate(params.data))
|
||||
return -EFAULT;
|
||||
if (addr && !validate_read(addr, addr_length))
|
||||
return -EFAULT;
|
||||
auto description = file_description(params.sockfd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
|
@ -212,7 +196,10 @@ ssize_t Process::sys$sendto(Userspace<const Syscall::SC_sendto_params*> user_par
|
|||
if (socket.is_shut_down_for_writing())
|
||||
return -EPIPE;
|
||||
SmapDisabler disabler;
|
||||
auto result = socket.sendto(*description, params.data.data, params.data.size, flags, addr, addr_length);
|
||||
auto data_buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>((const u8*)params.data.data), params.data.size);
|
||||
if (!data_buffer.has_value())
|
||||
return -EFAULT;
|
||||
auto result = socket.sendto(*description, data_buffer.value(), params.data.size, flags, addr, addr_length);
|
||||
if (result.is_error())
|
||||
return result.error();
|
||||
return result.value();
|
||||
|
@ -223,27 +210,17 @@ ssize_t Process::sys$recvfrom(Userspace<const Syscall::SC_recvfrom_params*> user
|
|||
REQUIRE_PROMISE(stdio);
|
||||
|
||||
Syscall::SC_recvfrom_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
int flags = params.flags;
|
||||
Userspace<sockaddr*> user_addr = params.addr;
|
||||
Userspace<socklen_t*> user_addr_length = params.addr_length;
|
||||
Userspace<sockaddr*> user_addr((FlatPtr)params.addr);
|
||||
Userspace<socklen_t*> user_addr_length((FlatPtr)params.addr_length);
|
||||
|
||||
SmapDisabler disabler;
|
||||
if (!validate(params.buffer))
|
||||
return -EFAULT;
|
||||
if (user_addr_length) {
|
||||
socklen_t addr_length;
|
||||
if (!validate_read_and_copy_typed(&addr_length, user_addr_length))
|
||||
return -EFAULT;
|
||||
if (!validate_write_typed(user_addr_length))
|
||||
return -EFAULT;
|
||||
if (!validate_write(user_addr, addr_length))
|
||||
return -EFAULT;
|
||||
} else if (user_addr) {
|
||||
if (!user_addr_length && user_addr)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
auto description = file_description(params.sockfd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
|
@ -258,7 +235,10 @@ ssize_t Process::sys$recvfrom(Userspace<const Syscall::SC_recvfrom_params*> user
|
|||
if (flags & MSG_DONTWAIT)
|
||||
description->set_blocking(false);
|
||||
|
||||
auto result = socket.recvfrom(*description, params.buffer.data, params.buffer.size, flags, user_addr, user_addr_length);
|
||||
auto data_buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>((const u8*)params.buffer.data), params.buffer.size);
|
||||
if (!data_buffer.has_value())
|
||||
return -EFAULT;
|
||||
auto result = socket.recvfrom(*description, data_buffer.value(), params.buffer.size, flags, user_addr, user_addr_length);
|
||||
if (flags & MSG_DONTWAIT)
|
||||
description->set_blocking(original_blocking);
|
||||
|
||||
|
@ -271,18 +251,12 @@ template<bool sockname, typename Params>
|
|||
int Process::get_sock_or_peer_name(const Params& params)
|
||||
{
|
||||
socklen_t addrlen_value;
|
||||
if (!validate_read_and_copy_typed(&addrlen_value, params.addrlen))
|
||||
if (!copy_from_user(&addrlen_value, params.addrlen, sizeof(socklen_t)))
|
||||
return -EFAULT;
|
||||
|
||||
if (addrlen_value <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!validate_write(params.addr, addrlen_value))
|
||||
return -EFAULT;
|
||||
|
||||
if (!validate_write_typed(params.addrlen))
|
||||
return -EFAULT;
|
||||
|
||||
auto description = file_description(params.sockfd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
|
@ -299,15 +273,17 @@ int Process::get_sock_or_peer_name(const Params& params)
|
|||
socket.get_local_address((sockaddr*)address_buffer, &addrlen_value);
|
||||
else
|
||||
socket.get_peer_address((sockaddr*)address_buffer, &addrlen_value);
|
||||
copy_to_user(params.addr, address_buffer, addrlen_value);
|
||||
copy_to_user(params.addrlen, &addrlen_value);
|
||||
if (!copy_to_user(params.addr, address_buffer, addrlen_value))
|
||||
return -EFAULT;
|
||||
if (!copy_to_user(params.addrlen, &addrlen_value))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$getsockname(Userspace<const Syscall::SC_getsockname_params*> user_params)
|
||||
{
|
||||
Syscall::SC_getsockname_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
return get_sock_or_peer_name<true>(params);
|
||||
}
|
||||
|
@ -315,7 +291,7 @@ int Process::sys$getsockname(Userspace<const Syscall::SC_getsockname_params*> us
|
|||
int Process::sys$getpeername(Userspace<const Syscall::SC_getpeername_params*> user_params)
|
||||
{
|
||||
Syscall::SC_getpeername_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
return get_sock_or_peer_name<false>(params);
|
||||
}
|
||||
|
@ -323,22 +299,19 @@ int Process::sys$getpeername(Userspace<const Syscall::SC_getpeername_params*> us
|
|||
int Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user_params)
|
||||
{
|
||||
Syscall::SC_getsockopt_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
int sockfd = params.sockfd;
|
||||
int level = params.level;
|
||||
int option = params.option;
|
||||
Userspace<void*> user_value = params.value;
|
||||
Userspace<socklen_t*> user_value_size = params.value_size;
|
||||
Userspace<void*> user_value((FlatPtr)params.value);
|
||||
Userspace<socklen_t*> user_value_size((FlatPtr)params.value_size);
|
||||
|
||||
if (!validate_write_typed(user_value_size))
|
||||
return -EFAULT;
|
||||
socklen_t value_size;
|
||||
if (!validate_read_and_copy_typed(&value_size, user_value_size))
|
||||
return -EFAULT;
|
||||
if (!validate_write(user_value, value_size))
|
||||
if (!copy_from_user(&value_size, params.value_size, sizeof(socklen_t)))
|
||||
return -EFAULT;
|
||||
|
||||
auto description = file_description(sockfd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
|
@ -357,10 +330,9 @@ int Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user
|
|||
int Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*> user_params)
|
||||
{
|
||||
Syscall::SC_setsockopt_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
if (!validate_read(params.value, params.value_size))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
Userspace<const void*> user_value((FlatPtr)params.value);
|
||||
auto description = file_description(params.sockfd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
|
@ -368,7 +340,7 @@ int Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*> user
|
|||
return -ENOTSOCK;
|
||||
auto& socket = *description->socket();
|
||||
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
|
||||
return socket.setsockopt(params.level, params.option, params.value, params.value_size);
|
||||
return socket.setsockopt(params.level, params.option, user_value, params.value_size);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,14 +34,13 @@ namespace Kernel {
|
|||
int Process::sys$fstat(int fd, Userspace<stat*> user_statbuf)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(user_statbuf))
|
||||
return -EFAULT;
|
||||
auto description = file_description(fd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
stat buffer = {};
|
||||
int rc = description->stat(buffer);
|
||||
copy_to_user(user_statbuf, &buffer);
|
||||
if (!copy_to_user(user_statbuf, &buffer))
|
||||
return -EFAULT;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -49,9 +48,7 @@ int Process::sys$stat(Userspace<const Syscall::SC_stat_params*> user_params)
|
|||
{
|
||||
REQUIRE_PROMISE(rpath);
|
||||
Syscall::SC_stat_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
if (!validate_write_typed(params.statbuf))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
auto path = get_syscall_path_argument(params.path);
|
||||
if (path.is_error())
|
||||
|
@ -63,7 +60,8 @@ int Process::sys$stat(Userspace<const Syscall::SC_stat_params*> user_params)
|
|||
auto result = metadata_or_error.value().stat(statbuf);
|
||||
if (result.is_error())
|
||||
return result;
|
||||
copy_to_user(params.statbuf, &statbuf);
|
||||
if (!copy_to_user(params.statbuf, &statbuf))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,22 +36,16 @@ namespace Kernel {
|
|||
int Process::sys$create_thread(void* (*entry)(void*), Userspace<const Syscall::SC_create_thread_params*> user_params)
|
||||
{
|
||||
REQUIRE_PROMISE(thread);
|
||||
if (!validate_read((const void*)entry, sizeof(void*)))
|
||||
return -EFAULT;
|
||||
|
||||
Syscall::SC_create_thread_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
unsigned detach_state = params.m_detach_state;
|
||||
int schedule_priority = params.m_schedule_priority;
|
||||
Userspace<void*> stack_location = params.m_stack_location;
|
||||
unsigned stack_size = params.m_stack_size;
|
||||
|
||||
if (!validate_write(stack_location, stack_size))
|
||||
return -EFAULT;
|
||||
|
||||
u32 user_stack_address = reinterpret_cast<u32>(stack_location.ptr()) + stack_size;
|
||||
auto user_stack_address = (u8*)params.m_stack_location + stack_size;
|
||||
|
||||
if (!MM.validate_user_stack(*this, VirtualAddress(user_stack_address - 4)))
|
||||
return -EFAULT;
|
||||
|
@ -83,7 +77,7 @@ int Process::sys$create_thread(void* (*entry)(void*), Userspace<const Syscall::S
|
|||
tss.eip = (FlatPtr)entry;
|
||||
tss.eflags = 0x0202;
|
||||
tss.cr3 = page_directory().cr3();
|
||||
tss.esp = user_stack_address;
|
||||
tss.esp = (u32)user_stack_address;
|
||||
|
||||
thread->make_thread_specific_region({});
|
||||
thread->set_state(Thread::State::Runnable);
|
||||
|
@ -120,8 +114,6 @@ int Process::sys$detach_thread(pid_t tid)
|
|||
int Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value)
|
||||
{
|
||||
REQUIRE_PROMISE(thread);
|
||||
if (exit_value && !validate_write_typed(exit_value))
|
||||
return -EFAULT;
|
||||
|
||||
InterruptDisabler disabler;
|
||||
auto* thread = Thread::from_tid(tid);
|
||||
|
@ -164,15 +156,15 @@ int Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value)
|
|||
// NOTE: 'thread' is very possibly deleted at this point. Clear it just to be safe.
|
||||
thread = nullptr;
|
||||
|
||||
if (exit_value)
|
||||
copy_to_user(exit_value, &joinee_exit_value);
|
||||
if (exit_value && !copy_to_user(exit_value, &joinee_exit_value))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$set_thread_name(pid_t tid, Userspace<const char*> user_name, size_t user_name_length)
|
||||
{
|
||||
REQUIRE_PROMISE(thread);
|
||||
auto name = validate_and_copy_string_from_user(user_name, user_name_length);
|
||||
auto name = copy_string_from_user(user_name, user_name_length);
|
||||
if (name.is_null())
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -185,7 +177,7 @@ int Process::sys$set_thread_name(pid_t tid, Userspace<const char*> user_name, si
|
|||
if (!thread || thread->pid() != pid())
|
||||
return -ESRCH;
|
||||
|
||||
thread->set_name(name);
|
||||
thread->set_name(move(name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -195,9 +187,6 @@ int Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buff
|
|||
if (buffer_size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!validate_write(buffer, buffer_size))
|
||||
return -EFAULT;
|
||||
|
||||
InterruptDisabler disabler;
|
||||
auto* thread = Thread::from_tid(tid);
|
||||
if (!thread || thread->pid() != pid())
|
||||
|
@ -206,7 +195,8 @@ int Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buff
|
|||
if (thread->name().length() + 1 > (size_t)buffer_size)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
copy_to_user(buffer, thread->name().characters(), thread->name().length() + 1);
|
||||
if (!copy_to_user(buffer, thread->name().characters(), thread->name().length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,16 +31,14 @@ namespace Kernel {
|
|||
clock_t Process::sys$times(Userspace<tms*> user_times)
|
||||
{
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(user_times))
|
||||
return -EFAULT;
|
||||
|
||||
tms times = {};
|
||||
times.tms_utime = m_ticks_in_user;
|
||||
times.tms_stime = m_ticks_in_kernel;
|
||||
times.tms_cutime = m_ticks_in_user_for_dead_children;
|
||||
times.tms_cstime = m_ticks_in_kernel_for_dead_children;
|
||||
|
||||
copy_to_user(user_times, ×);
|
||||
if (!copy_to_user(user_times, ×))
|
||||
return -EFAULT;
|
||||
|
||||
return g_uptime & 0x7fffffff;
|
||||
}
|
||||
|
|
|
@ -34,8 +34,6 @@ namespace Kernel {
|
|||
int Process::sys$ttyname(int fd, Userspace<char*> buffer, size_t size)
|
||||
{
|
||||
REQUIRE_PROMISE(tty);
|
||||
if (!validate_write(buffer, size))
|
||||
return -EFAULT;
|
||||
auto description = file_description(fd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
|
@ -44,15 +42,14 @@ int Process::sys$ttyname(int fd, Userspace<char*> buffer, size_t size)
|
|||
auto tty_name = description->tty()->tty_name();
|
||||
if (size < tty_name.length() + 1)
|
||||
return -ERANGE;
|
||||
copy_to_user(buffer, tty_name.characters(), tty_name.length() + 1);
|
||||
if (!copy_to_user(buffer, tty_name.characters(), tty_name.length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$ptsname(int fd, Userspace<char*> buffer, size_t size)
|
||||
{
|
||||
REQUIRE_PROMISE(tty);
|
||||
if (!validate_write(buffer, size))
|
||||
return -EFAULT;
|
||||
auto description = file_description(fd);
|
||||
if (!description)
|
||||
return -EBADF;
|
||||
|
@ -62,7 +59,8 @@ int Process::sys$ptsname(int fd, Userspace<char*> buffer, size_t size)
|
|||
auto pts_name = master_pty->pts_name();
|
||||
if (size < pts_name.length() + 1)
|
||||
return -ERANGE;
|
||||
copy_to_user(buffer, pts_name.characters(), pts_name.length() + 1);
|
||||
if (!copy_to_user(buffer, pts_name.characters(), pts_name.length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,9 +34,6 @@ int Process::sys$uname(Userspace<utsname*> buf)
|
|||
extern Lock* g_hostname_lock;
|
||||
|
||||
REQUIRE_PROMISE(stdio);
|
||||
if (!validate_write_typed(buf))
|
||||
return -EFAULT;
|
||||
|
||||
|
||||
LOCKER(*g_hostname_lock, Lock::Mode::Shared);
|
||||
if (g_hostname->length() + 1 > sizeof(utsname::nodename))
|
||||
|
@ -45,11 +42,16 @@ int Process::sys$uname(Userspace<utsname*> buf)
|
|||
// We have already validated the entire utsname struct at this
|
||||
// point, there is no need to re-validate every write to the struct.
|
||||
utsname* user_buf = buf.unsafe_userspace_ptr();
|
||||
copy_to_user(user_buf->sysname, "SerenityOS", 11);
|
||||
copy_to_user(user_buf->release, "1.0-dev", 8);
|
||||
copy_to_user(user_buf->version, "FIXME", 6);
|
||||
copy_to_user(user_buf->machine, "i686", 5);
|
||||
copy_to_user(user_buf->nodename, g_hostname->characters(), g_hostname->length() + 1);
|
||||
if (!copy_to_user(user_buf->sysname, "SerenityOS", 11))
|
||||
return -EFAULT;
|
||||
if (!copy_to_user(user_buf->release, "1.0-dev", 8))
|
||||
return -EFAULT;
|
||||
if (!copy_to_user(user_buf->version, "FIXME", 6))
|
||||
return -EFAULT;
|
||||
if (!copy_to_user(user_buf->machine, "i686", 5))
|
||||
return -EFAULT;
|
||||
if (!copy_to_user(user_buf->nodename, g_hostname->characters(), g_hostname->length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,8 +33,6 @@ namespace Kernel {
|
|||
int Process::sys$unlink(Userspace<const char*> user_path, size_t path_length)
|
||||
{
|
||||
REQUIRE_PROMISE(cpath);
|
||||
if (!validate_read(user_path, path_length))
|
||||
return -EFAULT;
|
||||
auto path = get_syscall_path_argument(user_path, path_length);
|
||||
if (path.is_error())
|
||||
return path.error();
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace Kernel {
|
|||
int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
|
||||
{
|
||||
Syscall::SC_unveil_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (!params.path.characters && !params.permissions.characters) {
|
||||
|
@ -66,7 +66,7 @@ int Process::sys$unveil(Userspace<const Syscall::SC_unveil_params*> user_params)
|
|||
auto& custody = custody_or_error.value();
|
||||
auto new_unveiled_path = custody->absolute_path();
|
||||
|
||||
auto permissions = validate_and_copy_string_from_user(params.permissions);
|
||||
auto permissions = copy_string_from_user(params.permissions);
|
||||
if (permissions.is_null())
|
||||
return -EFAULT;
|
||||
|
||||
|
|
|
@ -33,14 +33,13 @@ namespace Kernel {
|
|||
int Process::sys$utime(Userspace<const char*> user_path, size_t path_length, Userspace<const struct utimbuf*> user_buf)
|
||||
{
|
||||
REQUIRE_PROMISE(fattr);
|
||||
if (user_buf && !validate_read_typed(user_buf))
|
||||
return -EFAULT;
|
||||
auto path = get_syscall_path_argument(user_path, path_length);
|
||||
if (path.is_error())
|
||||
return path.error();
|
||||
utimbuf buf;
|
||||
if (user_buf) {
|
||||
copy_from_user(&buf, user_buf);
|
||||
if (!copy_from_user(&buf, user_buf))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
auto now = kgettimeofday();
|
||||
buf = { now.tv_sec, now.tv_sec };
|
||||
|
|
|
@ -104,27 +104,19 @@ pid_t Process::sys$waitid(Userspace<const Syscall::SC_waitid_params*> user_param
|
|||
REQUIRE_PROMISE(proc);
|
||||
|
||||
Syscall::SC_waitid_params params;
|
||||
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
if (!validate_write_typed(params.infop))
|
||||
if (!copy_from_user(¶ms, user_params))
|
||||
return -EFAULT;
|
||||
|
||||
#ifdef PROCESS_DEBUG
|
||||
dbg() << "sys$waitid(" << params.idtype << ", " << params.id << ", " << params.infop.ptr() << ", " << params.options << ")";
|
||||
dbg() << "sys$waitid(" << params.idtype << ", " << params.id << ", " << params.infop << ", " << params.options << ")";
|
||||
#endif
|
||||
|
||||
auto siginfo_or_error = do_waitid(static_cast<idtype_t>(params.idtype), params.id, params.options);
|
||||
if (siginfo_or_error.is_error())
|
||||
return siginfo_or_error.error();
|
||||
// While we waited, the process lock was dropped. This gave other threads
|
||||
// the opportunity to mess with the memory. For example, it could free the
|
||||
// region, and map it to a region to which it has no write permissions.
|
||||
// Therefore, we need to re-validate the pointer.
|
||||
if (!validate_write_typed(params.infop))
|
||||
return -EFAULT;
|
||||
|
||||
copy_to_user(params.infop, &siginfo_or_error.value());
|
||||
if (!copy_to_user(params.infop, &siginfo_or_error.value()))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,16 +36,19 @@ ssize_t Process::sys$writev(int fd, const struct iovec* iov, int iov_count)
|
|||
if (iov_count < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!validate_read_typed(iov, iov_count))
|
||||
return -EFAULT;
|
||||
{
|
||||
Checked checked_iov_count = sizeof(iovec);
|
||||
checked_iov_count *= iov_count;
|
||||
if (checked_iov_count.has_overflow())
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
u64 total_length = 0;
|
||||
Vector<iovec, 32> vecs;
|
||||
vecs.resize(iov_count);
|
||||
copy_from_user(vecs.data(), iov, iov_count * sizeof(iovec));
|
||||
if (!copy_n_from_user(vecs.data(), iov, iov_count))
|
||||
return -EFAULT;
|
||||
for (auto& vec : vecs) {
|
||||
if (!validate_read(vec.iov_base, vec.iov_len))
|
||||
return -EFAULT;
|
||||
total_length += vec.iov_len;
|
||||
if (total_length > NumericLimits<i32>::max())
|
||||
return -EINVAL;
|
||||
|
@ -60,7 +63,10 @@ ssize_t Process::sys$writev(int fd, const struct iovec* iov, int iov_count)
|
|||
|
||||
int nwritten = 0;
|
||||
for (auto& vec : vecs) {
|
||||
int rc = do_write(*description, (const u8*)vec.iov_base, vec.iov_len);
|
||||
auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len);
|
||||
if (!buffer.has_value())
|
||||
return -EFAULT;
|
||||
int rc = do_write(*description, buffer.value(), vec.iov_len);
|
||||
if (rc < 0) {
|
||||
if (nwritten == 0)
|
||||
return rc;
|
||||
|
@ -72,7 +78,7 @@ ssize_t Process::sys$writev(int fd, const struct iovec* iov, int iov_count)
|
|||
return nwritten;
|
||||
}
|
||||
|
||||
ssize_t Process::do_write(FileDescription& description, const u8* data, int data_size)
|
||||
ssize_t Process::do_write(FileDescription& description, const UserOrKernelBuffer& data, size_t data_size)
|
||||
{
|
||||
ssize_t total_nwritten = 0;
|
||||
if (!description.is_blocking()) {
|
||||
|
@ -83,7 +89,7 @@ ssize_t Process::do_write(FileDescription& description, const u8* data, int data
|
|||
if (description.should_append())
|
||||
description.seek(0, SEEK_END);
|
||||
|
||||
while (total_nwritten < data_size) {
|
||||
while ((size_t)total_nwritten < data_size) {
|
||||
if (!description.can_write()) {
|
||||
if (!description.is_blocking()) {
|
||||
// Short write: We can no longer write to this non-blocking description.
|
||||
|
@ -95,7 +101,7 @@ ssize_t Process::do_write(FileDescription& description, const u8* data, int data
|
|||
return -EINTR;
|
||||
}
|
||||
}
|
||||
auto nwritten_or_error = description.write(data + total_nwritten, data_size - total_nwritten);
|
||||
auto nwritten_or_error = description.write(data.offset(total_nwritten), data_size - total_nwritten);
|
||||
if (nwritten_or_error.is_error()) {
|
||||
if (total_nwritten)
|
||||
return total_nwritten;
|
||||
|
@ -115,8 +121,7 @@ ssize_t Process::sys$write(int fd, const u8* data, ssize_t size)
|
|||
return -EINVAL;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
if (!validate_read(data, size))
|
||||
return -EFAULT;
|
||||
|
||||
#ifdef DEBUG_IO
|
||||
dbg() << "sys$write(" << fd << ", " << (const void*)(data) << ", " << size << ")";
|
||||
#endif
|
||||
|
@ -126,7 +131,10 @@ ssize_t Process::sys$write(int fd, const u8* data, ssize_t size)
|
|||
if (!description->is_writable())
|
||||
return -EBADF;
|
||||
|
||||
return do_write(*description, data, size);
|
||||
auto buffer = UserOrKernelBuffer::for_user_buffer(const_cast<u8*>(data), (size_t)size);
|
||||
if (!buffer.has_value())
|
||||
return -EFAULT;
|
||||
return do_write(*description, buffer.value(), size);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue