]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
x86: enforce W^X-like user mappings (text RO after load)
authorTulio A M Mendes <[email protected]>
Fri, 6 Feb 2026 18:10:32 +0000 (15:10 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 6 Feb 2026 18:10:32 +0000 (15:10 -0300)
include/vmm.h
src/arch/x86/vmm.c
src/kernel/elf.c
user/linker.ld

index d98e0db269150f1c643a0d7b1c478253e88c9449..791522621d6f1e6a4e6af491a75ee4ced2607a40 100644 (file)
@@ -31,6 +31,18 @@ void vmm_init(void);
  */
 void vmm_map_page(uint64_t phys, uint64_t virt, uint32_t flags);
 
+/*
+ * Update flags for an already-mapped virtual page.
+ * Keeps the physical frame, only changes PRESENT/RW/USER bits.
+ */
+void vmm_set_page_flags(uint64_t virt, uint32_t flags);
+
+/*
+ * Update flags for an already-mapped virtual range.
+ * vaddr/len may be unaligned.
+ */
+void vmm_protect_range(uint64_t vaddr, uint64_t len, uint32_t flags);
+
 /*
  * Unmap a virtual page.
  */
index 96969bd3fe7b39117db00c5712dbf4de08e44982..ad992d6189e1e07f67d7483f26737983ae503641 100644 (file)
@@ -48,6 +48,14 @@ static inline void invlpg(uintptr_t vaddr) {
     __asm__ volatile("invlpg (%0)" : : "r" (vaddr) : "memory");
 }
 
+static uint32_t vmm_flags_to_x86(uint32_t flags) {
+    uint32_t x86_flags = 0;
+    if (flags & VMM_FLAG_PRESENT) x86_flags |= X86_PTE_PRESENT;
+    if (flags & VMM_FLAG_RW)      x86_flags |= X86_PTE_RW;
+    if (flags & VMM_FLAG_USER)    x86_flags |= X86_PTE_USER;
+    return x86_flags;
+}
+
 void vmm_map_page(uint64_t phys, uint64_t virt, uint32_t flags) {
     uint32_t pd_index = virt >> 22;
     uint32_t pt_index = (virt >> 12) & 0x03FF;
@@ -82,16 +90,43 @@ void vmm_map_page(uint64_t phys, uint64_t virt, uint32_t flags) {
     
     // ACCESS SAFETY: Convert to Virtual
     uint32_t* pt = (uint32_t*)P2V(pt_phys);
-    
-    uint32_t x86_flags = 0;
-    if (flags & VMM_FLAG_PRESENT) x86_flags |= X86_PTE_PRESENT;
-    if (flags & VMM_FLAG_RW)      x86_flags |= X86_PTE_RW;
-    if (flags & VMM_FLAG_USER)    x86_flags |= X86_PTE_USER;
-    
-    pt[pt_index] = ((uint32_t)phys) | x86_flags;
+
+    pt[pt_index] = ((uint32_t)phys) | vmm_flags_to_x86(flags);
     invlpg(virt);
 }
 
+void vmm_set_page_flags(uint64_t virt, uint32_t flags) {
+    uint32_t pd_index = virt >> 22;
+    uint32_t pt_index = (virt >> 12) & 0x03FF;
+
+    if (!(boot_pd[pd_index] & X86_PTE_PRESENT)) {
+        return;
+    }
+
+    uint32_t pt_phys = boot_pd[pd_index] & 0xFFFFF000;
+    uint32_t* pt = (uint32_t*)P2V(pt_phys);
+
+    uint32_t pte = pt[pt_index];
+    if (!(pte & X86_PTE_PRESENT)) {
+        return;
+    }
+
+    uint32_t phys = pte & 0xFFFFF000;
+    pt[pt_index] = phys | vmm_flags_to_x86(flags);
+    invlpg((uintptr_t)virt);
+}
+
+void vmm_protect_range(uint64_t vaddr, uint64_t len, uint32_t flags) {
+    if (len == 0) return;
+
+    uint64_t start = vaddr & ~0xFFFULL;
+    uint64_t end = (vaddr + len - 1) & ~0xFFFULL;
+    for (uint64_t va = start;; va += 0x1000ULL) {
+        vmm_set_page_flags(va, flags | VMM_FLAG_PRESENT);
+        if (va == end) break;
+    }
+}
+
 void vmm_unmap_page(uint64_t virt) {
     uint32_t pd_index = virt >> 22;
     uint32_t pt_index = (virt >> 12) & 0x03FF;
index 77c7b9f5e255df15a52b286b6244bac208e8c3f2..4340491b71a86a87bb661a3ad4c1f517b88b385e 100644 (file)
@@ -165,6 +165,11 @@ int elf32_load_user_from_initrd(const char* filename, uintptr_t* entry_out, uint
         if (ph[i].p_memsz > ph[i].p_filesz) {
             memset((void*)(uintptr_t)(ph[i].p_vaddr + ph[i].p_filesz), 0, ph[i].p_memsz - ph[i].p_filesz);
         }
+
+        if ((ph[i].p_flags & PF_W) == 0) {
+            vmm_protect_range((uint64_t)(uintptr_t)ph[i].p_vaddr, (uint64_t)ph[i].p_memsz,
+                              VMM_FLAG_USER);
+        }
     }
 
     const uintptr_t user_stack_base = 0x00800000U;
index 91522c204cffb9ef07faac59a0259ceac1f6804e..de6920a1844ae931e40734d9efe8a0389ff70479 100644 (file)
@@ -11,7 +11,8 @@ ENTRY(_start)
 
 PHDRS
 {
-    text PT_LOAD FLAGS(7);
+    text PT_LOAD FLAGS(5);
+    data PT_LOAD FLAGS(6);
 }
 
 SECTIONS
@@ -28,10 +29,10 @@ SECTIONS
 
     .data : {
         *(.data*)
-    } :text
+    } :data
 
     .bss : {
         *(.bss*)
         *(COMMON)
-    } :text
+    } :data
 }