diff options
author | Andreas Kling <kling@serenityos.org> | 2021-01-26 16:56:34 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-01-26 18:35:04 +0100 |
commit | a131927c753e2b7b9b3e1d7e67fb19774a28f3d4 (patch) | |
tree | 198134ee78099d6dcad39f8b96904a007c0d060b | |
parent | e7183cc762f634c73be4b4b018b96de8dc5b3031 (diff) | |
download | serenity-a131927c753e2b7b9b3e1d7e67fb19774a28f3d4.zip |
Kernel: sys$munmap() region splitting did not preserve "shared" flag
This was exploitable since the shared flag determines whether inode
permission checks are applied in sys$mprotect().
The bug was pretty hard to spot due to default arguments being used
instead. This patch removes the default arguments to make explicit
at each call site what's being done.
-rw-r--r-- | Kernel/Process.cpp | 5 | ||||
-rw-r--r-- | Kernel/VM/MemoryManager.cpp | 2 | ||||
-rw-r--r-- | Kernel/VM/Region.cpp | 6 | ||||
-rw-r--r-- | Kernel/VM/Region.h | 2 |
4 files changed, 9 insertions, 6 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 17ce03bba2..7636f7d35e 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -127,7 +127,8 @@ Range Process::allocate_range(VirtualAddress vaddr, size_t size, size_t alignmen Region& Process::allocate_split_region(const Region& source_region, const Range& range, size_t offset_in_vmobject) { - auto& region = add_region(Region::create_user_accessible(this, range, source_region.vmobject(), offset_in_vmobject, source_region.name(), source_region.access())); + auto& region = add_region( + Region::create_user_accessible(this, range, source_region.vmobject(), offset_in_vmobject, source_region.name(), source_region.access(), source_region.is_cacheable(), source_region.is_shared())); region.set_mmap(source_region.is_mmap()); region.set_stack(source_region.is_stack()); size_t page_offset_in_source_region = (offset_in_vmobject - source_region.offset_in_vmobject()) / PAGE_SIZE; @@ -144,7 +145,7 @@ KResultOr<Region*> Process::allocate_region(const Range& range, const String& na auto vmobject = AnonymousVMObject::create_with_size(range.size(), strategy); if (!vmobject) return ENOMEM; - auto region = Region::create_user_accessible(this, range, vmobject.release_nonnull(), 0, name, prot_to_region_access_flags(prot)); + auto region = Region::create_user_accessible(this, range, vmobject.release_nonnull(), 0, name, prot_to_region_access_flags(prot), true, false); if (!region->map(page_directory())) return ENOMEM; return &add_region(move(region)); diff --git a/Kernel/VM/MemoryManager.cpp b/Kernel/VM/MemoryManager.cpp index d06bc2623a..c1710ff2f4 100644 --- a/Kernel/VM/MemoryManager.cpp +++ b/Kernel/VM/MemoryManager.cpp @@ -454,7 +454,7 @@ OwnPtr<Region> MemoryManager::allocate_kernel_region_with_vmobject(const Range& ScopedSpinLock lock(s_mm_lock); OwnPtr<Region> region; if (user_accessible) - region = Region::create_user_accessible(nullptr, range, vmobject, 0, name, access, cacheable); + region = Region::create_user_accessible(nullptr, range, vmobject, 0, name, access, cacheable, false); else region = Region::create_kernel_only(range, vmobject, 0, name, access, cacheable); if (region) diff --git a/Kernel/VM/Region.cpp b/Kernel/VM/Region.cpp index e600440b01..3c8dadb4f4 100644 --- a/Kernel/VM/Region.cpp +++ b/Kernel/VM/Region.cpp @@ -99,7 +99,8 @@ OwnPtr<Region> Region::clone(Process& new_owner) ASSERT(vmobject().is_shared_inode()); // Create a new region backed by the same VMObject. - auto region = Region::create_user_accessible(&new_owner, m_range, m_vmobject, m_offset_in_vmobject, m_name, m_access); + auto region = Region::create_user_accessible( + &new_owner, m_range, m_vmobject, m_offset_in_vmobject, m_name, m_access, m_cacheable, m_shared); if (m_vmobject->is_anonymous()) region->copy_purgeable_page_ranges(*this); region->set_mmap(m_mmap); @@ -116,7 +117,8 @@ OwnPtr<Region> Region::clone(Process& new_owner) // Set up a COW region. The parent (this) region becomes COW as well! remap(); - auto clone_region = Region::create_user_accessible(&new_owner, m_range, vmobject_clone.release_nonnull(), m_offset_in_vmobject, m_name, m_access); + auto clone_region = Region::create_user_accessible( + &new_owner, m_range, vmobject_clone.release_nonnull(), m_offset_in_vmobject, m_name, m_access, m_cacheable, m_shared); if (m_vmobject->is_anonymous()) clone_region->copy_purgeable_page_ranges(*this); if (m_stack) { diff --git a/Kernel/VM/Region.h b/Kernel/VM/Region.h index fef5e6ecff..bee8c32e33 100644 --- a/Kernel/VM/Region.h +++ b/Kernel/VM/Region.h @@ -56,7 +56,7 @@ public: Execute = 4, }; - static NonnullOwnPtr<Region> create_user_accessible(Process*, const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, const StringView& name, u8 access, bool cacheable = true, bool shared = false); + static NonnullOwnPtr<Region> create_user_accessible(Process*, const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, const StringView& name, u8 access, bool cacheable, bool shared); static NonnullOwnPtr<Region> create_kernel_only(const Range&, NonnullRefPtr<VMObject>, size_t offset_in_vmobject, const StringView& name, u8 access, bool cacheable = true); ~Region(); |