x86-64页表全局位

use*_*390 8 x86 x86-64 page-tables

此设置中的每个 PTE(页表项)都有一个 G 位(G = 全局),它控制该项映射的物理页的范围。

如果设置了 G 位,则该条目对于所有进程都是全局的,并且它们都可以访问它映射的物理页,但须遵守其他访问权限。如果 G 位为零,则该条目不是全局的,而是进程私有的。[内核为其页面设置 G 位,但通过禁用其页面上的 U 位(U = 用户模式)来阻止用户模式访问。]

如果在用户模式 ​​PTE(设置了 U 位的 PTE)上设置 G 位,这不是一种安全漏洞,因为系统上的每个进程现在都可以访问 PTE 映射的页面?

我错过了什么吗?有没有办法在用户模式 ​​PTE 上设置 G 位,但仅在一组受信任的进程中使其全局,而不是系统上的所有进程?我们可以在 PTE 中同时设置 G 和 U 位吗?

Bee*_*ope 2

是的,在 x86 上,G 位仅在存在其他类型的控制时(例如将其限制为 Ring 0,这是内核使用的)或在不受保护的操作系统1上才有用。

将 G 位视为系统调用的优化:内核将其页面映射为全局页面,因此不需要进行 TLB 刷新。您仍然需要在进程之间的上下文切换上进行 TLB 刷新,但这些通常比内核<->用户模式切换少几个数量级。

您可以想象这样一个场景,其中 G 页对用户进程有用,例如共享内存:如果内核意识到这一点并为两个进程使用映射,则两个进程G==1之间的切换不需要使共享内存的 TLB 条目无效。不过,如今 TLB 重新填充实际上并没有那么糟糕,因为现代 x86 缓存了许多表条目,甚至超出了 TLB,以允许快速重新填充。

我不认为设置 G 和 U 位是不允许的,但内核实际上不会那样设置。

最后一点,您实际上可以想象只读全局映射对于vdso机制之类的东西很有用。所有进程都会映射该页面,但无法修改它,内核会根据需要更新它。当然,我不知道如何实际完成这项工作,因为内核需要写访问权限,并且似乎没有办法在中表达“环3只读,环0读/写”页表。也许内核可以为此页面使用另一个映射,但我不确定这是否合法:拥有一个覆盖“G”映射的映射(因为如果 G 映射位于 TLB 中,则 CPU 可能永远不会看到覆盖的映射)。


1从技术上讲,它在单用户操作系统上可能很有用,其中所有用户模式进程都具有相同的权限,但内核仍然受到用户模式的保护,但据我所知,这种模型在当代操作系统中并不存在。