diff options
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Process.cpp | 18 | ||||
-rw-r--r-- | Kernel/VM/MemoryManager.cpp | 44 | ||||
-rw-r--r-- | Kernel/VM/MemoryManager.h | 11 |
3 files changed, 50 insertions, 23 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 7c5a834fc9..f5532c696a 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1958,7 +1958,7 @@ bool Process::validate_read_from_kernel(VirtualAddress vaddr, ssize_t size) cons return false; if (is_kmalloc_address(vaddr.as_ptr())) return true; - return validate_read(vaddr.as_ptr(), size); + return MM.validate_kernel_read(*this, vaddr, size); } bool Process::validate_read_str(const char* str) @@ -1984,23 +1984,15 @@ bool Process::validate_read(const void* address, ssize_t size) const if (is_kmalloc_address(address)) return true; } - ASSERT(size); if (!size) return false; - if (first_address.page_base() != last_address.page_base()) { - if (!MM.validate_user_read(*this, last_address)) - return false; - } - return MM.validate_user_read(*this, first_address); + return MM.validate_user_read(*this, first_address, size); } bool Process::validate_write(void* address, ssize_t size) const { ASSERT(size >= 0); VirtualAddress first_address((u32)address); - VirtualAddress last_address = first_address.offset(size - 1); - if (last_address < first_address) - return false; if (is_ring0()) { if (is_kmalloc_address(address)) return true; @@ -2012,11 +2004,7 @@ bool Process::validate_write(void* address, ssize_t size) const } if (!size) return false; - if (first_address.page_base() != last_address.page_base()) { - if (!MM.validate_user_write(*this, last_address)) - return false; - } - return MM.validate_user_write(*this, first_address); + return MM.validate_user_write(*this, first_address, size); } pid_t Process::sys$getsid(pid_t pid) diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index 0b67633d52..e3728b4ae9 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -606,6 +606,35 @@ static inline bool is_user_address(VirtualAddress vaddr) return vaddr.get() >= (8 * MB) && vaddr.get() < 0xc0000000; } +template<MemoryManager::AccessSpace space, MemoryManager::AccessType access_type> +bool MemoryManager::validate_range(const Process& process, VirtualAddress base_vaddr, size_t size) const +{ + ASSERT(size); + VirtualAddress vaddr = base_vaddr.page_base(); + VirtualAddress end_vaddr = base_vaddr.offset(size - 1).page_base(); + if (end_vaddr < vaddr) { + dbg() << *current << " Shenanigans! Asked to validate " << base_vaddr << " size=" << size; + return false; + } + const Region* region = nullptr; + while (vaddr <= end_vaddr) { + if (!region || !region->contains(vaddr)) { + if (space == AccessSpace::Kernel) + region = kernel_region_from_vaddr(vaddr); + if (!region || !region->contains(vaddr)) + region = user_region_from_vaddr(const_cast<Process&>(process), vaddr); + if (!region + || (space == AccessSpace::User && !region->is_user_accessible()) + || (access_type == AccessType::Read && !region->is_readable()) + || (access_type == AccessType::Write && !region->is_writable())) { + return false; + } + } + vaddr = vaddr.offset(PAGE_SIZE); + } + return true; +} + bool MemoryManager::validate_user_stack(const Process& process, VirtualAddress vaddr) const { if (!is_user_address(vaddr)) @@ -614,20 +643,23 @@ bool MemoryManager::validate_user_stack(const Process& process, VirtualAddress v return region && region->is_user_accessible() && region->is_stack(); } -bool MemoryManager::validate_user_read(const Process& process, VirtualAddress vaddr) const +bool MemoryManager::validate_kernel_read(const Process& process, VirtualAddress vaddr, size_t size) const +{ + return validate_range<AccessSpace::Kernel, AccessType::Read>(process, vaddr, size); +} + +bool MemoryManager::validate_user_read(const Process& process, VirtualAddress vaddr, size_t size) const { if (!is_user_address(vaddr)) return false; - auto* region = user_region_from_vaddr(const_cast<Process&>(process), vaddr); - return region && region->is_user_accessible() && region->is_readable(); + return validate_range<AccessSpace::User, AccessType::Read>(process, vaddr, size); } -bool MemoryManager::validate_user_write(const Process& process, VirtualAddress vaddr) const +bool MemoryManager::validate_user_write(const Process& process, VirtualAddress vaddr, size_t size) const { if (!is_user_address(vaddr)) return false; - auto* region = user_region_from_vaddr(const_cast<Process&>(process), vaddr); - return region && region->is_user_accessible() && region->is_writable(); + return validate_range<AccessSpace::User, AccessType::Write>(process, vaddr, size); } void MemoryManager::register_vmobject(VMObject& vmobject) diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h index 967e681a2c..517106cad9 100644 --- a/Kernel/VM/MemoryManager.h +++ b/Kernel/VM/MemoryManager.h @@ -45,8 +45,10 @@ public: void enter_process_paging_scope(Process&); bool validate_user_stack(const Process&, VirtualAddress) const; - bool validate_user_read(const Process&, VirtualAddress) const; - bool validate_user_write(const Process&, VirtualAddress) const; + bool validate_user_read(const Process&, VirtualAddress, size_t) const; + bool validate_user_write(const Process&, VirtualAddress, size_t) const; + + bool validate_kernel_read(const Process&, VirtualAddress, size_t) const; enum class ShouldZeroFill { No, @@ -85,6 +87,11 @@ private: MemoryManager(u32 physical_address_for_kernel_page_tables); ~MemoryManager(); + enum class AccessSpace { Kernel, User }; + enum class AccessType { Read, Write }; + template<AccessSpace, AccessType> + bool validate_range(const Process&, VirtualAddress, size_t) const; + void register_vmobject(VMObject&); void unregister_vmobject(VMObject&); void register_region(Region&); |