当CPU处于用户态时,CPU不能执行特权指令,也不能访问内核空间内存。
而当CPU处于内核态时,CPU可以执行所有指令,可以访问所有内存。
现在在 Linux 中,用户模式程序可以访问所有内存(使用/dev/mem
)并且可以执行两条特权指令IN
和OUT
(使用iopl()
我认为)。
因此,Linux 中的用户模式程序可以完成内核模式中可以完成的大多数事情(我认为大多数事情)。
不允许用户模式程序拥有所有这些功能是否违背了拥有 CPU 模式的目的?
ilk*_*chu 23
因此,Linux 中的用户模式程序可以完成内核模式中可以完成的大多数事情(我认为大多数事情)。
好吧,并非所有用户模式程序都可以,只有具有适当权限的程序才可以。这是由内核决定的。
/dev/mem
受通常的文件系统访问权限和CAP_SYS_RAWIO
功能保护。iopl()
并且ioperm()
也通过相同的能力受到限制。
/dev/mem
也可以完全编译出内核(CONFIG_DEVMEM
)。
不允许用户模式程序拥有所有这些功能是否违背了拥有 CPU 模式的目的?
也许会。这取决于您希望特权用户空间进程能够做什么。如果用户空间进程有权访问/dev/sda
(或等效),它们也可以破坏整个硬盘驱动器,即使这违背了使用文件系统驱动程序来处理存储访问的目的。
(然后还有一个事实,即iopl()
通过在 i386 上利用 CPU 特权模式来工作,所以不能说它违背了它们的目的。)
Pet*_*des 16
只有modprobe
通过将新代码加载到内核中来“破坏”安全性的方式相同。
由于各种原因,有时在用户空间而不是内核线程中运行半特权代码(如 X 服务器中的图形驱动程序)更有意义。
kill
更容易地做到这一点,除非它锁定了硬件。它对安全性没有多大作用,但具有很大的可靠性和软件架构优势。
将图形驱动程序放入内核可能会减少 X 客户端和 X 服务器之间的上下文切换,就像只有一个用户->内核->用户,而不必将数据放入另一个使用空间进程,但 X 服务器在历史上太大且有缺陷希望它们完全在内核中。
是的,具有这些权限的恶意代码可以根据需要接管内核,/dev/mem
用于修改内核代码。
或者例如在 x86cli
上,在进行iopl
系统调用以将其 IO 特权级别设置为 ring 0后,运行一条指令以禁用该内核上的中断。
但即使是 x86 iopl
“仅”也可以访问一些指令:输入/输出(以及字符串版本输入/输出)和 cli/sti。它不允许您使用rdmsr
或wrmsr
读取或写入“特定于模型的寄存器”(例如IA32_LSTAR
,它为 x86-64syscall
指令设置内核入口点地址),或用于lidt
替换中断描述符表(这将让您完全采用通过现有内核的机器,至少在该内核上。)
你甚至无法读取控制寄存器(CR3一样持有的顶级页目录的物理地址,其作为偏移到攻击过程可能会发现有用/dev/mem
修改自己的页面表作为替代mmap
荷兰国际集团更多/dev/mem
。 )
invd
(在不回写的情况下使所有缓存无效!!(用例= 配置 RAM 之前的早期 BIOS))是另一种有趣的方法,它总是需要完整的 CPL 0(当前特权级别),而不仅仅是 IOPL。Evenwbinvd
是特权,因为它太慢(而且不可中断),并且必须刷新所有内核的所有缓存。(请参阅是否有办法刷新与程序相关的整个 CPU 缓存?和WBINVD 指令用法)
导致跳转到错误地址运行数据作为代码的错误因此无法在用户空间 X 服务器中意外执行任何这些指令。
当前特权级别(在受保护和长模式下)是cs
(代码段选择器)的低 2 位。 mov eax, cs
/and eax, 3
可以在任何模式下读取权限级别。
写权限级别,你做a jmp far
or call far
to set CS:RIP
(但是目标段的GDT/LDT条目可以根据旧的权限级别限制它,这就是为什么用户空间不能这样做来提升自己)。或者您使用int
或syscall
在内核入口点切换到 ring 0。