前言
NetBSD 的 mmap(2) 手册
讲解 prot
入参的部分提到:
Note that, due to hardware limitations, on some platforms
PROT_WRITE
may implyPROT_READ
, andPROT_READ
may implyPROT_EXEC
. Portable programs should not rely on these flags being separately enforceable.
我们熟知的“权限分为 rwx
,各用一个 bit 表示”只是一种理想的模型,实际硬件上不一定是这么实现的。
问题背景
ARMv8.1 处理器引入了 PAN(Privileged Access Never)特性,在 PSTATE 中添加了一个 PAN 位:当该位为 1 时,对 EL0 可访问的虚拟内存地址,所有来自更高特权级的访问都会产生权限错误。
XOM 意为 eXecute-Only Memory,顾名思义,指的是一段仅可执行的内存。
上述 PAN 特性有个 bug:对一个 EL0 的 XOM 地址而言,PAN 不生效。
问题详情
ARM64 的页描述符(Page Descriptor)中与权限相关的属性如下:
-
AP[2:1]
1 管理着内核态(EL1)和用户态(EL0)对该页的读写权限。当AP[1]
为 0 时,EL0 对该页无读写权限。 -
UXN
2 管理着用户态(EL0)对该页的执行权限。当UXN
为 0 时,EL0 对该页有执行权限。
那么,当 UXN == 0 && AP[1] == 0
时,EL0 对该页的权限为 --x
,即该页为 EL0 的 XOM 内存。
仅凭页描述符中的控制位,可实现的 EL1 最小权限为 r--
。若要剥夺这最后的读权限,需要凭借 PAN 特性来实现。但在上述情况下,PAN 特性并不生效。
ARMv8 文档 中关于 PAN 是这么说的:
FEAT_PAN, Privileged access never
FEAT_PAN adds a bit to PSTATE. When the value of this PAN state bit is 1, any privileged data access from EL1, or EL2 when HCR_EL2.E2H is 1, to a virtual memory address that is accessible to data accesses at EL0, generates a Permission fault.
既然该特性阻止的是 EL1 对“EL0 accessible”的地址的访问,那么此处的“accessible”要怎么理解就成了关键。现实情况是,这里的 accessible 实际等同于 readable:
也就是说,若 EL0 对某个地址的权限为 --x
,那么 PAN 就不会认为该地址是 EL0 accessible 的,便不会阻止 EL1 对该地址的访问。
参考资料:
解决方案
ARMv8.7 引入了 PAN3 特性,该特性引入 SCTLR_EL1.EPAN
:当该位为 1 时,PAN 对 EL0 的 XOM 生效。PAN3 与 PAN 一样,由 ID_AA64MMFR1_EL1.PAN
指示当前处理器是否支持该特性。
Linux 适配 EPAN 的补丁集:[PATCH v4 0/2] arm64: Support Enhanced PAN