1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 01:37:36 +00:00

Kernel: Enforce W^X more strictly (like PaX MPROTECT)

This patch adds enforcement of two new rules:

- Memory that was previously writable cannot become executable
- Memory that was previously executable cannot become writable

Unfortunately we have to make an exception for text relocations in the
dynamic loader. Since those necessitate writing into a private copy
of library code, we allow programs to transition from RW to RX under
very specific conditions. See the implementation of sys$mprotect()'s
should_make_executable_exception_for_dynamic_loader() for details.
This commit is contained in:
Andreas Kling 2021-01-29 14:38:49 +01:00
parent d988bd86e4
commit af3d3c5c4a
3 changed files with 106 additions and 13 deletions

View file

@ -50,10 +50,16 @@ class Region final
MAKE_SLAB_ALLOCATED(Region)
public:
enum Access {
// 76543210
// eXWR xwr
enum Access : u8 {
Read = 1,
Write = 2,
Execute = 4,
HasBeenReadable = 16,
HasBeenWritable = 32,
HasBeenExecutable = 64,
HasMadeExecutableExceptionForDynamicLoader = 128,
};
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);
@ -67,6 +73,18 @@ public:
bool is_readable() const { return m_access & Access::Read; }
bool is_writable() const { return m_access & Access::Write; }
bool is_executable() const { return m_access & Access::Execute; }
bool has_been_readable() const { return m_access & Access::HasBeenReadable; }
bool has_been_writable() const { return m_access & Access::HasBeenWritable; }
bool has_been_executable() const { return m_access & Access::HasBeenExecutable; }
bool has_made_executable_exception_for_dynamic_loader() const { return m_access & Access::HasMadeExecutableExceptionForDynamicLoader; }
void set_has_made_executable_exception_for_dynamic_loader()
{
ASSERT(!has_made_executable_exception_for_dynamic_loader());
m_access |= Access::HasMadeExecutableExceptionForDynamicLoader;
}
bool is_cacheable() const { return m_cacheable; }
const String& name() const { return m_name; }
unsigned access() const { return m_access; }
@ -245,7 +263,7 @@ private:
void set_access_bit(Access access, bool b)
{
if (b)
m_access |= access;
m_access |= access | (access << 4);
else
m_access &= ~access;
}