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

jus*_*mer 35 operating-system driver

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

Cir*_*四事件 60

Linux x86环使用概述

了解如何在Linux中使用环将使您很好地了解它们的设计目标.

在x86保护模式下,CPU始终处于4个环之一.Linux内核仅使用0和3:

  • 0为内核
  • 3为用户

这是kernel vs userland最硬,最快的定义.

为什么Linux不使用环1和2:CPU权限环:为什么不使用环1和2?

目前的戒指是如何确定的?

当前环由以下组合选择:

  • 全局描述符表:GDT条目的内存表,每个条目都有一个Privl对该环进行编码的字段.

    LGDT指令将地址设置为当前描述符表.

    另见:http://wiki.osdev.org/Global_Descriptor_Table

  • 段注册CS,DS等,它指向GDT中条目的索引.

    例如,CS = 0表示GDT的第一个条目当前对执行代码有效.

每个戒指可以做什么?

CPU芯片是物理构建的,因此:

  • ring 0可以做任何事情

  • ring 3无法运行多条指令并写入多个寄存器,最值得注意的是:

    • 不能改变自己的戒指!否则,它可以将自己设置为响铃0并且响铃将是无用的.

      换句话说,不能修改当前的段描述符,这决定了当前的环.

    • 无法修改页面表:x86分页如何工作?

      换句话说,不能修改CR3寄存器,并且分页本身会阻止修改页表.

      这可以防止一个进程为了安全性/易于编程的原因而看到其他进程的内存.

    • 无法注册中断处理程序.这些是通过写入存储器位置来配置的,这也可以通过分页来防止.

      处理程序在0环中运行,会破坏安全模型.

      换句话说,不能使用LGDT和LIDT指令.

    • 不能像in和那样做IO指令out,因而有任意硬件访问.

      否则,例如,如果任何程序可以直接从磁盘读取,则文件权限将无用.

      更确切地说,感谢Michael Petch:操作系统实际上可以在环3上允许IO指令,这实际上是由任务状态段控制的.

      不可能的是,如果戒指3首先没有它,则允许自己这样做.

      Linux总是不允许它.另请参阅:为什么Linux不通过TSS使用硬件上下文切换?

程序和操作系统如何在环之间转换?

  • 当CPU打开时,它开始在环0中运行初始程序(很好,但它是一个很好的近似值).你可以认为这个初始程序是内核(但它通常是一个引导程序,然后仍然在内环0中调用内核).

  • 当userland进程希望内核为其执行某些操作(如写入文件)时,它会使用生成中断的指令,例如int 0x80syscall向内核发送信号.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
    
    Run Code Online (Sandbox Code Playgroud)

    编译并运行:

    as -o hello_world.o hello_world.S
    ld -o hello_world.out hello_world.o
    ./hello_world.out
    
    Run Code Online (Sandbox Code Playgroud)

    GitHub上游.

    发生这种情况时,CPU会调用内核回调处理程序,内核在引导时注册该处理程序.这是一个具体的baremetal示例,它注册一个处理程序并使用它.

    此处理程序在ring 0中运行,它决定内核是否允许此操作,执行操作,并在ring 3中重新启动userland程序.x86_64

  • 当使用exec系统调用时(或内核启动时/init),内核准备新用户空进程的寄存器和内存,然后跳转到入口点并将CPU切换到3

  • 如果程序试图做一些顽皮的事情,比如写入禁止的寄存器或内存地址(因为分页),CPU也会调用环0中的一些内核回调处理程序.

    但是由于用户区很淘气,内核可能会杀死这个进程,或者用信号给它一个警告.

  • 当内核启动时,它会设置一个具有固定频率的硬件时钟,从而定期生成中断.

    此硬件时钟生成运行环0的中断,并允许其调度唤醒哪些用户空进程.

    这样,即使进程没有进行任何系统调用,也可能发生调度.

有多个戒指有什么意义?

分离内核和用户区有两个主要优点:

  • 制作节目更容易,因为你更确定一个人不会干扰另一个节目.例如,一个用户域进程不必担心由于分页而覆盖另一个程序的内存,也不必担心将硬件置于无效状态以用于另一个进程.
  • 它更安全.例如,文件权限和内存分离可能会阻止黑客应用程序读取您的银行数据.当然,这假设您信任内核.

怎么玩呢?

我已经创建了一个裸机设置,应该是直接操作环的好方法:https://github.com/cirosantilli/x86-bare-metal-examples

不幸的是,我没有耐心做出用户名的例子,但我确实做了分页设置,所以userland应该是可行的.我很乐意看到拉动请求.

或者,Linux内核模块在ring 0中运行,因此您可以使用它们来尝试特权操作,例如读取控制寄存器:如何从程序中访问控制寄存器cr0,cr2,cr3?获得分段错误

这是一个方便的QEMU + Buildroot设置,可以在不杀死主机的情况下进行试用.

内核模块的缺点是其他kthreads正在运行并可能干扰您的实验.但理论上你可以用内核模块接管所有中断处理程序并拥有系统,这实际上是一个有趣的项目.

负环

虽然英特尔手册中实际上没有引用负环,但实际上CPU模式还具有比环0本身更多的功能,因此非常适合"负环"名称.

一个例子是虚拟化中使用的管理程序模式.

有关详细信息,请参阅:https://security.stackexchange.com/questions/129098/what-is-protection-ring-1

在ARM中,环被称为异常级别,但主要思想保持不变.

ARMv8中存在4个异常级别,通常用作:

  • EL0:userland

  • EL1:内核(ARM术语中的"supervisor").

    输入svc指令(SuperVisor Call),以前称为swi 统一汇编,这是用于进行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
    
    Run Code Online (Sandbox Code Playgroud)

    GitHub上游.

    在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
    
    Run Code Online (Sandbox Code Playgroud)

    这是一个具体的baremetal示例,它注册SVC处理程序并执行SVC调用.

  • EL2:管理程序,例如Xen.

    进入hvc指令(HyperVisor Call).

    管理程序是操作系统,操作系统是用户空间.

    例如,Xen允许您在同一系统上同时运行多个操作系统(如Linux或Windows),并且它将操作系统彼此隔离,以确保安全性和调试的简便性,就像Linux对用户程序一样.

    管理程序是当今云基础架构的关键部分:它们允许多个服务器在单个硬件上运行,使硬件使用率始终接近100%并节省大量资金.

    例如,AWS使用Xen直到2017年才转向KVM发布消息.

  • EL3:又一个级别.TODO的例子.

    进入smc指令(安全模式呼叫)

ARMv8架构参考模型DDI 0487C.a - D1章-的AArch64系统级编程模型-图D1-1说明了这美丽的:

在此输入图像描述

请注意,ARM可能由于后见之明的优势而具有比x86更好的命名约定,而不需要负级别:0表示较低级别,3表示最高级别.较高级别往往比较低级别更频繁地创建.

可以使用以下MRS指令查询当前EL :当前执行模式/异常级别等是什么?

ARM不要求存在所有异常级别,以允许不需要该功能的实现来节省芯片区域.ARMv8"异常级别"说:

实现可能不包括所有异常级别.所有实现必须包括EL0和EL1.EL2和EL3是可选的.

例如,QEMU默认为EL1,但可以使用命令行选项启用EL2和EL3:qemu-system-aarch64在模拟a53上电时输入el1

代码片段在Ubuntu 18.10上测试过.

  • 哇,真是个答案!! (2认同)
  • 答案很详细,学到了! (2认同)

Rav*_*ari 12

英特尔处理器(x86和其他)允许应用程序限制功率.为了限制(保护)IO,内存,端口等关键资源,CPU与操作系统(本例中为Windows)联络,分别提供映射到内核模式和用户模式的权限级别(0最高权限为3).

因此,OS在环0中运行内核代码 - 由CPU提供的最高权限级别(0) - 以及环3中的用户代码.

有关详细信息,请参阅http://duartes.org/gustavo/blog/post/cpu-rings-privilege-and-protection/


归档时间:

查看次数:

36880 次

最近记录:

6 年,5 月 前