关注了就能看到更多这么棒的文章哦~
Memory sealing for the GNU C Library
By Jonathan Corbet
June 12, 2024
Gemini-1.5-flash translation
https://lwn.net/Articles/978010/
mseal()
系统调用 允许进程阻止其地址空间未来进行任何更改(因此被称为“密封 sealing”);它借鉴了 OpenBSD 中的 mimmutable()
系统调用。 mseal()
产生了大量的讨论,但最终被合并到即将发布的 6.10 内核中。虽然 mseal()
最初旨在保护 Chrome 浏览器,但人们希望它在其他地方也能发挥作用;作为实现这一希望的一步,Adhemerval Zanella 发布了一个 补丁系列,为 GNU C 库 (glibc) 添加了对 mseal()
的支持以及使用方法。
这个新的系统调用旨在通过使攻击者更难对进程的地址空间进行更改来提高安全性。如果一个内存区域已经被密封,它就不能被取消映射(unmap)、重新映射(remap)或更改对其进行的保护;一些 madvise()
操作也被禁止。密封是一个单向操作;一旦内存被密封,它在进程的生命周期内就不能被解封。
该系列补丁的第一个步骤是使 mseal()
可供 glibc 用户使用。该接口几乎与内核提供的接口完全相同:
int mseal(void /address, size_t length, unsigned long flags);
address
和 length
参数描述了要密封的内存范围; flags
值目前未使用,必须为零。
然而,Zanella 并没有止步于添加系统调用包装器。C 库,包括动态加载器,在很大程度上负责组装进程的地址空间;它能够很好地知道地址空间的哪些部分不应该更改,因此可以被密封。Zanella 的补丁集利用了这些信息,可以选择性地密封地址空间的各个部分,包括:
进程正在运行的二进制代码,当然是在它完成 set up 之后。这种密封适用于静态和动态二进制文件。所有作为依赖项加载的共享库也将被密封,包括只读段。(有人可能想到一些主意,不过这种密封发生在 RELRO 设置完成之后,因此它不足以阻止 XZ 后门)。
任何预加载的库。
内核的 vDSO 区域。
使用
dlopen()
且带有RTLD_NODELETE
标记(防止在dlclose()
调用时卸载库)加载的任何动态库。任何 审计模块 及其依赖项。
虽然大多数程序应该在启用此密封的情况下正常运行(并且更安全),但肯定会有例外,这些例外会在其地址空间中进行复杂的应对。因此,自然地,在 glibc 可调参数列表 中添加了一个新的可调参数,名为 gtld.rtld.seal
,会用于控制密封行为。将此参数设置为零将禁用库自动执行的任何密封操作(虽然 mseal()
将仍能继续工作)。默认值(1)导致密封发生,但任何无法密封地址空间部分的尝试都会被忽略。对于安全性要求更高的程序,将此参数设置为 2 将导致进程在任何密封尝试失败时被终止。
这项工作还在早期作; mseal()
尚未被包含在已发布的内核中,而这也是 Zanella 补丁集的第一个版本。即使没有其他问题,在 6.10 发布之前,它也不太可能应用到 glibc 仓库;在此期间,它可能会经历一些更改。但它的基本形式似乎不太可能发生重大变化,因此很有可能使用 glibc 的系统最终将默认情况下拥有更好的地址空间保护。预计 6.10 将于 7 月中旬发布,这意味着将其包含在计划中的 glibc 2.40 发布(8 月初)的时间不太够了,因此 mseal()
更可能出现在 2.41 中。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~