x86 中 DPL 和 RPL 的区别
Difference between DPL and RPL in x86
阅读intel x86手册和其他资源,我不明白DPL(描述符特权级别)和RPL(请求特权级别)之间的区别。
为什么需要两者兼而有之?
非常感谢
问得好。
CPL vs. DPL vs. RPL
为了简单起见,我们首先只考虑 CPL 和 DPL:
- CPL 是您当前的权限级别。
- DPL 是段的特权级别。它定义了访问该段所需的最低1 权限级别。
- 权限级别范围为0-3;较低的数字是 更多 特权
- 所以:要访问一个段,CPL必须小于等于该段的DPL
RPL 是与段选择器 关联的特权级别。段选择器只是一个引用段的 16 位值。每个内存访问(隐式2 或其他方式)都使用段选择器作为访问的一部分。
访问段时,实际上有两个检查必须执行。仅当满足以下条件 时才允许访问该段:
- CPL <= DPL
- RPL <= DPL
因此即使 CPL 有足够的权限访问一个段,如果引用该段的段选择器没有足够的权限,访问仍然会被拒绝。
RPL背后的动机
这样做的目的是什么? 好吧,推理现在有点过时了,但英特尔文档提供了一个类似这样的场景:
- 假设操作系统提供了一个系统调用,它接受来自调用者的逻辑地址(段选择器+偏移量)并写入该地址
- CPL 为 3 的普通应用程序 运行; CPL 为 0
的系统调用 运行
- 假设某个片段(我们称之为 X)的 DPL 为 0
应用程序通常无法访问段 X 中的内存(因为 CPL > DPL)。但是根据系统调用的实现方式,应用程序可能能够使用段 X 中的地址参数调用系统调用。然后,由于系统调用是特权的,它能够代表写入段 X的应用程序。这可能会在操作系统中引入 privilege escalation vulnerability。
为了缓解这种情况,官方建议当特权例程接受非特权代码提供的段选择器时,它应该首先设置段选择器的 RPL 以匹配非特权代码的 RPL3 。这样,操作系统将无法对非特权调用者无法访问的段进行任何访问。这有助于加强操作系统和应用程序之间的界限。
过去与现在
在 x86 系列处理器中存在分页之前,286 引入了段保护。当时,分段是限制从 user-mode 上下文访问内核内存的唯一方法。 RPL 提供了一种方便的方法来在跨不同权限级别传递指针时强制执行此限制。
现代操作系统使用分页来限制对内存的访问,从而消除了分段的需要。由于我们不需要分段,我们可以使用 flat memory model, which means segment registers CS
, DS
, SS
, and ES
all have a base of zero and extend through the entire address space. In fact, in 64-bit "long mode", a flat memory model is enforced, regardless of the contents of those four segment registers. Segments are still used sometimes (for example, Windows uses FS
and GS
to point to the Thread Information Block and 0x23 and 0x33 to switch between 32- and 64-bit code,Linux 是类似的),但您只是不再传递分段。所以 RPL 主要是旧时代未使用的剩余物。
RPL:有没有必要?
您问为什么必须同时拥有 DPL 和 RPL。即使在 286 的背景下,实际上 没有必要 拥有 RPL。考虑到上述情况,特权过程总是可以通过 LAR 指令检索提供的段的 DPL,将其与调用者的特权进行比较,如果调用者的特权不足以访问该段,则抢先退出。但是,在我看来,设置 RPL 是管理不同权限级别的段访问的一种更优雅、更简单的方法。
要了解有关权限级别的更多信息,请查看 Intel's software developer manuals 的第 3 卷,尤其是标题为 "Privilege Levels" 和 "Checking Caller Access Privileges" 的部分。
1 从技术上讲,DPL 可以有不同的含义,具体取决于正在访问的段或门的类型。为了简单起见,我描述的所有内容都具体适用于 数据段 。查看英特尔文档以获取更多信息
2例如指令指针在取指令时隐式使用CS中存储的段选择符;大多数类型的数据访问隐式使用存储在 DS 等中的段选择器
3见ARPL指令(16-bit/32-bit保护模式)
阅读intel x86手册和其他资源,我不明白DPL(描述符特权级别)和RPL(请求特权级别)之间的区别。 为什么需要两者兼而有之? 非常感谢
问得好。
CPL vs. DPL vs. RPL
为了简单起见,我们首先只考虑 CPL 和 DPL:
- CPL 是您当前的权限级别。
- DPL 是段的特权级别。它定义了访问该段所需的最低1 权限级别。
- 权限级别范围为0-3;较低的数字是 更多 特权
- 所以:要访问一个段,CPL必须小于等于该段的DPL
RPL 是与段选择器 关联的特权级别。段选择器只是一个引用段的 16 位值。每个内存访问(隐式2 或其他方式)都使用段选择器作为访问的一部分。
访问段时,实际上有两个检查必须执行。仅当满足以下条件 时才允许访问该段:
- CPL <= DPL
- RPL <= DPL
因此即使 CPL 有足够的权限访问一个段,如果引用该段的段选择器没有足够的权限,访问仍然会被拒绝。
RPL背后的动机
这样做的目的是什么? 好吧,推理现在有点过时了,但英特尔文档提供了一个类似这样的场景:
- 假设操作系统提供了一个系统调用,它接受来自调用者的逻辑地址(段选择器+偏移量)并写入该地址
- CPL 为 3 的普通应用程序 运行; CPL 为 0 的系统调用 运行
- 假设某个片段(我们称之为 X)的 DPL 为 0
应用程序通常无法访问段 X 中的内存(因为 CPL > DPL)。但是根据系统调用的实现方式,应用程序可能能够使用段 X 中的地址参数调用系统调用。然后,由于系统调用是特权的,它能够代表写入段 X的应用程序。这可能会在操作系统中引入 privilege escalation vulnerability。
为了缓解这种情况,官方建议当特权例程接受非特权代码提供的段选择器时,它应该首先设置段选择器的 RPL 以匹配非特权代码的 RPL3 。这样,操作系统将无法对非特权调用者无法访问的段进行任何访问。这有助于加强操作系统和应用程序之间的界限。
过去与现在
在 x86 系列处理器中存在分页之前,286 引入了段保护。当时,分段是限制从 user-mode 上下文访问内核内存的唯一方法。 RPL 提供了一种方便的方法来在跨不同权限级别传递指针时强制执行此限制。
现代操作系统使用分页来限制对内存的访问,从而消除了分段的需要。由于我们不需要分段,我们可以使用 flat memory model, which means segment registers CS
, DS
, SS
, and ES
all have a base of zero and extend through the entire address space. In fact, in 64-bit "long mode", a flat memory model is enforced, regardless of the contents of those four segment registers. Segments are still used sometimes (for example, Windows uses FS
and GS
to point to the Thread Information Block and 0x23 and 0x33 to switch between 32- and 64-bit code,Linux 是类似的),但您只是不再传递分段。所以 RPL 主要是旧时代未使用的剩余物。
RPL:有没有必要?
您问为什么必须同时拥有 DPL 和 RPL。即使在 286 的背景下,实际上 没有必要 拥有 RPL。考虑到上述情况,特权过程总是可以通过 LAR 指令检索提供的段的 DPL,将其与调用者的特权进行比较,如果调用者的特权不足以访问该段,则抢先退出。但是,在我看来,设置 RPL 是管理不同权限级别的段访问的一种更优雅、更简单的方法。
要了解有关权限级别的更多信息,请查看 Intel's software developer manuals 的第 3 卷,尤其是标题为 "Privilege Levels" 和 "Checking Caller Access Privileges" 的部分。
1 从技术上讲,DPL 可以有不同的含义,具体取决于正在访问的段或门的类型。为了简单起见,我描述的所有内容都具体适用于 数据段 。查看英特尔文档以获取更多信息
2例如指令指针在取指令时隐式使用CS中存储的段选择符;大多数类型的数据访问隐式使用存储在 DS 等中的段选择器
3见ARPL指令(16-bit/32-bit保护模式)