仅用于站内搜索,没有排版格式,具体信息请跳转上方微信公众号内链接
你正在编写一个普通的应用程序,突发奇想,想要直接控制硬盘读写、修改其他程序的内存空间,甚至直接关闭整个计算机系统。如果你尝试这样做,结果会怎样?
答案很简单,在现代操作系统上,你的程序不但不能接管计算机反而会被反杀掉。
有一系列操作是绝对不允许在用户态执行的。
内存是计算机系统最基础的资源,必须由操作系统统一管理。内核通过CPU提供的虚拟内存技术为每个进程创建独立的虚拟地址空间,实现进程间的内存隔离,这其中最核心的就是页表。
如果用户程序能够随意修改页表,将导致灾难性后果,因为这意味着:
进程可能访问其他进程的私有内存,造成数据泄露或损坏
进程可能修改内核内存,破坏系统核心数据结构
内存保护机制失效,导致系统不稳定或完全崩溃
例如,如果一个程序能够修改CR3寄存器,它就可以切换到任意进程的地址空间,读取或修改其他程序的数据,这将完全破坏系统的安全边界。
有些指令可以直接控制CPU的核心行为,包括但不限于:
开关中断指令(CLI/STI)
修改控制寄存器(CR0、CR2、CR4等)
执行I/O指令(IN/OUT)
如果我们写的程序直接关闭中断(CLI),那么这将导致系统无法响应外部事件,包括定时器中断,从而阻止操作系统重新获得控制权,这意味着我们写的while循环将会真正的独占一个CPU核心。
如果我们写的程序可以修改控制寄存器,那么就可以直接禁用内存保护或更改CPU的基本运行模式。
有些操作可以直接控制硬件的读写,这包括:
使用IN/OUT指令直接读写I/O端口
访问内存映射I/O(MMIO)区域
硬件设备是系统共享资源,需要协调访问以避免冲突,不正确的硬件操作可能导致设备故障或数据损坏,多个程序同时访问同一设备会导致操作冲突和数据损坏,而不正确的设备命令序列可能导致硬件故障。
例如,如果用户程序可以直接访问硬盘控制器,它可以绕过文件系统和权限检查,读取或修改任何磁盘扇区,包括其他用户的私有文件或系统关键数据。
内核维护着大量复杂而关键的数据结构,这些数据结构共同构成了系统运行的大脑,对系统的正常运行至关重要。因此对这些数据结构的访问和修改必须严格限制在内核态下进行。
(PS,这是人能看懂的东西?)
在Linux等现代操作系统中,内核数据结构包括进程控制块(在Linux中称为task_struct)、文件描述符表、中断向量表、页表等。如果允许普通用户程序随意访问和修改这些数据结构,将会带来灾难性的后果。
以进程控制块为例,它存储了进程的所有关键信息,包括进程ID、用户ID、权限位图、资源限制和调度参数等。如果一个恶意程序能够修改自己的进程控制块,它可以轻松地将自己的有效用户ID改为0(即root或管理员),立即获得系统的最高权限,从而绕过所有安全检查,访问任何文件,执行任何操作。
因为我们可以看到,实际上CPU执行的指令可以分为两类,一类就是以上列举的操作(操作系统的职责范畴),再一类就是我们写的程序(被编译后生成的指令),CPU在执行这两类指令时需要具有不同的权限等级。
现代CPU(如x86架构)通常实现了多个特权级别,从Ring0(最高权限)到Ring3(最低权限)。虽然有四个级别,但大多数操作系统只使用其中的两个:
Ring0(内核态):操作系统内核运行的特权级别
Ring3(用户态):普通应用程序运行的特权级别
只有当CPU位于Ring0也就是内核态时才可以执行我们刚才列举的这些操作,否则会触发异常,这会进一步触发操作系统的运行,操作系统运行起来后会终止掉有问题的进程。
因此如果我们的代码想要执行上述操作的话就只能让操作系统替代我们去执行,这通过系统调用来实现。
CPU的这种特权级别隔离机制是计算机系统安全稳定运行的基石设计之一,这是现代计算机能够同时运行数十甚至数百个程序而保持稳定的关键所在。
我是小风哥,畅销书《计算机底层的秘密》作者,推荐一下我写的专栏《深入理解操作系统》,第二版焕新升级,600+精美手绘图、87节体系课、配套专属讨论群(一群人可以走的更远),如果操作系统对你来说始终是一个黑盒,那么这个专栏就是为你准备的: