diff --git a/kernel/src/memory/MemoryManager.cpp b/kernel/src/memory/MemoryManager.cpp index 5c73c96a..61eb24e4 100644 --- a/kernel/src/memory/MemoryManager.cpp +++ b/kernel/src/memory/MemoryManager.cpp @@ -347,23 +347,74 @@ namespace MemoryManager return false; } - // FIXME: Replace this with some kind of strdup_from_user() function. + bool validate_user_readable_page(u64 address) + { + auto rc = MMU::get_flags(address); + if (rc.has_error()) return false; + if (rc.value() & MMU::User) return true; + return false; + } + + bool validate_user_writable_page(u64 address) + { + auto rc = MMU::get_flags(address); + if (rc.has_error()) return false; + if ((rc.value() & MMU::User) && (rc.value() && MMU::ReadWrite)) return true; + return false; + } + bool validate_userspace_string(u64 address) { - if (!validate_readable_page(address)) return false; + if (!validate_user_readable_page(address)) return false; while (*(char*)address != 0) { address++; if (address % ARCH_PAGE_SIZE) { - if (!validate_readable_page(address)) return false; + if (!validate_user_readable_page(address)) return false; } } return true; } + bool validate_user_write(void* user, usize size) + { + uintptr_t user_ptr = (uintptr_t)user; + uintptr_t user_page = align_down(user_ptr); + + uintptr_t diff = user_ptr - user_page; + + usize pages = get_blocks_from_size(size + diff, ARCH_PAGE_SIZE); + + while (pages--) + { + if (!validate_user_writable_page(user_page)) return false; + user_page += ARCH_PAGE_SIZE; + } + + return true; + } + + bool validate_user_read(const void* user, usize size) + { + uintptr_t user_ptr = (uintptr_t)user; + uintptr_t user_page = align_down(user_ptr); + + uintptr_t diff = user_ptr - user_page; + + usize pages = get_blocks_from_size(size + diff, ARCH_PAGE_SIZE); + + while (pages--) + { + if (!validate_user_readable_page(user_page)) return false; + user_page += ARCH_PAGE_SIZE; + } + + return true; + } + bool copy_to_user(void* user, const void* kernel, usize size) { uintptr_t user_ptr = (uintptr_t)user; @@ -375,7 +426,7 @@ namespace MemoryManager if (user_ptr != user_page) { // FIXME: Validate that this page is writable by the user, not just the kernel. - if (!validate_writable_page(user_page)) return false; + if (!validate_user_writable_page(user_page)) return false; } while (size--) @@ -383,7 +434,7 @@ namespace MemoryManager // Crossed a page boundary, gotta check the page tables again before touching any memory!! if (user_ptr % ARCH_PAGE_SIZE) { - if (!validate_writable_page(user_ptr)) return false; + if (!validate_user_writable_page(user_ptr)) return false; } *(char*)user_ptr = *kernel_ptr++; diff --git a/kernel/src/memory/MemoryManager.h b/kernel/src/memory/MemoryManager.h index 6ce8d001..76bcf9e4 100644 --- a/kernel/src/memory/MemoryManager.h +++ b/kernel/src/memory/MemoryManager.h @@ -20,8 +20,24 @@ namespace MemoryManager bool validate_readable_page(u64 address); bool validate_writable_page(u64 address); + bool validate_user_readable_page(u64 address); + bool validate_user_writable_page(u64 address); + bool validate_userspace_string(u64 address); + bool validate_user_write(void* user, usize size); + bool validate_user_read(const void* user, usize size); + + template bool validate_user_write_typed(T* user) + { + return validate_user_write(user, sizeof(T)); + } + + template bool validate_user_read_typed(const T* user) + { + return validate_user_read(user, sizeof(T)); + } + bool copy_to_user(void* user, const void* kernel, usize size); template bool copy_to_user_typed(T* user, const T* kernel)