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_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;

View File

@ -27,7 +27,7 @@ namespace Kernel
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);
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 BAN::StringView name() const override { return m_name.sv(); }

View File

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

View File

@ -27,18 +27,18 @@ namespace Kernel
BAN_NON_MOVABLE(FileBackedRegion);
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();
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:
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:
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:
BAN::RefPtr<Inode> m_inode;

View File

@ -11,22 +11,22 @@ namespace Kernel
BAN_NON_MOVABLE(MemoryBackedRegion);
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();
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
// 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);
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:
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; }
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 physical_page_count() const { return m_physical_page_count; }
@ -46,6 +50,7 @@ namespace Kernel
void unpin();
void wait_not_pinned();
BAN::ErrorOr<void> mprotect(PageTable::flags_t);
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0;
// 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;
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);
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;
const size_t m_size;
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 };
size_t m_physical_page_count { 0 };

View File

@ -6,6 +6,8 @@
#include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/MemoryRegion.h>
#include <fcntl.h>
namespace Kernel
{
@ -55,15 +57,16 @@ namespace Kernel
public:
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;
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
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:
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)
{ }

View File

@ -38,7 +38,7 @@ namespace Kernel
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:
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_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_smo_create(size_t len, int prot);

View File

@ -241,9 +241,9 @@ namespace Kernel
class FramebufferMemoryRegion : public MemoryRegion
{
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)
return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<FramebufferMemoryRegion>::adopt(region_ptr);
@ -258,7 +258,7 @@ namespace Kernel
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)
return BAN::Error::from_errno(ENOTSUP);
@ -281,9 +281,9 @@ namespace Kernel
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)
return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<FramebufferMemoryRegion>::adopt(region_ptr);
@ -297,7 +297,7 @@ namespace Kernel
// Returns error if no memory was available
// Returns true if page was succesfully 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;
@ -312,8 +312,8 @@ namespace Kernel
}
private:
FramebufferMemoryRegion(PageTable& page_table, size_t size, MemoryRegion::Type region_type, PageTable::flags_t page_flags, BAN::RefPtr<FramebufferDevice> framebuffer)
: MemoryRegion(page_table, size, region_type, page_flags)
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, status_flags)
, m_framebuffer(framebuffer)
{ }
@ -370,7 +370,7 @@ namespace Kernel
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)
return BAN::Error::from_errno(EINVAL);
@ -379,7 +379,7 @@ namespace Kernel
if (region_type != MemoryRegion::Type::SHARED)
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));
}

View File

@ -212,7 +212,7 @@ namespace Kernel::ELF
file_backed_size,
{ .start = pheader_base, .end = pheader_base + file_backed_size },
MemoryRegion::Type::PRIVATE,
flags
flags, O_EXEC | O_RDWR
));
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),
{ .start = aligned_vaddr + file_backed_size, .end = pheader_base + program_header.p_memsz },
MemoryRegion::Type::PRIVATE,
flags
flags, O_EXEC | O_RDWR
));
if (file_backed_size < program_header.p_filesz)
@ -267,7 +267,8 @@ namespace Kernel::ELF
offset + region_size,
{ .start = last_loaded_address, .end = USERSPACE_END },
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)

View File

@ -7,7 +7,7 @@
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());
@ -16,14 +16,14 @@ namespace Kernel
if ((size > (size_t)inode->size() || (size_t)offset > (size_t)inode->size() - size))
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)
return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<FileBackedRegion>::adopt(region_ptr);
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)));
LockGuard _(inode->m_mutex);
@ -39,8 +39,8 @@ namespace Kernel
return region;
}
FileBackedRegion::FileBackedRegion(BAN::RefPtr<Inode> inode, PageTable& page_table, off_t offset, ssize_t size, Type type, PageTable::flags_t flags)
: MemoryRegion(page_table, size, type, 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, status_flags)
, m_inode(inode)
, m_offset(offset)
{
@ -200,7 +200,7 @@ namespace Kernel
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> FileBackedRegion::clone(PageTable& page_table)
{
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

View File

@ -4,12 +4,12 @@
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)
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)
return BAN::Error::from_errno(ENOMEM);
auto region = BAN::UniqPtr<MemoryBackedRegion>::adopt(region_ptr);
@ -19,8 +19,8 @@ namespace Kernel
return region;
}
MemoryBackedRegion::MemoryBackedRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags)
: MemoryRegion(page_table, size, type, flags)
MemoryBackedRegion::MemoryBackedRegion(PageTable& page_table, size_t size, Type type, PageTable::flags_t flags, int status_flags)
: MemoryRegion(page_table, size, type, flags, status_flags)
{
}
@ -68,7 +68,7 @@ namespace Kernel
ASSERT(&PageTable::current() == &m_page_table);
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)
{

View File

@ -4,11 +4,12 @@
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_size(size)
, m_type(type)
, m_flags(flags)
, m_status_flags(status_flags)
{
}
@ -49,6 +50,25 @@ namespace Kernel
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)
{
ASSERT(contains(address));

View File

@ -99,7 +99,7 @@ namespace Kernel
else
{
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], [&] {
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));
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)
continue;
@ -140,15 +140,17 @@ namespace Kernel
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(&PageTable::current() == &m_page_table);
if (m_preallocated)
return false;
const size_t index = (vaddr - this->vaddr()) / PAGE_SIZE;
ASSERT(m_paddrs[index] == 0);
if (m_paddrs[index])
return false;
SpinLockGuard _(m_lock);
@ -159,7 +161,7 @@ namespace Kernel
m_page_table.map_page_at(m_paddrs[index], vaddr, m_flags);
memset(reinterpret_cast<void*>(vaddr), 0, PAGE_SIZE);
return {};
return true;
}
}

View File

@ -318,7 +318,8 @@ namespace Kernel
tls_size,
{ .start = master_addr, .end = USERSPACE_END },
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;
@ -2146,7 +2147,8 @@ namespace Kernel
page_table(),
args.len,
address_range,
region_type, page_flags
region_type, page_flags,
O_EXEC | O_RDWR
));
LockGuard _(m_process_lock);
@ -2173,7 +2175,8 @@ namespace Kernel
page_table(),
args.off, args.len,
address_range,
region_type, page_flags
region_type, page_flags,
status_flags
));
}
else if (inode->is_device())
@ -2182,7 +2185,8 @@ namespace Kernel
page_table(),
args.off, args.len,
address_range,
region_type, page_flags
region_type, page_flags,
status_flags
));
}
@ -2228,6 +2232,70 @@ namespace Kernel
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)
{
if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE)

View File

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

View File

@ -24,6 +24,11 @@ int munmap(void* addr, size_t 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)
{
pthread_testcancel();
@ -45,8 +50,3 @@ int mlock(const void*, size_t)
{
ASSERT_NOT_REACHED();
}
int mprotect(void*, size_t, int)
{
ASSERT_NOT_REACHED();
}