Linux v5.2 内核安全特性深度解析

本文详细介绍了Linux内核v5.2版本中的多项安全增强特性,包括页面分配器随机化、栈变量初始化、用户空间访问防护、MDS缓解措施等,旨在提升系统安全性和稳定性。

Linux v5.2 中的安全特性

先前版本:v5.1

Linux内核v5.2于上周发布!以下是我发现的一些有趣的安全相关特性:

页面分配器空闲列表随机化

虽然SLUB和SLAB分配器的空闲列表已经随机化了一段时间,但 overarching 页面分配器本身并未随机化。这意味着任何在kmem_cache/kmalloc()之外进行分配的操作在内存中的位置都是确定性的。这对安全性和某些缓存管理情况都不利。Dan Williams在CONFIG_SHUFFLE_PAGE_ALLOCATOR下实现了这种随机化,为内存布局提供了额外的不确定性,尽管粒度较低,为4MB(参见SHUFFLE_ORDER)。另外请注意,此功能需要在启动时通过page_alloc.shuffle=1启用,除非您有直接映射的内存端缓存(您可以在/sys/module/page_alloc/parameters/shuffle检查状态)。

使用Clang进行栈变量初始化

Alexander Potapenko通过CONFIG_INIT_STACK_ALL添加了对Clang的-ftrivial-auto-var-init=pattern选项的支持,该选项启用栈变量的自动初始化。这比之前的GCC插件提供了更广泛的覆盖范围,因为Clang的实现还涵盖了未通过引用传递的变量。(理论上,内核构建仍应警告这些实例,但即使存在,Clang也会初始化它们。)GCC插件和Clang实现之间的另一个显著区别是,Clang使用重复的0xAA字节模式进行初始化,而不是零。(尽管在某些情况下会发生变化,例如32位指针初始化为0x000000AA。)与GCC插件一样,好处是消除了未初始化栈变量缺陷的整个类别。

PowerPC上的内核用户空间访问防护

与x86上的SMAP和ARM上的PAN类似,Michael Ellerman和Russell Currey在CONFIG_PPC_RADIX_MMU=y(默认情况下)下为Power9及更高版本的PPC CPU添加了支持,禁止在没有显式标记的情况下访问用户空间(KUAP)。这是v4.10中执行防护(KUEP)的延续。现在,如果攻击者试图诱使内核进行任何类型的意外用户空间访问(不仅仅是执行代码),内核将出错。

x86上的微架构数据采样缓解措施

另一组缓存内存侧信道攻击被发现,并被统称为微架构数据采样(MDS)。MDS比其他缓存侧信道更弱(对目标地址的控制较少),但内存内容仍然可能被暴露。与L1TF非常相似,当威胁模型包括在对称多线程(SMT:逻辑核心多于物理核心)下运行不受信任的代码时,唯一的完全缓解措施是禁用超线程(使用“nosmt”启动)。对于MDS家族的所有其他变体,Andi Kleen(和其他人)实现了各种刷新机制以避免缓存泄漏。

非特权userfaultfd sysctl旋钮

FUSE和userfaultfd都为攻击者提供了一种方式,通过在未映射的页面上启动访问来在内存访问过程中停滞内核线程。虽然FUSE通常受到某种访问控制,但userfaultfd却没有。为了避免各种堆整理和堆喷涂技术利用Use-after-Free缺陷,Peter Xu添加了新的“vm.unprivileged_userfaultfd” sysctl旋钮,以禁止非特权访问userfaultfd系统调用。

x86上用于文本poke的临时mm

内核定期执行自修改,例如使用text_poke()(在alternatives、ftrace等期间)。以前,这是通过固定映射(“fixmap”)完成的,其中使用内存高端的特定固定地址来根据需要映射物理页面。然而,这导致了一些时间风险:其他CPU可以写入fixmap,或者在移除时可能存在陈旧的TLB条目,其他CPU可能仍然能够通过写入来更改目标内容。相反,Nadav Amit为内核文本写入创建了一个单独的内存映射,就像内核试图写入用户空间一样。此映射最终保持本地于当前CPU,并且poke地址是随机的,与旧的fixmap不同。

进行中:隐式fall-through移除

Gustavo A. R. Silva几乎完成了标记(和修复)内核中所有隐式fall-through情况的工作。根据Gustavo的拉取请求,看起来v5.3将在全局构建标志中添加-Wimplicit-fallthrough,然后这类错误应该在内核中保持灭绝。

添加了CLONE_PIDFD

Christian Brauner向clone()系统调用添加了新的CLONE_PIDFD标志,这补充了v5.1中的pidfd工作,因此程序现在可以在fork()(实际上是clone())时立即获得进程ID的句柄,而不需要在进程创建后从/proc获取句柄。随着信号和分叉现在启用,下一个主要部分(已经在linux-next中)将是向waitid()系统调用添加P_PIDFD,并且常见的进程管理可以完全使用pidfd完成。

其他事项

Alexander Popov指出了一些我在这篇博客文章中遗漏的更多v5.2特性。我在这里重复它们,并进行了一些小的编辑/澄清。谢谢Alexander!

  • x86-64 IRQ/异常/调试堆栈现在有保护页,以立即并从这些上下文中确定性地检测堆栈溢出。
  • mincore(2)变得更加保守,以避免有关内存缓存状态和类似信息的信息暴露。
  • x86的objtool现在可以验证uaccess辅助函数的调用者,以确保SMAP不会保持禁用状态。
  • powerpc/32现在支持KASAN。
  • powerpc现在在启动时如果发现W+X页面会发出警告。

编辑: 添加了CLONE_PIDFD注释,由Christian Brauner提醒。:) 编辑: 添加了Alexander Popov的注释

目前就这些;如果您认为我应该在这里添加任何内容,请告诉我。我们几乎要到v5.3的-rc1了!

© 2019 – 2022, Kees Cook。本作品根据知识共享署名-相同方式共享4.0许可协议授权。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计