diff --git a/kernel/include/kernel/Device/Device.h b/kernel/include/kernel/Device/Device.h index 86e2064d..617a107b 100644 --- a/kernel/include/kernel/Device/Device.h +++ b/kernel/include/kernel/Device/Device.h @@ -16,7 +16,11 @@ namespace Kernel virtual bool is_partition() const { return false; } virtual bool is_storage_device() const { return false; } - virtual BAN::ErrorOr> 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> 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; diff --git a/kernel/include/kernel/Device/FramebufferDevice.h b/kernel/include/kernel/Device/FramebufferDevice.h index d98b406e..bce2b3ca 100644 --- a/kernel/include/kernel/Device/FramebufferDevice.h +++ b/kernel/include/kernel/Device/FramebufferDevice.h @@ -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> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t) override; + virtual BAN::ErrorOr> 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(); } diff --git a/kernel/include/kernel/FS/Inode.h b/kernel/include/kernel/FS/Inode.h index 64d135fa..c5cb7728 100644 --- a/kernel/include/kernel/FS/Inode.h +++ b/kernel/include/kernel/FS/Inode.h @@ -22,7 +22,7 @@ namespace Kernel class FileBackedRegion; class FileSystem; - class SharedFileData; + struct SharedFileData; class Inode : public BAN::RefCounted { diff --git a/kernel/include/kernel/Memory/FileBackedRegion.h b/kernel/include/kernel/Memory/FileBackedRegion.h index 3ab47c45..a96cad22 100644 --- a/kernel/include/kernel/Memory/FileBackedRegion.h +++ b/kernel/include/kernel/Memory/FileBackedRegion.h @@ -27,18 +27,18 @@ namespace Kernel BAN_NON_MOVABLE(FileBackedRegion); public: - static BAN::ErrorOr> create(BAN::RefPtr, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t); + static BAN::ErrorOr> create(BAN::RefPtr, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t, int status_flags); ~FileBackedRegion(); - virtual BAN::ErrorOr msync(vaddr_t, size_t, int) override; + BAN::ErrorOr msync(vaddr_t, size_t, int) override; - virtual BAN::ErrorOr> clone(PageTable& new_page_table) override; + BAN::ErrorOr> clone(PageTable& new_page_table) override; protected: - virtual BAN::ErrorOr allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; + BAN::ErrorOr allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; private: - FileBackedRegion(BAN::RefPtr, PageTable&, off_t offset, ssize_t size, Type flags, PageTable::flags_t page_flags); + FileBackedRegion(BAN::RefPtr, PageTable&, off_t offset, ssize_t size, Type type, PageTable::flags_t flags, int status_flags); private: BAN::RefPtr m_inode; diff --git a/kernel/include/kernel/Memory/MemoryBackedRegion.h b/kernel/include/kernel/Memory/MemoryBackedRegion.h index a030dd06..47c60e31 100644 --- a/kernel/include/kernel/Memory/MemoryBackedRegion.h +++ b/kernel/include/kernel/Memory/MemoryBackedRegion.h @@ -11,22 +11,22 @@ namespace Kernel BAN_NON_MOVABLE(MemoryBackedRegion); public: - static BAN::ErrorOr> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t); + static BAN::ErrorOr> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t, int status_flags); ~MemoryBackedRegion(); - virtual BAN::ErrorOr> clone(PageTable& new_page_table) override; + BAN::ErrorOr> clone(PageTable& new_page_table) override; - virtual BAN::ErrorOr msync(vaddr_t, size_t, int) override { return {}; } + BAN::ErrorOr 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 copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size); protected: - virtual BAN::ErrorOr allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; + BAN::ErrorOr 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); }; } diff --git a/kernel/include/kernel/Memory/MemoryRegion.h b/kernel/include/kernel/Memory/MemoryRegion.h index bddf04eb..59a9782e 100644 --- a/kernel/include/kernel/Memory/MemoryRegion.h +++ b/kernel/include/kernel/Memory/MemoryRegion.h @@ -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(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 mprotect(PageTable::flags_t); virtual BAN::ErrorOr msync(vaddr_t, size_t, int) = 0; // Returns error if no memory was available @@ -56,7 +61,7 @@ namespace Kernel virtual BAN::ErrorOr> 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 initialize(AddressRange); virtual BAN::ErrorOr 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 }; diff --git a/kernel/include/kernel/Memory/SharedMemoryObject.h b/kernel/include/kernel/Memory/SharedMemoryObject.h index b30e5f4a..7ad614c9 100644 --- a/kernel/include/kernel/Memory/SharedMemoryObject.h +++ b/kernel/include/kernel/Memory/SharedMemoryObject.h @@ -6,6 +6,8 @@ #include #include +#include + namespace Kernel { @@ -55,15 +57,16 @@ namespace Kernel public: static BAN::ErrorOr> create(BAN::RefPtr, PageTable&, AddressRange); - virtual BAN::ErrorOr> clone(PageTable& new_page_table) override; - virtual BAN::ErrorOr msync(vaddr_t, size_t, int) override { return {}; } + BAN::ErrorOr> clone(PageTable& new_page_table) override; + + BAN::ErrorOr msync(vaddr_t, size_t, int) override { return {}; } protected: - virtual BAN::ErrorOr allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; + BAN::ErrorOr allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; private: SharedMemoryObject(BAN::RefPtr 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) { } diff --git a/kernel/include/kernel/Memory/VirtualRange.h b/kernel/include/kernel/Memory/VirtualRange.h index 5a1c7013..c096ba8d 100644 --- a/kernel/include/kernel/Memory/VirtualRange.h +++ b/kernel/include/kernel/Memory/VirtualRange.h @@ -38,7 +38,7 @@ namespace Kernel bool contains(vaddr_t address) const { return vaddr() <= address && address < vaddr() + size(); } - BAN::ErrorOr allocate_page_for_demand_paging(vaddr_t address); + BAN::ErrorOr allocate_page_for_demand_paging(vaddr_t address); private: VirtualRange(PageTable&, bool preallocated, bool has_guard_pages, vaddr_t, size_t, PageTable::flags_t); diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index d54bd9b1..318a0b17 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -170,6 +170,7 @@ namespace Kernel BAN::ErrorOr sys_mmap(const sys_mmap_t*); BAN::ErrorOr sys_munmap(void* addr, size_t len); + BAN::ErrorOr sys_mprotect(void* addr, size_t len, int prot); BAN::ErrorOr sys_msync(void* addr, size_t len, int flags); BAN::ErrorOr sys_smo_create(size_t len, int prot); diff --git a/kernel/kernel/Device/FramebufferDevice.cpp b/kernel/kernel/Device/FramebufferDevice.cpp index 910a8bc8..60943df9 100644 --- a/kernel/kernel/Device/FramebufferDevice.cpp +++ b/kernel/kernel/Device/FramebufferDevice.cpp @@ -241,9 +241,9 @@ namespace Kernel class FramebufferMemoryRegion : public MemoryRegion { public: - static BAN::ErrorOr> create(PageTable& page_table, size_t size, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags, BAN::RefPtr framebuffer) + static BAN::ErrorOr> create(PageTable& page_table, size_t size, AddressRange address_range, MemoryRegion::Type region_type, PageTable::flags_t page_flags, int status_flags, BAN::RefPtr 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::adopt(region_ptr); @@ -258,7 +258,7 @@ namespace Kernel m_framebuffer->sync_pixels_full(); } - virtual BAN::ErrorOr msync(vaddr_t vaddr, size_t size, int flags) override + BAN::ErrorOr 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> clone(PageTable& new_page_table) override + BAN::ErrorOr> 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::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 allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override + BAN::ErrorOr 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 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 framebuffer) + : MemoryRegion(page_table, size, region_type, page_flags, status_flags) , m_framebuffer(framebuffer) { } @@ -370,7 +370,7 @@ namespace Kernel BAN::RefPtr m_framebuffer; }; - BAN::ErrorOr> 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> 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(BAN::move(region)); } diff --git a/kernel/kernel/ELF.cpp b/kernel/kernel/ELF.cpp index b491950d..8efb8965 100644 --- a/kernel/kernel/ELF.cpp +++ b/kernel/kernel/ELF.cpp @@ -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) diff --git a/kernel/kernel/Memory/FileBackedRegion.cpp b/kernel/kernel/Memory/FileBackedRegion.cpp index f9e15a2c..fdfbe383 100644 --- a/kernel/kernel/Memory/FileBackedRegion.cpp +++ b/kernel/kernel/Memory/FileBackedRegion.cpp @@ -7,7 +7,7 @@ namespace Kernel { - BAN::ErrorOr> FileBackedRegion::create(BAN::RefPtr inode, PageTable& page_table, off_t offset, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags) + BAN::ErrorOr> FileBackedRegion::create(BAN::RefPtr 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::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, PAGE_SIZE))); LockGuard _(inode->m_mutex); @@ -39,8 +39,8 @@ namespace Kernel return region; } - FileBackedRegion::FileBackedRegion(BAN::RefPtr 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, 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> 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 diff --git a/kernel/kernel/Memory/MemoryBackedRegion.cpp b/kernel/kernel/Memory/MemoryBackedRegion.cpp index 8723b970..99f8b22c 100644 --- a/kernel/kernel/Memory/MemoryBackedRegion.cpp +++ b/kernel/kernel/Memory/MemoryBackedRegion.cpp @@ -4,12 +4,12 @@ namespace Kernel { - BAN::ErrorOr> MemoryBackedRegion::create(PageTable& page_table, size_t size, AddressRange address_range, Type type, PageTable::flags_t flags) + BAN::ErrorOr> 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::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) { diff --git a/kernel/kernel/Memory/MemoryRegion.cpp b/kernel/kernel/Memory/MemoryRegion.cpp index f0e11d0d..8741c6c1 100644 --- a/kernel/kernel/Memory/MemoryRegion.cpp +++ b/kernel/kernel/Memory/MemoryRegion.cpp @@ -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 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(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 MemoryRegion::allocate_page_containing(vaddr_t address, bool wants_write) { ASSERT(contains(address)); diff --git a/kernel/kernel/Memory/VirtualRange.cpp b/kernel/kernel/Memory/VirtualRange.cpp index 8d640bdd..e3b52278 100644 --- a/kernel/kernel/Memory/VirtualRange.cpp +++ b/kernel/kernel/Memory/VirtualRange.cpp @@ -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 VirtualRange::allocate_page_for_demand_paging(vaddr_t vaddr) + BAN::ErrorOr 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(vaddr), 0, PAGE_SIZE); - return {}; + return true; } } diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 495d2a2d..f62914d7 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -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 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 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(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 Process::sys_msync(void* addr, size_t len, int flags) { if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE) diff --git a/userspace/libraries/LibC/include/sys/syscall.h b/userspace/libraries/LibC/include/sys/syscall.h index a909adc0..2f67d999 100644 --- a/userspace/libraries/LibC/include/sys/syscall.h +++ b/userspace/libraries/LibC/include/sys/syscall.h @@ -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) \ diff --git a/userspace/libraries/LibC/sys/mman.cpp b/userspace/libraries/LibC/sys/mman.cpp index b84b9006..eb4d65ab 100644 --- a/userspace/libraries/LibC/sys/mman.cpp +++ b/userspace/libraries/LibC/sys/mman.cpp @@ -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(); -}