diff --git a/VKernel/Kernel/paging/paging.vp b/VKernel/Kernel/paging/paging.vp index f459192..0bfd583 100644 --- a/VKernel/Kernel/paging/paging.vp +++ b/VKernel/Kernel/paging/paging.vp @@ -205,6 +205,14 @@ def _set_page_writable(phys_addr: uint64): pdp_s: _p* = _p*(pml4.entries[pml4_idx] & ~uint64(0xFFF)) pdp_idx: uint64 = (va >> 30) & 0x1FF if not (pdp_s.entries[pdp_idx] & PTE_PRESENT): return + if pdp_s.entries[pdp_idx] & PTE_PS: + # 1GB 大页(PDPTE.PS=1,固件 identity 映射常见):没有下层 PD,W 位在本条目自身。 + # 若仍按 `& ~0xFFF` 取"PD 基址",条目位 63(NX,固件对 1GB 数据页常置 1)会一起被带出来 + # → 派生指针非规范 → 读 %rax+idx*8 即 #GP(0)(现场 rip=0x11a93e,偶发取决于该 VA 是否 + # 落进 1GB 大页)。与下面 2MB 分支同口径:直接置本条目 W 位。 + pdp_s.entries[pdp_idx] = pdp_s.entries[pdp_idx] | uint64(PTE_WRITABLE) + __asm__(f"invlpg [{asminp(va, ASM_DESCR.REG_ANY)}]") + return pd_s: _p* = _p*(pdp_s.entries[pdp_idx] & ~uint64(0xFFF)) pd_idx: uint64 = (va >> 21) & 0x1FF if not (pd_s.entries[pd_idx] & PTE_PRESENT): return @@ -234,6 +242,12 @@ def MakePTWritable(): pj: uint64 for pj in range(512): if not (pdp_m.entries[pj] & PTE_PRESENT): continue + # 1GB 大页(PDPTE.PS=1)不是页表页:把它当 PD 解引用,会把大页内存内容当表项读 + # (其中约一半 qword 的 bit0=1)→ 按"表项"递归 _set_page_writable 随机地址 → 任意 + # 内存被置 W 位(偶发数据损坏)且可算出非规范指针 → #GP。跳过(与下面 2MB 的 + # `if PTE_PS: continue` 同口径);若页表页本身落在 1GB 大页里,则由上面 + # _set_page_writable(该页地址) 命中 1GB 分支把大页条目的 W 位置起。 + if pdp_m.entries[pj] & PTE_PS: continue pd_m: _p* = _p*(pdp_m.entries[pj] & ~uint64(0xFFF)) _set_page_writable(uint64(pd_m)) pk: uint64 @@ -264,6 +278,10 @@ def MakeRangeRO(vaddr_start: uint64, vaddr_end: uint64): pdp_r: _p* = _p*(pml4.entries[pml4_idx] & ~uint64(0xFFF)) pdp_idx: uint64 = (va >> 30) & 0x1FF if not (pdp_r.entries[pdp_idx] & PTE_PRESENT): va += 0x1000; continue + # 1GB 大页(PDPTE.PS=1):同样不是 PD,当 PD 用会把大页内容当表项读(并据其"表项" + # 写页表 → 写坏任意内存)。1GB 大页拆分需新建 1 个 PD + 若干 PT(513 页),此处不支持 + # → 跳过该页。后果:若 .rodata 落在 1GB 大页内则该段保持可写(不保护),但绝不再写坏内存。 + if pdp_r.entries[pdp_idx] & PTE_PS: va += 0x1000; continue pd_r: _p* = _p*(pdp_r.entries[pdp_idx] & ~uint64(0xFFF)) pd_idx: uint64 = (va >> 21) & 0x1FF if not (pd_r.entries[pd_idx] & PTE_PRESENT): va += 0x1000; continue