diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 4ad7502a..09209a7d 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -121,6 +121,7 @@ set(KERNEL_SOURCES kernel/USB/USBManager.cpp kernel/USB/XHCI/Controller.cpp kernel/USB/XHCI/Device.cpp + kernel/UserCopy.cpp icxxabi.cpp ) diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 60b85a28..939342b0 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -284,9 +284,6 @@ namespace Kernel BAN::ErrorOr find_parent_file(int fd, const char* path, int flags) const; BAN::ErrorOr find_relative_parent(int fd, const char* path) const; - BAN::ErrorOr read_from_user(const void* user_addr, void* out, size_t size); - BAN::ErrorOr read_string_from_user(const char* user_addr, char* out, size_t max_size); - BAN::ErrorOr write_to_user(void* user_addr, const void* in, size_t size); BAN::ErrorOr validate_and_pin_pointer_access(const void*, size_t, bool needs_write); uint64_t signal_pending_mask() const diff --git a/kernel/include/kernel/UserCopy.h b/kernel/include/kernel/UserCopy.h new file mode 100644 index 00000000..ddf42263 --- /dev/null +++ b/kernel/include/kernel/UserCopy.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace Kernel +{ + + BAN::ErrorOr read_from_user(const void* user_addr, void* out, size_t size); + BAN::ErrorOr read_string_from_user(const char* user_addr, char* out, size_t max_size); + BAN::ErrorOr write_to_user(void* user_addr, const void* in, size_t size); + +}; diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index df04424c..482631b1 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -254,7 +255,7 @@ namespace Kernel if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) { struct flock flock; - TRY(Process::current().read_from_user(reinterpret_cast(extra), &flock, sizeof(struct flock))); + TRY(read_from_user(reinterpret_cast(extra), &flock, sizeof(struct flock))); flock.l_pid = Process::current().pid(); BAN::RefPtr inode; @@ -307,7 +308,7 @@ namespace Kernel } if (cmd == F_GETLK) - TRY(Process::current().write_to_user(reinterpret_cast(extra), &flock, sizeof(struct flock))); + TRY(write_to_user(reinterpret_cast(extra), &flock, sizeof(struct flock))); return 0; } diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 575ea665..2bd0307f 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -3885,47 +3886,6 @@ namespace Kernel return region->allocate_page_containing(address, wants_write); } - extern "C" bool safe_user_memcpy(void*, const void*, size_t); - extern "C" bool safe_user_strncpy(void*, const void*, size_t); - - static inline bool is_valid_user_address(const void* user_addr, size_t size) - { - const vaddr_t user_vaddr = reinterpret_cast(user_addr); - if (BAN::Math::will_addition_overflow(user_vaddr, size)) - return false; - if (user_vaddr + size > USERSPACE_END) - return false; - return true; - } - - BAN::ErrorOr Process::read_from_user(const void* user_addr, void* out, size_t size) - { - if (!is_valid_user_address(user_addr, size)) - return BAN::Error::from_errno(EFAULT); - if (!safe_user_memcpy(out, user_addr, size)) - return BAN::Error::from_errno(EFAULT); - return {}; - } - - BAN::ErrorOr Process::read_string_from_user(const char* user_addr, char* out, size_t max_size) - { - max_size = BAN::Math::min(max_size, USERSPACE_END - reinterpret_cast(user_addr)); - if (!is_valid_user_address(user_addr, max_size)) - return BAN::Error::from_errno(EFAULT); - if (!safe_user_strncpy(out, user_addr, max_size)) - return BAN::Error::from_errno(EFAULT); - return {}; - } - - BAN::ErrorOr Process::write_to_user(void* user_addr, const void* in, size_t size) - { - if (!is_valid_user_address(user_addr, size)) - return BAN::Error::from_errno(EFAULT); - if (!safe_user_memcpy(user_addr, in, size)) - return BAN::Error::from_errno(EFAULT); - return {}; - } - BAN::ErrorOr Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write) { // TODO: allow pinning multiple regions? diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 43b23849..b6d2ac5a 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace Kernel { @@ -727,7 +728,7 @@ namespace Kernel { static_assert(sizeof(T) >= sizeof(uintptr_t)); sp -= sizeof(T); - if (m_process->write_to_user(reinterpret_cast(sp), &value, sizeof(T)).is_error()) + if (write_to_user(reinterpret_cast(sp), &value, sizeof(T)).is_error()) m_process->exit(128 + SIGSEGV, SIGSEGV | 0x80); }; diff --git a/kernel/kernel/UserCopy.cpp b/kernel/kernel/UserCopy.cpp new file mode 100644 index 00000000..5d3a792a --- /dev/null +++ b/kernel/kernel/UserCopy.cpp @@ -0,0 +1,48 @@ +#include +#include + +extern "C" bool safe_user_memcpy(void*, const void*, size_t); +extern "C" bool safe_user_strncpy(void*, const void*, size_t); + +namespace Kernel +{ + +static inline bool is_valid_user_address(const void* user_addr, size_t size) +{ + const vaddr_t user_vaddr = reinterpret_cast(user_addr); + if (BAN::Math::will_addition_overflow(user_vaddr, size)) + return false; + if (user_vaddr + size > USERSPACE_END) + return false; + return true; +} + +BAN::ErrorOr read_from_user(const void* user_addr, void* out, size_t size) +{ + if (!is_valid_user_address(user_addr, size)) + return BAN::Error::from_errno(EFAULT); + if (!safe_user_memcpy(out, user_addr, size)) + return BAN::Error::from_errno(EFAULT); + return {}; +} + +BAN::ErrorOr read_string_from_user(const char* user_addr, char* out, size_t max_size) +{ + max_size = BAN::Math::min(max_size, USERSPACE_END - reinterpret_cast(user_addr)); + if (!is_valid_user_address(user_addr, max_size)) + return BAN::Error::from_errno(EFAULT); + if (!safe_user_strncpy(out, user_addr, max_size)) + return BAN::Error::from_errno(EFAULT); + return {}; +} + +BAN::ErrorOr write_to_user(void* user_addr, const void* in, size_t size) +{ + if (!is_valid_user_address(user_addr, size)) + return BAN::Error::from_errno(EFAULT); + if (!safe_user_memcpy(user_addr, in, size)) + return BAN::Error::from_errno(EFAULT); + return {}; +} + +}