From 56e38c43ea6016915f8967e8839b1b381d1d13b8 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 29 Aug 2026 17:41:03 +0800 Subject: [PATCH] =?UTF-8?q?fix(kernel):=20MakePTWritable=20=E7=A7=BB?= =?UTF-8?q?=E5=88=B0=20WP=3D0=20=E9=98=B6=E6=AE=B5=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=EF=BC=8C=E7=A0=B4=E9=99=A4=E9=A1=B5=E8=A1=A8=E9=A1=B5=E9=80=92?= =?UTF-8?q?=E5=BD=92=E5=8F=AA=E8=AF=BB=E6=AD=BB=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 WP=1 后改页表页自身会写只读页 → #PF(ProtectKernelRO 阶段 cr2=0xf8033e0)。改为 paging.init 里先 MakePTWritable(WP=0 允许写只读页)再置 WP,ProtectKernelRO 只保护 .rodata 内容页。 --- VKernel/Kernel/paging/paging.vp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/VKernel/Kernel/paging/paging.vp b/VKernel/Kernel/paging/paging.vp index 0cb8027..6a9c4c3 100644 --- a/VKernel/Kernel/paging/paging.vp +++ b/VKernel/Kernel/paging/paging.vp @@ -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]