summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-01-26 16:56:34 +0100
committerAndreas Kling <kling@serenityos.org>2021-01-26 18:35:04 +0100
commita131927c753e2b7b9b3e1d7e67fb19774a28f3d4 (patch)
tree198134ee78099d6dcad39f8b96904a007c0d060b
parente7183cc762f634c73be4b4b018b96de8dc5b3031 (diff)
downloadserenity-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.cpp5
-rw-r--r--Kernel/VM/MemoryManager.cpp2
-rw-r--r--Kernel/VM/Region.cpp6
-rw-r--r--Kernel/VM/Region.h2
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();