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