内核代码能否以其他内核代码无法撤消的方式将内容设置为只读?
Can kernel code make things read-only in a way that other kernel code can't undo?
我的印象是 Linux 内核保护自身的尝试围绕着不让恶意代码 运行 进入内核空间。特别是,如果要加载恶意内核模块,从安全角度来看,它将是 "game over"。然而,我最近发现 a post 与这种信念相矛盾,并说内核可以通过某种方式保护自身的某些部分免受自身其他部分的影响:
There is plenty of mechanisms to protect you against malicious modules. I write kernel code for fun so I have some experience in the field; it's basically a flag in the pagetable.
What's there to stop any kernel module from changing that flag in the pagetable back? The only protection against malicious modules is keeping them from loading at all. Once one loads, it's game over.
Make the pagetable readonly. Done.
Kernel modules can just make it read-write again, the same way your code made it read-only, then carry on with their changes.
You can actually lock this down so that kernel mode cannot modify the page table until an interrupt occurs. If your IDT is read-only as well there is no way for the module to do anything about it.
这对我来说没有任何意义。我错过了关于内核内存如何工作的重要信息吗?内核空间代码可以限制自己修改页面 table 吗?这真的能防止内核 rootkit 吗?如果是这样,那么为什么 Linux 内核今天不这样做以结束所有内核 rootkit?
如果恶意内核代码以受信任的方式加载(例如加载内核模块而不是利用漏洞)则否:内核代码是内核代码。
英特尔CPU确实有一系列机制来禁用read/write对内核内存的访问:
CR0.WP
如果设置不允许对用户和内核只读页面进行写访问。用于检测内核代码中的错误。
CR4.PKE
如果设置(必须启用 4 级分页,在 64 位模式下是强制的)不允许内核访问(不包括取指)用户页面模式,除非这些页面被标记为正确密钥(标记其 RW 权限)。用于允许内核写入 VSDO 和 KUSER_SHARED_DATA
等结构,但不允许写入其他用户模式结构。密钥权限在 MSR 中,而不是在内存中;密钥本身在页面 table 条目中。
CR4.SMEP
如果设置不允许从用户模式页面获取内核指令。用于防止将内核函数指针重定向到用户模式分配页面的攻击(例如 nelson.c
特权升级漏洞)。
CR4.SMAP
如果设置在 隐式 访问期间或任何类型(隐式或显式)访问期间不允许内核访问用户模式页面(如果 EFLAGS.AC=0
,从而覆盖保护密钥)。用于执行更严格的无用户模式访问策略。
- 当然,分页结构中的
R/W
和 U/S
位控制项目是 read-only/read-write 并分配给用户还是内核。
您可以在 Intel 手册中阅读如何为 管理员模式访问 应用权限:
Data writes to supervisor-mode addresses.
Access rights depend on the value of CR0.WP:
- If CR0.WP = 0, data may be written to any supervisor-mode address.
- If CR0.WP = 1, data may be written to any supervisor-mode address with a translation for which the
R/W flag (bit 1) is 1 in every paging-structure entry controlling the translation; data may not be written
to any supervisor-mode address with a translation for which the R/W flag is 0 in any paging-structure
entry controlling the translation.
因此,即使内核将页面 X
保护为只读,然后将页面结构本身保护为只读,恶意模块也可以简单地清除 CR0.WP
.
它还可以更改 CR3
并使用自己的分页结构。
请注意,英特尔开发了 SGX 来解决内核本身是邪恶的威胁模型。
然而,运行以安全的方式(即没有单点故障)将内核组件放入 enclaves 可能并非易事。
另一种方法是使用 VMX 扩展来虚拟化内核,尽管实现起来绝非易事。
最后,CPU在分段层有四个保护级别,但分页只有两个:主管(CPL = 0)和用户(CPL > 0)。
理论上可以 运行 "Ring 1" 中的内核组件,但是你需要创建一个接口(例如调用门或 syscall
之类的东西)才能访问另一个内核函数。
在用户模式下完全 运行 它更容易(因为您首先不信任该模块)。
我不知道这是什么意思:
You can actually lock this down so that kernel mode cannot modify the page table until an interrupt occurs.
我不记得有任何中断处理机制lock/unlock。
不过我很好奇,如果有人能透露一些信息,欢迎他们。
x86 CPUs 中的安全性(但这可能是普遍的)一直是分层的:先来的人为后来的人设置约束。
在同一层级的非隔离组件之间通常几乎没有保护。
我的印象是 Linux 内核保护自身的尝试围绕着不让恶意代码 运行 进入内核空间。特别是,如果要加载恶意内核模块,从安全角度来看,它将是 "game over"。然而,我最近发现 a post 与这种信念相矛盾,并说内核可以通过某种方式保护自身的某些部分免受自身其他部分的影响:
There is plenty of mechanisms to protect you against malicious modules. I write kernel code for fun so I have some experience in the field; it's basically a flag in the pagetable.
What's there to stop any kernel module from changing that flag in the pagetable back? The only protection against malicious modules is keeping them from loading at all. Once one loads, it's game over.
Make the pagetable readonly. Done.
Kernel modules can just make it read-write again, the same way your code made it read-only, then carry on with their changes.
You can actually lock this down so that kernel mode cannot modify the page table until an interrupt occurs. If your IDT is read-only as well there is no way for the module to do anything about it.
这对我来说没有任何意义。我错过了关于内核内存如何工作的重要信息吗?内核空间代码可以限制自己修改页面 table 吗?这真的能防止内核 rootkit 吗?如果是这样,那么为什么 Linux 内核今天不这样做以结束所有内核 rootkit?
如果恶意内核代码以受信任的方式加载(例如加载内核模块而不是利用漏洞)则否:内核代码是内核代码。
英特尔CPU确实有一系列机制来禁用read/write对内核内存的访问:
CR0.WP
如果设置不允许对用户和内核只读页面进行写访问。用于检测内核代码中的错误。CR4.PKE
如果设置(必须启用 4 级分页,在 64 位模式下是强制的)不允许内核访问(不包括取指)用户页面模式,除非这些页面被标记为正确密钥(标记其 RW 权限)。用于允许内核写入 VSDO 和KUSER_SHARED_DATA
等结构,但不允许写入其他用户模式结构。密钥权限在 MSR 中,而不是在内存中;密钥本身在页面 table 条目中。CR4.SMEP
如果设置不允许从用户模式页面获取内核指令。用于防止将内核函数指针重定向到用户模式分配页面的攻击(例如nelson.c
特权升级漏洞)。CR4.SMAP
如果设置在 隐式 访问期间或任何类型(隐式或显式)访问期间不允许内核访问用户模式页面(如果EFLAGS.AC=0
,从而覆盖保护密钥)。用于执行更严格的无用户模式访问策略。- 当然,分页结构中的
R/W
和U/S
位控制项目是 read-only/read-write 并分配给用户还是内核。
您可以在 Intel 手册中阅读如何为 管理员模式访问 应用权限:
Data writes to supervisor-mode addresses.
Access rights depend on the value of CR0.WP:
- If CR0.WP = 0, data may be written to any supervisor-mode address.
- If CR0.WP = 1, data may be written to any supervisor-mode address with a translation for which the R/W flag (bit 1) is 1 in every paging-structure entry controlling the translation; data may not be written to any supervisor-mode address with a translation for which the R/W flag is 0 in any paging-structure entry controlling the translation.
因此,即使内核将页面 X
保护为只读,然后将页面结构本身保护为只读,恶意模块也可以简单地清除 CR0.WP
.
它还可以更改 CR3
并使用自己的分页结构。
请注意,英特尔开发了 SGX 来解决内核本身是邪恶的威胁模型。
然而,运行以安全的方式(即没有单点故障)将内核组件放入 enclaves 可能并非易事。
另一种方法是使用 VMX 扩展来虚拟化内核,尽管实现起来绝非易事。
最后,CPU在分段层有四个保护级别,但分页只有两个:主管(CPL = 0)和用户(CPL > 0)。
理论上可以 运行 "Ring 1" 中的内核组件,但是你需要创建一个接口(例如调用门或 syscall
之类的东西)才能访问另一个内核函数。
在用户模式下完全 运行 它更容易(因为您首先不信任该模块)。
我不知道这是什么意思:
You can actually lock this down so that kernel mode cannot modify the page table until an interrupt occurs.
我不记得有任何中断处理机制lock/unlock。 不过我很好奇,如果有人能透露一些信息,欢迎他们。
x86 CPUs 中的安全性(但这可能是普遍的)一直是分层的:先来的人为后来的人设置约束。
在同一层级的非隔离组件之间通常几乎没有保护。