diff --git a/VKernel/Kernel/main.vp b/VKernel/Kernel/main.vp index ead55cc..835d77a 100644 --- a/VKernel/Kernel/main.vp +++ b/VKernel/Kernel/main.vp @@ -176,7 +176,10 @@ class ViperKernel: mm.init(0, 0, 0, 0, 0) pt_pool_buf2: t.CVoid | t.CPtr = mm.malloc(t.CUInt64T(513) * t.CUInt64T(4096)) paging.init_pool(pt_pool_buf2, t.CUInt64T(513) * t.CUInt64T(4096)) - serial.puts("[main] paging and mm init done\n") + serial.puts("[main] paging and mm init done\n") + # 把 .rodata(字符串常量/vtable)映射只读 + CR0.WP=1: + # 越界写立即 #PF 暴露 cr2/rip(此前静默破坏格式串/路径/符号名 → P2/P3/P4/P5 连锁) + paging.ProtectKernelRO() proc.ProcessManager() serial.puts("[main] process manager init done\n") diff --git a/VKernel/Kernel/paging/paging.vp b/VKernel/Kernel/paging/paging.vp index 9b5dcd6..dbdcfce 100644 --- a/VKernel/Kernel/paging/paging.vp +++ b/VKernel/Kernel/paging/paging.vp @@ -30,9 +30,12 @@ pt: _p | t.CPtr def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T): global pml4 pml4 = GetCurrentPml4() + # 置位 CR0.WP:内核态写只读页也会 #PF(此前清除 WP 使页表只读形同虚设, + # 越界写 .rodata 字符串常量静默破坏 → 格式串/路径/符号名损坏连锁)。 + # 配合 ProtectKernelRO() 把 .rodata 页清 W 位,越界写立即 #PF 暴露写源。 c.Asm(f""" mov rax, cr0 - and rax, ~0x10000 + or rax, 0x10000 mov cr0, rax """) @@ -183,6 +186,48 @@ def EnablePaging(): global pml4, pdp, pd, pt c.Asm(f"mov cr3, {c.AsmInp(t.CUInt64T(pml4), t.ASM_DESCR.REG_ANY)}") +def MakeRangeRO(vaddr_start: t.CUInt64T, vaddr_end: t.CUInt64T): + """把 [vaddr_start, vaddr_end) 范围内所有页的 PTE 清 W 位(只读) + + 定位越界写源:内核态写只读页在 CR0.WP=1 下触发 #PF(int=14), + isrCommonhandler 打印 cr2/rip → 写源立即暴露,不再静默破坏 .rodata。 + """ + global pml4 + if not pml4: return + va: t.CUInt64T = vaddr_start & ~t.CUInt64T(0xFFF) + while va < vaddr_end: + pml4_idx: t.CUInt64T = (va >> 39) & 0x1FF + if not (pml4.entries[pml4_idx] & PTE_PRESENT): va += 0x1000; continue + pdp_r: _p | t.CPtr = t.CType(pml4.entries[pml4_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr) + pdp_idx: t.CUInt64T = (va >> 30) & 0x1FF + if not (pdp_r.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue + pd_r: _p | t.CPtr = t.CType(pdp_r.entries[pdp_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr) + pd_idx: t.CUInt64T = (va >> 21) & 0x1FF + if not (pd_r.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue + if pd_r.entries[pd_idx] & PTE_PS: va += 0x200000; continue + pt_r: _p | t.CPtr = t.CType(pd_r.entries[pd_idx] & ~t.CUInt64T(0xFFF), _p, t.CPtr) + pt_idx: t.CUInt64T = (va >> 12) & 0x1FF + pt_r.entries[pt_idx] = pt_r.entries[pt_idx] & ~t.CUInt64T(PTE_WRITABLE) + c.Asm(f"invlpg [{c.AsmInp(va, t.ASM_DESCR.REG_ANY)}]") + va += 0x1000 + +def ProtectKernelRO(): + """把内核镜像 .rodata 段(字符串常量/vtable 等)映射为只读 + + 地址经 c.Asm 内联引用链接器符号 __rodata_start/__rodata_end + (linker.ld 定义,TPV 不声明 extern——避免生成定义与链接器符号冲突)。 + """ + global pml4 + if not pml4: return + ro_start: t.CUInt64T = 0 + ro_end: t.CUInt64T = 0 + c.Asm(f"""lea rax, [rip + __rodata_start] + mov {c.AsmOut(ro_start, t.ASM_DESCR.OUTPUT_REG)}, rax + lea rax, [rip + __rodata_end] + mov {c.AsmOut(ro_end, t.ASM_DESCR.OUTPUT_REG)}, rax""", + op=[t.ASM_DESCR.CLOBBER_RAX]) + MakeRangeRO(ro_start, ro_end) + def GetCurrentPml4() -> _p | t.CPtr: global pml4, pdp, pd, pt cr3: t.CUInt64T diff --git a/VKernel/linker.ld b/VKernel/linker.ld index 9ad6879..d994a3a 100644 --- a/VKernel/linker.ld +++ b/VKernel/linker.ld @@ -10,8 +10,10 @@ SECTIONS { } .rodata : { + __rodata_start = .; *(.rodata) *(.rodata.*) + __rodata_end = .; } .data : {