特权级别(ring 0和ring 3)

 前言:

    大家时常看到ring 0、1、2、3等,那么我们今天来说下这个ring number
    x86指令集中特权级别控制当前在处理器上运行的程序对内存区域、I/O 端口和特殊指令等资源的访问。有 4 个特权级别,从 0(最高特权)到 3(最低特权)。大多数现代操作系统对内核/执行程序使用 0 级,对应用程序使用 3 级。级别 n 可用的任何资源也可用于级别 0 到 n,因此特权级别是环。当权限较低的进程试图访问权限较高的进程时,会向操作系统报告一般保护错误异常。
    Linux 和 Windows 仅使用 ring 0 和 ring 3,但其他一些操作系统可以使用三个不同的保护级别。

   

 ring 0(不是字母的o,为是数字的0)

内核是操作系统的核心,可以访问所有内容,可以访问 Ring 0。这里运行的代码被称为内核模式。内核模式进程有可能影响整个系统。
如果这里出现问题,系统很可能会崩溃。因为ring 0可以直接访问CPU和系统内存


ring 1 和ring 2

 ring 1 和ring 2 提供了ring 3 所缺乏的独特优势。操作系统使用ring 1 与计算机硬件进行交互。这个戒指需要运行命令,
例如通过我们监视器上的摄像头流式传输视频。必须与系统存储、加载或保存文件交互的指令存储在ring 2 中。 这些权限称为输入和输出权限,因为它们涉及将数据传入和传出工作内存RAM。 例如,在ring 2 中,从存储中加载 Excel 文件文档。在这种情况下,ring 3 将负责编辑和保存数据。


 ring 3

以用户模式运行的用户进程可以访问 Ring 3。因此,这是权限最低的ring。这是我们可以找到大部分计算机应用程序的地方。
由于ring 3无法访问CPU或内存,因此涉及这些的任何指令都必须传递给ring 0


那么它有没有具体的实现呢? 当然有。这需要你了解 GDT(全局描述符表)的条目段描述符
  处理器通过识别CPL、DPL、RPL这3种特权级进行特权级检验。

 Segment Descriptor(段描述符)

     每个段描述符通过指定base 地址和大小来定义虚拟内存区域。此外,还有各种标志位和特权级别(Privilege level)。将 0x100 与段大小进行比较(它必须更小,否则地址在 CS 段之外!)然后添加到base地址以形成“线性”虚拟地址

   段描述符表中的每个条目都有一个复杂的结构,我们以结构的方式展现:(x86 and x86-64 segment descriptor)

Segment Descriptor(段描述符)
63   5655   5251   4847   4039   32
Base
31   24
Flags
3   0
Limit
19   16
Access Byte
7   0
Base
23   16
31   1615   0
Base
15   0
Limit
15   0


    我们以计算机存储的方式按位来展现一下
      

 

  • Base:  一个 32-bit 值,包含段(segment)开始的线性地址。
  • Limit:  一个 20-bit的值, 告诉最大可寻址单元, 任何一个以1字节, 或 以 4KiB pages为单位.
    因此,如果选page为粒度并将“limit”值设置为0xFFFFF,则在32位模式下该段将跨越整个4GiB地址空间。

       在 64-bit模式下,  Base 和 Limit 的值是被忽略的, 每个描述符覆盖整个线性地址空间,而不管它们被设置为什么。

访问字节0-7 bit 一共8个bit
76543210
P DPL S E DC RW A
  • P(bit位): 
      Present bit. Allows an entry to refer to a valid segment. Must be set (1) for any valid segment.
  • DPL(bit位): 描述特权等级字段
       包含  CPU Privilege level 的 segment. 0 = 最高权限(kernel), 3 = 最低权限 (用户程序).
       0和3是linux采用的特权等级
  • S(bit位): Descriptor type bit.
       If clear (0) the descriptor defines a system segment (eg. a Task State Segment). If set (1) it defines a code or data segment.
  • E(bit位): 
     Executable bit. If clear (0) the descriptor defines a data segment. If set (1) it defines a code segment which can be executed from.
  • DC(bit位): 
       Direction bit/Conforming bit.
    • For data selectors: Direction bit. If clear (0) the segment grows up. If set (1) the segment grows down, ie. the Offset has to be greater than the Limit.
    • For code selectors: Conforming bit.
      • If clear (0) code in this segment can only be executed from the ring set in DPL.
      • If set (1) code in this segment can be executed from an equal or lower privilege level. For example, code in ring 3 can far-jump to conforming code in a ring 2 segment. The DPL field represent the highest privilege level that is allowed to execute the segment. For example, code in ring 0 cannot far-jump to a conforming code segment where DPL is 2, while code in ring 2 and 3 can. Note that the privilege level remains the same, ie. a far-jump from ring 3 to a segment with a DPL of 2 remains in ring 3 after the jump.
  • RW(bit位): Readable bit/Writable bit.
    • For code segments: Readable bit. If clear (0), read access for this segment is not allowed. If set (1) read access is allowed. Write access is never allowed for code segments.
    • For data segments: Writeable bit. If clear (0), write access for this segment is not allowed. If set (1) write access is allowed. Read access is always allowed for data segments.
  • A(bit位): 
       Accessed bit. Best left clear (0), the CPU will set it when the segment is accessed.
Flags
3210
G DB L Reserved
  • G(bit位): Granularity flag, indicates the size the Limit value is scaled by. If clear (0), the Limit is in 1 Byte blocks (byte granularity). If set (1), the Limit is in 4 KiB blocks (page granularity).
  • DB(bit位): Size flag. If clear (0), the descriptor defines a 16-bit protected mode segment. If set (1) it defines a 32-bit protected mode segment. A GDT can have both 16-bit and 32-bit selectors at once.
  • L: Long-mode code flag. If set (1), the descriptor defines a 64-bit code segment. When set, DB should always be clear. For any other type of segment (other code types or any data segment), it should be clear (0).

 

 

 

https://en.wikipedia.org/wiki/Protection_ring
https://www.baeldung.com/cs/os-rings
 Linux 和 Windows 仅使用 ring 0 和 ring 3,但其他一些操作系统可以使用三个不同的保护级别。
posted @ 2023-04-07 21:24  jinzi  阅读(176)  评论(0编辑  收藏  举报