fix(kernel): .rodata 映射只读 + CR0.WP=1,越界写立即 #PF 暴露写源
此前清 WP + 页表全可写,越界写 .rodata 字符串常量静默破坏(格式串 %lu 变 %lc、路径/符号名损坏连锁 → work=+/eyboard/terminal.elf 加载失败)。ProtectKernelRO 经 c.Asm 引用 __rodata_start/__rodata_end 清 PTE_WRITABLE,配合 CR0.WP 置位,越界写触发 #PF 打印 cr2/rip。
This commit is contained in:
1 parent
b887d3d9c2
commit
04ca2d4c5b
3 files changed
+52
-2
No files matched your search
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,8 +10,10 @@ SECTIONS {
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
__rodata_start = .;
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
__rodata_end = .;
|
||||
}
|
||||
|
||||
.data : {
|
||||
|
||||
Reference in new issue
Block a user