虚悬页表
摘要 内核页表隔离 (KPTI) 是防御 Meltdown 类攻击的关键机制,通过分离用户态与内核态页表,确保用户态代码无法直接窥探内核地址空间。在 ARM64 上,KPTI 由 CONFIG_UNMAP_KERNEL_AT_EL0 和 kpti 引导参数控制,利用 TTBR0_EL1 与 TTBR1_EL1 的切换将内核映射仅在异常入口时临时暴露。然而,ARM 体系结构的维护操作(Maintenance Operations)存在一个隐蔽缺陷:部分 SoC 的 TLBI(TLB Invalidate)指令和 IC IALLU 序列仅刷新 TLB 而不冲刷页表缓存(PTC, Page Table Cache),导致在异常返回(ERET)后,TTBR1 中残留的中间页表项仍可通过推测执行或预取被用户态感知。攻击者利用性能监控单元(PMU)的精确计数器,在用户态测量内核地址访问的延迟差异,即使 KPTI 已重新隔离页表,仍可通过这些“虚悬的页表”还原内核基址,从而击碎 KASLR。 双重身份页表 两个TTBR ARM64 的虚拟地址空间分为两个区域:0x0000_0000_0000_0000 到 0x0000_FFFF_FFFF_FFFF 为用户空间,0xFFFF_0000_0000_0000 以上为内核空间。当 MMU 进行地址翻译时,根据虚拟地址的最高位自动选择页表基址寄存器:用户地址使用 TTBR0_EL1,内核地址使用 TTBR1_EL1。在未启用 KPTI 的情况下,两个寄存器都指向同一个页表(通常包含内核映射),用户态代码虽不能直接访问内核内存(受页表权限 U/S 位控制),但可以通过侧信道探测 TLB 存在性。 ======================= 正常态:用户空间 (EL0) ======================= CPU 视角: +——————–+ +——————–+ | TTBR0_EL1 (受限表) | —-> | 仅映射:用户空间 | (只读内核映射表) +——————–+ +——————–+…