Parcourir la source

Kernel: Add mechanism to make some memory read-only after init finishes

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. :^)
Andreas Kling il y a 4 ans
Parent
commit
d8013c60bb
5 fichiers modifiés avec 28 ajouts et 0 suppressions
  1. 2 0
      Kernel/Arch/i386/CPU.h
  2. 14 0
      Kernel/VM/MemoryManager.cpp
  3. 2 0
      Kernel/VM/MemoryManager.h
  4. 3 0
      Kernel/init.cpp
  5. 7 0
      Kernel/linker.ld

+ 2 - 0
Kernel/Arch/i386/CPU.h

@@ -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)

+ 14 - 0
Kernel/VM/MemoryManager.cpp

@@ -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;
@@ -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());

+ 2 - 0
Kernel/VM/MemoryManager.h

@@ -141,6 +141,8 @@ public:
 
     PageFaultResponse handle_page_fault(const PageFault&);
 
+    void protect_readonly_after_init_memory();
+
     static void enter_process_paging_scope(Process&);
     static void enter_space(Space&);
 

+ 3 - 0
Kernel/init.cpp

@@ -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.

+ 7 - 0
Kernel/linker.ld

@@ -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 = .;