Kernel/LibC: Implement mprotect

There may be some race conditions with this but i think this is good
enough to start with
This commit is contained in:
Bananymous 2025-08-05 02:39:19 +03:00
parent eb7922ab88
commit f1369c8fd6
18 changed files with 167 additions and 61 deletions

View File

@ -16,7 +16,11 @@ namespace Kernel
virtual bool is_partition() const { return false; } virtual bool is_partition() const { return false; }
virtual bool is_storage_device() const { return false; } virtual bool is_storage_device() const { return false; }
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t) { (void)offset; (void)len; return BAN::Error::from_errno(EINVAL); } virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t, int status_flags)
{
(void)offset; (void)len; (void)status_flags;
return BAN::Error::from_errno(ENOTSUP);
}
virtual dev_t rdev() const override = 0; virtual dev_t rdev() const override = 0;

View File

@ -27,7 +27,7 @@ namespace Kernel
void sync_pixels_linear(uint32_t first_pixel, uint32_t pixel_count); void sync_pixels_linear(uint32_t first_pixel, uint32_t pixel_count);
void sync_pixels_rectangle(uint32_t top_right_x, uint32_t top_right_y, uint32_t width, uint32_t height); void sync_pixels_rectangle(uint32_t top_right_x, uint32_t top_right_y, uint32_t width, uint32_t height);
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t) override; virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t, int status_flags) override;
virtual dev_t rdev() const override { return m_rdev; } virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::StringView name() const override { return m_name.sv(); } virtual BAN::StringView name() const override { return m_name.sv(); }

View File

@ -22,7 +22,7 @@ namespace Kernel
class FileBackedRegion; class FileBackedRegion;
class FileSystem; class FileSystem;
class SharedFileData; struct SharedFileData;
class Inode : public BAN::RefCounted<Inode> class Inode : public BAN::RefCounted<Inode>
{ {

View File

@ -27,18 +27,18 @@ namespace Kernel
BAN_NON_MOVABLE(FileBackedRegion); BAN_NON_MOVABLE(FileBackedRegion);
public: public:
static BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> create(BAN::RefPtr<Inode>, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t); static BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> create(BAN::RefPtr<Inode>, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t, int status_flags);
~FileBackedRegion(); ~FileBackedRegion();
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override; BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override;
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override; BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
protected: protected:
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
private: private:
FileBackedRegion(BAN::RefPtr<Inode>, PageTable&, off_t offset, ssize_t size, Type flags, PageTable::flags_t page_flags); FileBackedRegion(BAN::RefPtr<Inode>, PageTable&, off_t offset, ssize_t size, Type type, PageTable::flags_t flags, int status_flags);
private: private:
BAN::RefPtr<Inode> m_inode; BAN::RefPtr<Inode> m_inode;

View File

@ -11,22 +11,22 @@ namespace Kernel
BAN_NON_MOVABLE(MemoryBackedRegion); BAN_NON_MOVABLE(MemoryBackedRegion);
public: public:
static BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t); static BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t, int status_flags);
~MemoryBackedRegion(); ~MemoryBackedRegion();
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override; BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; } BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
// Copy data from buffer into this region // Copy data from buffer into this region
// This can fail if no memory is mapped and no free memory was available // This can fail if no memory is mapped and no free memory was available
BAN::ErrorOr<void> copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size); BAN::ErrorOr<void> copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size);
protected: protected:
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
private: private:
MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t); MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t, int status_flags);
}; };
} }

View File

@ -39,6 +39,10 @@ namespace Kernel
size_t size() const { return m_size; } size_t size() const { return m_size; }
vaddr_t vaddr() const { return m_vaddr; } vaddr_t vaddr() const { return m_vaddr; }
int status_flags() const { return m_status_flags; }
Type type() const { return m_type; }
PageTable::flags_t flags() const { return m_flags; }
size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); } size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); }
size_t physical_page_count() const { return m_physical_page_count; } size_t physical_page_count() const { return m_physical_page_count; }
@ -46,6 +50,7 @@ namespace Kernel
void unpin(); void unpin();
void wait_not_pinned(); void wait_not_pinned();
BAN::ErrorOr<void> mprotect(PageTable::flags_t);
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0; virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0;
// Returns error if no memory was available // Returns error if no memory was available
@ -56,7 +61,7 @@ namespace Kernel
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) = 0; virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) = 0;
protected: protected:
MemoryRegion(PageTable&, size_t size, Type type, PageTable::flags_t flags); MemoryRegion(PageTable&, size_t size, Type type, PageTable::flags_t flags, int status_flags);
BAN::ErrorOr<void> initialize(AddressRange); BAN::ErrorOr<void> initialize(AddressRange);
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t address, bool wants_write) = 0; virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t address, bool wants_write) = 0;
@ -65,7 +70,8 @@ namespace Kernel
PageTable& m_page_table; PageTable& m_page_table;
const size_t m_size; const size_t m_size;
const Type m_type; const Type m_type;
const PageTable::flags_t m_flags; PageTable::flags_t m_flags;
const int m_status_flags;
vaddr_t m_vaddr { 0 }; vaddr_t m_vaddr { 0 };
size_t m_physical_page_count { 0 }; size_t m_physical_page_count { 0 };

View File

@ -6,6 +6,8 @@
#include <kernel/Lock/SpinLock.h> #include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/MemoryRegion.h> #include <kernel/Memory/MemoryRegion.h>
#include <fcntl.h>
namespace Kernel namespace Kernel
{ {
@ -55,15 +57,16 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange); static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange);
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override; BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
protected: protected:
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
private: private:
SharedMemoryObject(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table) SharedMemoryObject(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table)
: MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags) : MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags, O_EXEC | O_RDWR)
, m_object(object) , m_object(object)
{ } { }

View File

@ -38,7 +38,7 @@ namespace Kernel
bool contains(vaddr_t address) const { return vaddr() <= address && address < vaddr() + size(); } bool contains(vaddr_t address) const { return vaddr() <= address && address < vaddr() + size(); }
BAN::ErrorOr<void> allocate_page_for_demand_paging(vaddr_t address); BAN::ErrorOr<bool> allocate_page_for_demand_paging(vaddr_t address);
private: private:
VirtualRange(PageTable&, bool preallocated, bool has_guard_pages, vaddr_t, size_t, PageTable::flags_t); VirtualRange(PageTable&, bool preallocated, bool has_guard_pages, vaddr_t, size_t, PageTable::flags_t);

View File

@ -170,6 +170,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*); BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len); BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
BAN::ErrorOr<long> sys_mprotect(void* addr, size_t len, int prot);
BAN::ErrorOr<long> sys_msync(void* addr, size_t len, int flags); BAN::ErrorOr<long> sys_msync(void* addr, size_t len, int flags);
BAN::ErrorOr<long> sys_smo_create(size_t len, int prot); BAN::ErrorOr<long> sys_smo_create(size_t len, int prot);

View File

@ -241,9 +241,9 @@ namespace Kernel
class FramebufferMemoryRegion : public MemoryRegion class FramebufferMemoryRegion : public MemoryRegion
{ {
public: public:
static BAN::ErrorOr<BAN::UniqPtr<FramebufferMemoryRegion>> create(PageTable& page_table, size_t size, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags, BAN::RefPtr<FramebufferDevice> framebuffer) static BAN::ErrorOr<BAN::UniqPtr<FramebufferMemoryRegion>> create(PageTable& page_table, size_t size, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags, int status_flags, BAN::RefPtr<FramebufferDevice> framebuffer)
{ {
auto* region_ptr = new FramebufferMemoryRegion(page_table, size, region_type, page_flags, framebuffer); auto* region_ptr = new FramebufferMemoryRegion(page_table, size, region_type, page_flags, status_flags, framebuffer);
if (region_ptr == nullptr) if (region_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<FramebufferMemoryRegion>::adopt(region_ptr); auto region = BAN::UniqPtr<FramebufferMemoryRegion>::adopt(region_ptr);
@ -258,7 +258,7 @@ namespace Kernel
m_framebuffer->sync_pixels_full(); m_framebuffer->sync_pixels_full();
} }
virtual BAN::ErrorOr<void> msync(vaddr_t vaddr, size_t size, int flags) override BAN::ErrorOr<void> msync(vaddr_t vaddr, size_t size, int flags) override
{ {
if (flags != MS_SYNC) if (flags != MS_SYNC)
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
@ -281,9 +281,9 @@ namespace Kernel
return {}; return {};
} }
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override
{ {
auto* region_ptr = new FramebufferMemoryRegion(new_page_table, m_size, m_type, m_flags, m_framebuffer); auto* region_ptr = new FramebufferMemoryRegion(new_page_table, m_size, m_type, m_flags, m_status_flags, m_framebuffer);
if (region_ptr == nullptr) if (region_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<FramebufferMemoryRegion>::adopt(region_ptr); auto region = BAN::UniqPtr<FramebufferMemoryRegion>::adopt(region_ptr);
@ -297,7 +297,7 @@ namespace Kernel
// Returns error if no memory was available // Returns error if no memory was available
// Returns true if page was succesfully allocated // Returns true if page was succesfully allocated
// Returns false if page was already allocated // Returns false if page was already allocated
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override
{ {
(void)wants_write; (void)wants_write;
@ -312,8 +312,8 @@ namespace Kernel
} }
private: private:
FramebufferMemoryRegion(PageTable& page_table, size_t size, MemoryRegion::Type region_type, PageTable::flags_t page_flags, BAN::RefPtr<FramebufferDevice> framebuffer) FramebufferMemoryRegion(PageTable& page_table, size_t size, MemoryRegion::Type region_type, PageTable::flags_t page_flags, int status_flags, BAN::RefPtr<FramebufferDevice> framebuffer)
: MemoryRegion(page_table, size, region_type, page_flags) : MemoryRegion(page_table, size, region_type, page_flags, status_flags)
, m_framebuffer(framebuffer) , m_framebuffer(framebuffer)
{ } { }
@ -370,7 +370,7 @@ namespace Kernel
BAN::RefPtr<FramebufferDevice> m_framebuffer; BAN::RefPtr<FramebufferDevice> m_framebuffer;
}; };
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FramebufferDevice::mmap_region(PageTable& page_table, off_t offset, size_t len, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags) BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FramebufferDevice::mmap_region(PageTable& page_table, off_t offset, size_t len, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags, int status_flags)
{ {
if (offset != 0) if (offset != 0)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
@ -379,7 +379,7 @@ namespace Kernel
if (region_type != MemoryRegion::Type::SHARED) if (region_type != MemoryRegion::Type::SHARED)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
auto region = TRY(FramebufferMemoryRegion::create(page_table, len, address_range, region_type, page_flags, this)); auto region = TRY(FramebufferMemoryRegion::create(page_table, len, address_range, region_type, page_flags, status_flags, this));
return BAN::UniqPtr<MemoryRegion>(BAN::move(region)); return BAN::UniqPtr<MemoryRegion>(BAN::move(region));
} }

View File

@ -212,7 +212,7 @@ namespace Kernel::ELF
file_backed_size, file_backed_size,
{ .start = pheader_base, .end = pheader_base + file_backed_size }, { .start = pheader_base, .end = pheader_base + file_backed_size },
MemoryRegion::Type::PRIVATE, MemoryRegion::Type::PRIVATE,
flags flags, O_EXEC | O_RDWR
)); ));
TRY(memory_regions.emplace_back(BAN::move(region))); TRY(memory_regions.emplace_back(BAN::move(region)));
} }
@ -226,7 +226,7 @@ namespace Kernel::ELF
(pheader_base + program_header.p_memsz) - (aligned_vaddr + file_backed_size), (pheader_base + program_header.p_memsz) - (aligned_vaddr + file_backed_size),
{ .start = aligned_vaddr + file_backed_size, .end = pheader_base + program_header.p_memsz }, { .start = aligned_vaddr + file_backed_size, .end = pheader_base + program_header.p_memsz },
MemoryRegion::Type::PRIVATE, MemoryRegion::Type::PRIVATE,
flags flags, O_EXEC | O_RDWR
)); ));
if (file_backed_size < program_header.p_filesz) if (file_backed_size < program_header.p_filesz)
@ -267,7 +267,8 @@ namespace Kernel::ELF
offset + region_size, offset + region_size,
{ .start = last_loaded_address, .end = USERSPACE_END }, { .start = last_loaded_address, .end = USERSPACE_END },
MemoryRegion::Type::PRIVATE, MemoryRegion::Type::PRIVATE,
PageTable::Flags::UserSupervisor | PageTable::Flags::Present PageTable::Flags::UserSupervisor | PageTable::Flags::Present,
O_EXEC | O_RDWR
)); ));
for (vaddr_t vaddr = region->vaddr(); vaddr < region->vaddr() + offset + region->size(); vaddr += PAGE_SIZE) for (vaddr_t vaddr = region->vaddr(); vaddr < region->vaddr() + offset + region->size(); vaddr += PAGE_SIZE)

View File

@ -7,7 +7,7 @@
namespace Kernel namespace Kernel
{ {
BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> FileBackedRegion::create(BAN::RefPtr<Inode> inode, PageTable& page_table, off_t offset, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags) BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> FileBackedRegion::create(BAN::RefPtr<Inode> inode, PageTable& page_table, off_t offset, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags, int status_flags)
{ {
ASSERT(inode->mode().ifreg()); ASSERT(inode->mode().ifreg());
@ -16,14 +16,14 @@ namespace Kernel
if ((size > (size_t)inode->size() || (size_t)offset > (size_t)inode->size() - size)) if ((size > (size_t)inode->size() || (size_t)offset > (size_t)inode->size() - size))
return BAN::Error::from_errno(EOVERFLOW); return BAN::Error::from_errno(EOVERFLOW);
auto* region_ptr = new FileBackedRegion(inode, page_table, offset, size, type, flags); auto* region_ptr = new FileBackedRegion(inode, page_table, offset, size, type, flags, status_flags);
if (region_ptr == nullptr) if (region_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<FileBackedRegion>::adopt(region_ptr); auto region = BAN::UniqPtr<FileBackedRegion>::adopt(region_ptr);
TRY(region->initialize(address_range)); TRY(region->initialize(address_range));
if (type == Type::PRIVATE && (flags & PageTable::Flags::ReadWrite)) if (type == Type::PRIVATE)
TRY(region->m_dirty_pages.resize(BAN::Math::div_round_up<size_t>(size, PAGE_SIZE))); TRY(region->m_dirty_pages.resize(BAN::Math::div_round_up<size_t>(size, PAGE_SIZE)));
LockGuard _(inode->m_mutex); LockGuard _(inode->m_mutex);
@ -39,8 +39,8 @@ namespace Kernel
return region; return region;
} }
FileBackedRegion::FileBackedRegion(BAN::RefPtr<Inode> inode, PageTable& page_table, off_t offset, ssize_t size, Type type, PageTable::flags_t flags) FileBackedRegion::FileBackedRegion(BAN::RefPtr<Inode> inode, PageTable& page_table, off_t offset, ssize_t size, Type type, PageTable::flags_t flags, int status_flags)
: MemoryRegion(page_table, size, type, flags) : MemoryRegion(page_table, size, type, flags, status_flags)
, m_inode(inode) , m_inode(inode)
, m_offset(offset) , m_offset(offset)
{ {
@ -200,7 +200,7 @@ namespace Kernel
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FileBackedRegion::clone(PageTable& page_table) BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FileBackedRegion::clone(PageTable& page_table)
{ {
const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK; const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
auto result = TRY(FileBackedRegion::create(m_inode, page_table, m_offset, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags)); auto result = TRY(FileBackedRegion::create(m_inode, page_table, m_offset, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags, m_status_flags));
// non-dirty pages can go through demand paging // non-dirty pages can go through demand paging

View File

@ -4,12 +4,12 @@
namespace Kernel namespace Kernel
{ {
BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> MemoryBackedRegion::create(PageTable& page_table, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags) BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> MemoryBackedRegion::create(PageTable& page_table, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags, int status_flags)
{ {
if (type != Type::PRIVATE) if (type != Type::PRIVATE)
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
auto* region_ptr = new MemoryBackedRegion(page_table, size, type, flags); auto* region_ptr = new MemoryBackedRegion(page_table, size, type, flags, status_flags);
if (region_ptr == nullptr) if (region_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr); auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr);
@ -19,8 +19,8 @@ namespace Kernel
return region; return region;
} }
MemoryBackedRegion::MemoryBackedRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags) MemoryBackedRegion::MemoryBackedRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags, int status_flags)
: MemoryRegion(page_table, size, type, flags) : MemoryRegion(page_table, size, type, flags, status_flags)
{ {
} }
@ -68,7 +68,7 @@ namespace Kernel
ASSERT(&PageTable::current() == &m_page_table); ASSERT(&PageTable::current() == &m_page_table);
const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK; const size_t aligned_size = (m_size + PAGE_SIZE - 1) & PAGE_ADDR_MASK;
auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags)); auto result = TRY(MemoryBackedRegion::create(new_page_table, m_size, { .start = m_vaddr, .end = m_vaddr + aligned_size }, m_type, m_flags, m_status_flags));
for (size_t offset = 0; offset < m_size; offset += PAGE_SIZE) for (size_t offset = 0; offset < m_size; offset += PAGE_SIZE)
{ {

View File

@ -4,11 +4,12 @@
namespace Kernel namespace Kernel
{ {
MemoryRegion::MemoryRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags) MemoryRegion::MemoryRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags, int status_flags)
: m_page_table(page_table) : m_page_table(page_table)
, m_size(size) , m_size(size)
, m_type(type) , m_type(type)
, m_flags(flags) , m_flags(flags)
, m_status_flags(status_flags)
{ {
} }
@ -49,6 +50,25 @@ namespace Kernel
return true; return true;
} }
BAN::ErrorOr<void> MemoryRegion::mprotect(PageTable::flags_t new_page_flags)
{
if (m_flags == new_page_flags)
return {};
const size_t page_count = BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE);
for (size_t i = 0; i < page_count; i++)
{
const vaddr_t vaddr = m_vaddr + i * PAGE_SIZE;
const paddr_t paddr = m_page_table.physical_address_of(vaddr);
if (paddr == 0)
continue;
m_page_table.map_page_at(paddr, vaddr, new_page_flags);
}
m_flags = new_page_flags;
return {};
}
BAN::ErrorOr<bool> MemoryRegion::allocate_page_containing(vaddr_t address, bool wants_write) BAN::ErrorOr<bool> MemoryRegion::allocate_page_containing(vaddr_t address, bool wants_write)
{ {
ASSERT(contains(address)); ASSERT(contains(address));

View File

@ -99,7 +99,7 @@ namespace Kernel
else else
{ {
const size_t page_count = size() / PAGE_SIZE; const size_t page_count = size() / PAGE_SIZE;
for (size_t i = m_has_guard_pages; i < page_count; i++) for (size_t i = 0; i < page_count; i++)
{ {
PageTable::with_fast_page(m_paddrs[i], [&] { PageTable::with_fast_page(m_paddrs[i], [&] {
memset(PageTable::fast_page_as_ptr(), 0, PAGE_SIZE); memset(PageTable::fast_page_as_ptr(), 0, PAGE_SIZE);
@ -120,7 +120,7 @@ namespace Kernel
auto result = TRY(create_to_vaddr(page_table, vaddr(), size(), m_flags, m_preallocated, m_has_guard_pages)); auto result = TRY(create_to_vaddr(page_table, vaddr(), size(), m_flags, m_preallocated, m_has_guard_pages));
const size_t page_count = size() / PAGE_SIZE; const size_t page_count = size() / PAGE_SIZE;
for (size_t i = m_has_guard_pages; i < page_count; i++) for (size_t i = 0; i < page_count; i++)
{ {
if (m_paddrs[i] == 0) if (m_paddrs[i] == 0)
continue; continue;
@ -140,15 +140,17 @@ namespace Kernel
return result; return result;
} }
BAN::ErrorOr<void> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr) BAN::ErrorOr<bool> VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr)
{ {
ASSERT(!m_preallocated);
ASSERT(vaddr % PAGE_SIZE == 0);
ASSERT(contains(vaddr)); ASSERT(contains(vaddr));
ASSERT(&PageTable::current() == &m_page_table); ASSERT(&PageTable::current() == &m_page_table);
if (m_preallocated)
return false;
const size_t index = (vaddr - this->vaddr()) / PAGE_SIZE; const size_t index = (vaddr - this->vaddr()) / PAGE_SIZE;
ASSERT(m_paddrs[index] == 0); if (m_paddrs[index])
return false;
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
@ -159,7 +161,7 @@ namespace Kernel
m_page_table.map_page_at(m_paddrs[index], vaddr, m_flags); m_page_table.map_page_at(m_paddrs[index], vaddr, m_flags);
memset(reinterpret_cast<void*>(vaddr), 0, PAGE_SIZE); memset(reinterpret_cast<void*>(vaddr), 0, PAGE_SIZE);
return {}; return true;
} }
} }

View File

@ -318,7 +318,8 @@ namespace Kernel
tls_size, tls_size,
{ .start = master_addr, .end = USERSPACE_END }, { .start = master_addr, .end = USERSPACE_END },
MemoryRegion::Type::PRIVATE, MemoryRegion::Type::PRIVATE,
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
O_EXEC | O_RDWR
)); ));
BAN::Vector<uint8_t> temp_buffer; BAN::Vector<uint8_t> temp_buffer;
@ -2146,7 +2147,8 @@ namespace Kernel
page_table(), page_table(),
args.len, args.len,
address_range, address_range,
region_type, page_flags region_type, page_flags,
O_EXEC | O_RDWR
)); ));
LockGuard _(m_process_lock); LockGuard _(m_process_lock);
@ -2173,7 +2175,8 @@ namespace Kernel
page_table(), page_table(),
args.off, args.len, args.off, args.len,
address_range, address_range,
region_type, page_flags region_type, page_flags,
status_flags
)); ));
} }
else if (inode->is_device()) else if (inode->is_device())
@ -2182,7 +2185,8 @@ namespace Kernel
page_table(), page_table(),
args.off, args.len, args.off, args.len,
address_range, address_range,
region_type, page_flags region_type, page_flags,
status_flags
)); ));
} }
@ -2228,6 +2232,70 @@ namespace Kernel
return 0; return 0;
} }
BAN::ErrorOr<long> Process::sys_mprotect(void* addr, size_t len, int prot)
{
if (len == 0)
return BAN::Error::from_errno(EINVAL);
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(addr);
if (vaddr % PAGE_SIZE != 0)
return BAN::Error::from_errno(EINVAL);
if (auto rem = len % PAGE_SIZE)
len += PAGE_SIZE - rem;
PageTable::flags_t flags = 0;
if (prot & PROT_READ)
flags |= PageTable::Flags::Present;
if (prot & PROT_WRITE)
flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
if (prot & PROT_EXEC)
flags |= PageTable::Flags::Execute | PageTable::Flags::Execute;
if (flags == 0)
flags = PageTable::Flags::Reserved;
else
flags |= PageTable::Flags::UserSupervisor;
LockGuard _(m_process_lock);
// FIXME: We should protect partial regions.
// This is a hack to only protect if the whole mmap region
// is contained within [addr, addr + len]
for (size_t i = 0; i < m_mapped_regions.size(); i++)
{
auto& region = m_mapped_regions[i];
const vaddr_t region_s = region->vaddr();
const vaddr_t region_e = region->vaddr() + region->size();
if (vaddr <= region_s && region_e <= vaddr + len)
{
const bool is_shared = (region->type() == MemoryRegion::Type::SHARED);
const bool is_writable = (region->status_flags() & O_WRONLY);
const bool want_write = (prot & PROT_WRITE);
if (is_shared && want_write && !is_writable)
return BAN::Error::from_errno(EACCES);
// FIXME: if the region is pinned writable, this may
// cause some problems :D
TRY(region->mprotect(flags));
}
else if (region->overlaps(vaddr, len))
{
const bool is_shared = (region->type() == MemoryRegion::Type::SHARED);
const bool is_writable = (region->status_flags() & O_WRONLY);
const bool want_write = (prot & PROT_WRITE);
if (is_shared && want_write && !is_writable)
return BAN::Error::from_errno(EACCES);
dwarnln("TODO: partial region mprotect");
TRY(region->mprotect(flags | region->flags()));
}
}
return 0;
}
BAN::ErrorOr<long> Process::sys_msync(void* addr, size_t len, int flags) BAN::ErrorOr<long> Process::sys_msync(void* addr, size_t len, int flags)
{ {
if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE) if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE)

View File

@ -52,6 +52,7 @@ __BEGIN_DECLS
O(SYS_SYNC, sync) \ O(SYS_SYNC, sync) \
O(SYS_MMAP, mmap) \ O(SYS_MMAP, mmap) \
O(SYS_MUNMAP, munmap) \ O(SYS_MUNMAP, munmap) \
O(SYS_MPROTECT, mprotect) \
O(SYS_TTY_CTRL, tty_ctrl) \ O(SYS_TTY_CTRL, tty_ctrl) \
O(SYS_POWEROFF, poweroff) \ O(SYS_POWEROFF, poweroff) \
O(SYS_FCHMODAT, fchmodat) \ O(SYS_FCHMODAT, fchmodat) \

View File

@ -24,6 +24,11 @@ int munmap(void* addr, size_t len)
return syscall(SYS_MUNMAP, addr, len); return syscall(SYS_MUNMAP, addr, len);
} }
int mprotect(void* addr, size_t len, int prot)
{
return syscall(SYS_MPROTECT, addr, len, prot);
}
int msync(void* addr, size_t len, int flags) int msync(void* addr, size_t len, int flags)
{ {
pthread_testcancel(); pthread_testcancel();
@ -45,8 +50,3 @@ int mlock(const void*, size_t)
{ {
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
int mprotect(void*, size_t, int)
{
ASSERT_NOT_REACHED();
}