Skip to content

Commit

Permalink
Kernel: Add mechanism to make some memory read-only after init finishes
Browse files Browse the repository at this point in the history
You can now use the READONLY_AFTER_INIT macro when declaring a variable
and we will put it in a special ".ro_after_init" section in the kernel.

Data in that section remains writable during the boot and init process,
and is then marked read-only just before launching the SystemServer.

This is based on an idea from the Linux kernel. :^)
  • Loading branch information
awesomekling committed Feb 14, 2021
1 parent 917f7d6 commit d8013c6
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Kernel/Arch/i386/CPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include <Kernel/VirtualAddress.h>
#include <LibC/sys/arch/i386/regs.h>

#define READONLY_AFTER_INIT __attribute__((section(".ro_after_init")))

#define PAGE_SIZE 4096
#define GENERIC_INTERRUPT_HANDLERS_COUNT (256 - IRQ_VECTOR_BASE)
#define PAGE_MASK ((FlatPtr)0xfffff000u)
Expand Down
14 changes: 14 additions & 0 deletions Kernel/VM/MemoryManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ extern u8* end_of_kernel_image;
extern FlatPtr start_of_kernel_text;
extern FlatPtr start_of_kernel_data;
extern FlatPtr end_of_kernel_bss;
extern FlatPtr start_of_ro_after_init;
extern FlatPtr end_of_ro_after_init;

extern multiboot_module_entry_t multiboot_copy_boot_modules_array[16];
extern size_t multiboot_copy_boot_modules_count;
Expand Down Expand Up @@ -121,6 +123,18 @@ void MemoryManager::protect_kernel_image()
}
}

void MemoryManager::protect_readonly_after_init_memory()
{
ScopedSpinLock mm_lock(s_mm_lock);
ScopedSpinLock page_lock(kernel_page_directory().get_lock());
// Disable writing to the .ro_after_init section
for (auto i = (FlatPtr)&start_of_ro_after_init; i < (FlatPtr)&end_of_ro_after_init; i += PAGE_SIZE) {
auto& pte = *ensure_pte(kernel_page_directory(), VirtualAddress(i));
pte.set_writable(false);
flush_tlb(&kernel_page_directory(), VirtualAddress(i));
}
}

void MemoryManager::register_reserved_ranges()
{
ASSERT(!m_physical_memory_ranges.is_empty());
Expand Down
2 changes: 2 additions & 0 deletions Kernel/VM/MemoryManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ class MemoryManager {

PageFaultResponse handle_page_fault(const PageFault&);

void protect_readonly_after_init_memory();

static void enter_process_paging_scope(Process&);
static void enter_space(Space&);

Expand Down
3 changes: 3 additions & 0 deletions Kernel/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ void init_stage2(void*)

load_kernel_symbol_table();

// NOTE: Everything marked READONLY_AFTER_INIT becomes non-writable after this point.
MM.protect_readonly_after_init_memory();

int error;

// FIXME: It would be nicer to set the mode from userspace.
Expand Down
7 changes: 7 additions & 0 deletions Kernel/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ SECTIONS
end_of_kernel_data = .;
}

.ro_after_init ALIGN(4K) (NOLOAD) : AT(ADDR(.ro_after_init) - 0xc0000000)
{
start_of_ro_after_init = .;
*(.ro_after_init);
end_of_ro_after_init = .;
}

.bss ALIGN(4K) (NOLOAD) : AT (ADDR(.bss) - 0xc0000000)
{
start_of_kernel_bss = .;
Expand Down

0 comments on commit d8013c6

Please sign in to comment.