fix(kernel): MakePTWritable 移到 WP=0 阶段执行,破除页表页递归只读死锁

在 WP=1 后改页表页自身会写只读页 → #PF(ProtectKernelRO 阶段 cr2=0xf8033e0)。改为 paging.init 里先 MakePTWritable(WP=0 允许写只读页)再置 WP,ProtectKernelRO 只保护 .rodata 内容页。
This commit is contained in:
TermiNexus committed 2026-08-29 17:41:03 +08:00
1 parent 4f729b20a3
commit 56e38c43ea
1 file changed
+7 -3
+7 -3
View File
@@ -30,6 +30,11 @@ pt: _p | t.CPtr
def init(MemmapAddr: t.CUInt64T, MemmapSize: t.CUInt64T):
global pml4
pml4 = GetCurrentPml4()
# 先把所有页表页设为可写(此时 CR0.WP=0,允许写只读页表页):
# bootloader 建立的 pml4/pdp/pd/pt 位于 0xf8xxxx 默认只读,而内核运行时
# MapPage/clone 需修改页表。若在 WP=1 之后再改页表页自身 → 写只读页 #PF
# (ProtectKernelRO 阶段 cr2=0xf8033e0 根因:设大页 W 位时写 pd 页自身)。
MakePTWritable()
# 置位 CR0.WP:内核态写只读页也会 #PF(此前清除 WP 使页表只读形同虚设,
# 越界写 .rodata 字符串常量静默破坏 → 格式串/路径/符号名损坏连锁)。
# 配合 ProtectKernelRO() 把 .rodata 页清 W 位,越界写立即 #PF 暴露写源。
@@ -274,9 +279,8 @@ def ProtectKernelRO():
"""
global pml4
if not pml4: return
# 先放开页表页自身(bootloader 映射只读,内核运行需修改页表),
# 再保护 .rodata 内容页——否则写页表即 #PF(slog.so 映射 0x600000 根因)。
MakePTWritable()
# 页表页可写已在 paging.init(WP=0 阶段)由 MakePTWritable 完成,
# 此处只保护 .rodata 内容页(WP=1 后写只读页即 #PF 暴露写源)。
ro_start: t.CUInt64T = 0
ro_end: t.CUInt64T = 0
c.Asm(f"""lea rax, [rip + __rodata_start]