gpt4 book ai didi

operating-system - 在操作系统的上下文中,Ring 0 和 Ring 3 是什么?

转载 作者:行者123 更新时间:2023-12-03 07:54:59 34 4
gpt4 key购买 nike

我一直在学习有关 Windows 驱动程序开发的基础知识,我一直在寻找术语 Ring 0 和 Ring 3。这些是指什么?它们与内核模式和用户模式相同吗?

最佳答案

Linux x86 环使用概述
了解环在 Linux 中的使用方式将使您对它们的设计目的有一个很好的了解。
在 x86 保护模式下,CPU 始终处于 4 个环之一。 Linux内核只使用0和3:

  • 0 内核
  • 3 用户

  • 这是内核与用户空间的最严格和快速的定义。
    为什么 Linux 不使用环 1 和 2: CPU Privilege Rings: Why rings 1 and 2 aren't used?
    当前环是如何确定的?
    当前环由以下组合选择:
  • 全局描述符表:GDT 条目的内存表,每个条目都有一个字段 Privl 对环进行编码。
    LGDT 指令将地址设置为当前描述符表。
    另见:http://wiki.osdev.org/Global_Descriptor_Table
  • 段寄存器 CS、DS 等,它们指向 GDT 中条目的索引。
    例如,CS = 0 表示 GDT 的第一个条目当前对于正在执行的代码是事件的。

  • 每个环能做什么?
    CPU 芯片的物理构造使得:
  • ring 0 可以做任何事情
  • ring 3 不能运行多条指令和写入多个寄存器,最值得注意的是:
  • 不能换自己的戒指!否则,它可以将自己设置为环 0,而环将毫无用处。
    换句话说,不能修改当前的 segment descriptor ,它决定了当前的环。
  • 不能修改页表:How does x86 paging work?
    换句话说,不能修改 CR3 寄存器,分页本身阻止了页表的修改。
    出于安全/易于编程的原因,这可以防止一个进程看到其他进程的内存。
  • 无法注册中断处理程序。这些是通过写入内存位置来配置的,这也可以通过分页来防止。
    处理程序在环 0 中运行,并且会破坏安全模型。
    换句话说,不能使用 LGDT 和 LIDT 指令。
  • 不能做 inout 等IO指令,因此具有任意的硬件访问权限。
    否则,例如,如果任何程序可以直接从磁盘读取,文件权限将毫无用处。
    更准确地说,多亏了 Michael Petch :操作系统实际上可以允许环 3 上的 IO 指令,这实际上是由 Task state segment 控制的。
    如果环 3 首先没有它,那么它不可能允许自己这样做。
    Linux 总是不允许它。另见:Why doesn't Linux use the hardware context switch via the TSS?


  • 程序和操作系统如何在环之间转换?
  • 当 CPU 打开时,它开始在环 0 中运行初始程序(很好,但它是一个很好的近似值)。您可以将这个初始程序视为内核(但它通常是 a bootloader that then calls the kernel still in ring 0 )。
  • 当用户进程希望内核为它做一些事情,比如写入文件时,它使用一条指令来生成一个中断,例如 int 0x80 or syscall 来向内核发出信号。 x86-64 Linux 系统调用 hello world 示例:
  • .data
    hello_world:
    .ascii "hello world\n"
    hello_world_len = . - hello_world
    .text
    .global _start
    _start:
    /* write */
    mov $1, %rax
    mov $1, %rdi
    mov $hello_world, %rsi
    mov $hello_world_len, %rdx
    syscall

    /* exit */
    mov $60, %rax
    mov $0, %rdi
    syscall
    编译并运行:
    as -o hello_world.o hello_world.S
    ld -o hello_world.out hello_world.o
    ./hello_world.out
    GitHub upstream
    发生这种情况时,CPU 调用内核在启动时注册的中断回调处理程序。这是一个 concrete baremetal example that registers a handler and uses it
    这个处理程序在 ring 0 中运行,它决定内核是否允许这个 Action ,执行这个 Action ,并在 ring 3 中重新启动用户态程序。 x86_64
  • 当系统调用 exec 时(或内核 will start /init 时),内核 prepares the registers and memory 切换到新用户态进程的入口点,然后ring3
  • 如果程序试图做一些顽皮的事情,比如写入禁止的寄存器或内存地址(因为分页),CPU 也会在环 0 中调用一些内核回调处理程序。
    但是由于用户空间是顽皮的,内核这次可能会杀死进程,或者给它一个信号警告。
  • 当内核启动时,它会设置一个固定频率的硬件时钟,周期性地产生中断。
    该硬件时钟生成运行 ring 0 的中断,并允许它安排唤醒哪些用户级进程。
    这样,即使进程没有进行任何系统调用,也可以进行调度。

  • 有多个环有什么意义?
    分离内核和用户空间有两个主要优点:
  • 编写程序更容易,因为您更确定一个程序不会干扰另一个程序。例如,一个用户级进程不必担心由于分页而覆盖另一个程序的内存,也不必担心将硬件置于另一个进程的无效状态。
  • 更安全。例如。文件权限和内存分离可以防止黑客应用读取您的银行数据。当然,这假设您信任内核。

  • 怎么玩?
    我创建了一个裸机设置,它应该是直接操作环的好方法: https://github.com/cirosantilli/x86-bare-metal-examples
    不幸的是,我没有耐心制作用户空间示例,但我确实进行了分页设置,因此用户空间应该是可行的。我很想看到一个拉取请求。
    或者,Linux 内核模块在 ring 0 中运行,因此您可以使用它们来尝试特权操作,例如读取控制寄存器: How to access the control registers cr0,cr2,cr3 from a program? Getting segmentation fault
    这是一个 convenient QEMU + Buildroot setup 可以在不杀死主机的情况下进行尝试。
    内核模块的缺点是其他 kthread 正在运行,可能会干扰您的实验。但理论上你可以用你的内核模块接管所有中断处理程序并拥有系统,这实际上是一个有趣的项目。
    负环
    虽然 Intel 手册中实际上并未引用负环,但实际上有 CPU 模式比环 0 本身具有更多功能,因此非常适合“负环”名称。
    一个例子是虚拟化中使用的管理程序模式。
    有关更多详细信息,请参阅:
  • https://security.stackexchange.com/questions/129098/what-is-protection-ring-1
  • https://security.stackexchange.com/questions/216527/ring-3-exploits-and-existence-of-other-rings

  • ARM
    在 ARM 中,环被称为异常级别,但主要思想保持不变。
    ARMv8 中存在 4 个异常级别,通常用作:
  • EL0:用户空间
  • EL1:内核(ARM 术语中的“主管”)。
    使用 svc 指令(SuperVisor Call)输入,以前称为 swi before unified assembly ,这是用于进行 Linux 系统调用的指令。 Hello world ARMv8 示例:
    你好
    .text
    .global _start
    _start:
    /* write */
    mov x0, 1
    ldr x1, =msg
    ldr x2, =len
    mov x8, 64
    svc 0

    /* exit */
    mov x0, 0
    mov x8, 93
    svc 0
    msg:
    .ascii "hello syscall v8\n"
    len = . - msg
    GitHub upstream
    在 Ubuntu 16.04 上使用 QEMU 进行测试:
    sudo apt-get install qemu-user gcc-arm-linux-gnueabihf
    arm-linux-gnueabihf-as -o hello.o hello.S
    arm-linux-gnueabihf-ld -o hello hello.o
    qemu-arm hello
    这是一个具体的裸机示例 registers an SVC handler and does an SVC call
  • EL2: hypervisors ,例如 Xen
    使用 hvc 指令(HyperVisor 调用)输入。
    管理程序之于操作系统,就像操作系统之于用户空间。
    例如,Xen 允许您在同一系统上同时运行多个操作系统,例如 Linux 或 Windows,并且为了安全和易于调试,它将操作系统彼此隔离,就像 Linux 对用户程序所做的那样。
    管理程序是当今云基础架构的关键部分:它们允许多个服务器在单个硬件上运行,使硬件使用率始终接近 100% 并节省大量资金。
    例如,AWS 使用 Xen 直到 2017 年 its move to KVM made the news
  • EL3:又一个层次。待办事项示例。
    使用 smc 指令输入(安全模式调用)

  • ARMv8 Architecture Reference Model DDI 0487C.a - 第 D1 章 - AArch64 系统级程序员模型 - 图 D1-1 很好地说明了这一点:
    enter image description here
    随着 ARMv8.1 Virtualization Host Extensions (VHE) 的出现,ARM 的情况发生了一些变化。这个扩展允许内核在 EL2 中高效运行:
    enter image description here
    VHE 的创建是因为 KVM 等 Linux 内核虚拟化解决方案已经超越 Xen(参见上文提到的 AWS 向 KVM 的迁移),因为大多数客户端只需要 Linux VM,并且您可以想象,所有这些都在一个在项目中,KVM 比 Xen 更简单,而且可能更高效。所以现在主机 Linux 内核在这些情况下充当管理程序。
    从图中我们可以看到,当 bit E2H of register HCR_EL2 等于 1 时,则启用了 VHE,并且:
  • Linux 内核运行在 EL2 而不是 EL1
  • HCR_EL2.TGE == 1 时,我们是一个普通的主机用户程序。使用 sudo 可以像往常一样破坏主机。
  • HCR_EL2.TGE == 0 我们是 guest 操作系统时(例如,当你 run an Ubuntu OS inside QEMU KVM inside the host Ubuntu 。做 sudo 不能破坏主机的错误,除非有/41231412314123141413232314123231432123223123231431223123231412223181812222101818121223123231224181812122221812122241222181812213341142

    请注意,ARM 可能是事后诸葛亮,在特权级别的命名约定比 x86 更好,而无需负级别:0 是较低的,3 是最高的。较高级别往往比较低级别更频繁地创建。
    当前EL可以用MRS指令查询:what is the current execution mode/exception level, etc?
    ARM 不要求存在所有异常级别以允许不需要该功能以节省芯片面积的实现。 ARMv8“异常级别”说:

    An implementation might not include all of the Exception levels. All implementations must include EL0 and EL1.EL2 and EL3 are optional.


    例如 QEMU 默认为 EL1,但可以使用命令行选项启用 EL2 和 EL3:qemu-system-aarch64 entering el1 when emulating a53 power up
    在 Ubuntu 18.10 上测试的代码片段。

  • 关于operating-system - 在操作系统的上下文中,Ring 0 和 Ring 3 是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18717016/

    34 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com