我认为用户程序可以通过多种方式有意影响 Linux 内核的状态。
- 通过调用系统调用;
- 通过调用映射()写入已经映射到内核的内存;
- 通过加载内核模块插入模块。
我想不出任何其他办法。不考虑硬件中断,因为它们不是由用户程序启动的。我认为两者映射()和插入模块正在使用系统调用,因此用户程序可能必须依赖系统调用来影响内核的状态。我对么?
如果我是正确的,那么假设内核中存在一些漏洞,并且恶意用户程序想要利用它们来攻击内核。鉴于我们的验证总能说出真相,是否可以验证每个系统调用来防御此类攻击?
答案1
碰巧还有另外一个重要的与内核的接口:/proc
和/sys
虚拟文件系统。虽然它们不保存常规文件,但它们的内容是通往内核的直接门户:对它们进行操作就是直接对内核分配的内存进行操作。例如,如果您想删除所有内存缓存,您可以使用...
echo 3 > /proc/sys/vm/drop_caches
...内核会立即做出反应。
现在,程序需要系统调用才能与文件系统交互:、、、open
等等...但是,仍然有一种方法可以跟踪所有这些系统调用:内核提供了一种跟踪机制。更具体地说,系统调用的跟踪由 处理。该虚拟目录包含每个系统调用的两个子目录。例如,通过 open 系统调用,我们有:read
write
/sys/kernel/debug/tracing
/sys/kernel/debug/tracing/events/syscalls
sys_enter_open
sys_exit_open
在这些目录中,您将找到一个名为enable
.如果它包含“1”,则open
正在跟踪关联的事件(进入或退出呼叫)。我通常使用该enter
事件,但您可以选择更适合您需要的事件。
激活系统调用跟踪后,您将在 处找到日志/sys/kernel/debug/tracing/trace
。现在,请记住打开使用系统调用很多。它是程序和文件之间的最终网关,文件可以是 Linux 系统上的任何东西。还要记住...
UNIX 的设计初衷并不是为了阻止用户做愚蠢的事情,因为这也会阻止他们做聪明的事情。 — 道格·格温
虽然您可以监视系统上发生的情况,但内核不会努力阻止用户做愚蠢的事情:这更多是系统管理员工作的一部分。
管理跟踪机制需要 下的权限/sys/kernel/debug/tracing/trace
。您可能需要成为 root 才能激活和操作跟踪。完成后不要忘记禁用跟踪。
答案2
这取决于。 “验证”是什么意思?如果你只是想监视某个进程触发的系统调用,那么这是可能的......通常......但是如果你想深入挖掘,那么你就会遇到麻烦......我还没有听说过任何可以做到这一点的工具。
您可以使用 strace 来查看某个特定进程正在触发哪些系统调用。当然,您必须以 root 身份运行它...但是,您不会总是成功运行 strace,因为它可以保护应用程序不监视其活动 - ptrace 调用会被丢弃。尝试在 chromium 上进行 stracing - 你会看到的;)
如果 strace 还不够,我想您可以分解每个应用程序二进制文件并手动检查它的作用。这应该很有趣:)(或者,当然,您可以获取源代码并将所有这些算法视为人类可读的文本..但是当您可以使用 ASM 时为什么要选择更简单的方法:))
答案3
这是一个很好的初步近似。用户空间和内核之间有很强的界限,并且最多交互必须涉及系统调用。该模型有助于理解为什么strace
作为故障排除工具如此强大。
大量内核漏洞可归咎于缺乏此类验证。只要您了解此类验证的成本极高即可。对于可用于直接硬件访问等的语言来说尤其如此。当使用像 C 这样的原始语言时更是如此,因为语言设计为此类验证提供的帮助比人们想要的要少得多。
一个众所周知的缓解措施是使用微内核。更少的代码允许更多的验证。通过微内核架构,可以显着地更加包含大量设备驱动程序代码。如果您有足够的 IOMMU 和 MMU,也许完全如此。
然而,这种说法并不正确。
如果您使用正确的术语进行搜索,我认为您可以找到许多作为反例的漏洞。错误可能会在尚未映射的内存范围上生成:
“Linux 内核 i386 SMP 页面错误处理程序权限升级”[安全团队]。
一般来说,您需要验证所有特定于体系结构的故障代码。这包括接收系统调用和页面错误的代码。然而,还有其他类型的错误,例如浮点异常(除以零)。
此外,硬件细节也可能会产生漏洞。当您尝试验证代码时,可能不知道具体的硬件详细信息。