LWN:对文件对应内存内容添加保护页!

关注了就能看到更多这么棒的文章哦~

Guard pages for file-backed memory

By Jonathan Corbet
March 3, 2025
Gemini-1.5-flash translation
https://lwn.net/Articles/1011366/

6.13 内核版本中包含的诸多新特性之一是 guard pages(保护页),这是一种强化机制,能够以高效的方式将 zero-access pages(零访问页)注入到进程的地址空间中。然而,该特性仅支持 anonymous pages(匿名页)(用户空间数据)。为了使保护页更广泛地应用,Lorenzo Stoakes 整理了一个 补丁集,以支持 file-backed pages(文件支持页)的该特性;在此过程中,他检查并解决了扩展该特性可能遇到的一长串潜在问题。但是,有一个潜在的问题并未在他的列表中。

保护页的目的是防止有缺陷的(或恶意的)代码 overrun(超出)内存区域。如果运行中的进程试图读取或写入它,放置在区域末尾的 inaccessible page(不可访问页)将导致 segmentation fault(段错误);放置正确的保护页可以捕获许多常见的 buffer overrun(缓冲区溢出)和类似的问题。然而,在 6.13 之前,将保护页放入进程地址空间的唯一方法是使用 mprotect() 设置一个或多个页面的保护;这确实有效,但代价是创建一个新的 virtual memory area(VMA,虚拟内存区域)来包含受影响的页面。放置大量的保护页将创建大量的 VMA,这会减慢许多内存管理功能的速度。

新的保护页特性通过在 page-table(页表)级别工作而不是创建新的 VMA 来解决这个问题。进程可以通过调用 madvise() 来创建保护页,请求 MADV_GUARD_INSTALL 操作。指定的内存范围将被呈现为不可访问;在该操作之前可能存储在那里的任何数据都将被删除。还有一个操作( MADV_GUARD_REMOVE )可以删除保护页。

将保护页放置在包含 anonymous pages(匿名页)的 VMA 中是最简单的情况,这就是为什么首先支持 anonymous pages(匿名页)。这些页面与磁盘上的任何文件没有连接,因此更改它们的行为所涉及的风险相对较小。File-backed pages(文件支持页)带来了更多的复杂性,也多了一些保护页可能导致问题的地方。Stoakes 在补丁发布中详细介绍了这些问题。

例如,readahead(预读)是在进程顺序处理文件时保持性能的重要组成部分。当该进程从文件中读取一些数据时,内核可以猜测该进程将在不久的将来继续请求文件中的后续数据。通过在用户空间请求数据之前启动读取操作,内核可以确保在请求到达时该数据已经存在(或至少正在传输中)。保护页的存在将使得预读在此处完全停止,因为该页面已被标记为不可访问。正如 Stoakes 指出的那样,这不应该是一个问题,因为进程映射文件、放置保护页,之后尝试读取该页面的做法是不寻常的。

在其他情况下也会出现类似的复杂情况。内核通常会尝试 "fault around(围绕页面进行缺页处理)" 已被 fault in(缺页调入)的页面,假设附近的数据会是接下来需要使用的;保护页也会阻止这种情况。如果文件被 truncate(截断),则删除的部分可能包含保护页,但保护页本身将保留在原位。诸如此类;在每种情况下,Stoakes 都确保内核的操作将是正确的并且有意义。

但是,仍然存在一些例外情况,其中一个是在发布补丁之前已知的,而另一个是意外的。已知的问题是,保护页不能放置在使用 mlock() 锁定到 RAM 中的内存区域中。正如 Vlastimil Babka 指出的那样,问题在于 mlock() 保证受影响的页面不会从 RAM 中被踢出。但是,安装保护页会释放存储在那里的任何数据,这与 mlock() 的承诺背道而驰。Stoakes 正在 考虑 一种新的操作,该操作将使数据销毁在这种情况下变得明确,但是,正如 David Hildenbrand 说,“ mlock is weird(mlock 很奇怪)”,并且还有许多其他细节需要管理。

Kalesh Singh 提出了意外的问题,他想知道保护页的存在将如何在 /proc/=/ =PID=/=/maps 和 /proc/=/ =PID=/=/smaps 中表示。这些文件在 Documentation/filesystems.proc.html 中有详细记录,它们详细描述了进程的 VMA。Singh 说:

在实践中,我发现许多应用程序从 proc/self[s]maps 读取范围,以确定它们可以访问的内容(通常与混淆技术有关)。如果他们不知道保护区域,这将导致他们崩溃;我认为我们需要为这些区域提供类似于 PROT_NONE (—p) 的条目,并且通常保持行为与 proc/*[s]maps 中所说的内容之间的一致性。

似乎 Android 上运行的银行应用程序以这种行为而闻名,如果安装了保护页,可能会遇到麻烦——Android 运行时很可能希望这样做作为一般的强化措施。由于这些应用程序已经读取了指示的 /proc 文件,Singh 认为这将是指示保护页存在的合乎逻辑的地方。

这个请求 让 Stoakes 感到惊讶,因为他认为该主题之前已经讨论过,并且情况已得到理解。这种情况是,由于这些文件描述的是 VMA,因此它们不适合放置有关保护页的信息,因为根据设计,保护页没有自己的 VMA。Hildenbrand 迅速 建议, /proc/=/ =PID=/=/pagemap 中的一个 bit,它现在提供页面级数据,将是向用户空间导出该信息的最佳方式。尽管如此,谈话变得有些紧张,似乎主要是由于误解而不是真正的分歧。

但最终,人们一致认为 pagemap 是放置此信息的正确位置。Suren Baghdasaryan 最终 加入了对话,说需要做一些工作才能使 Android 系统中的应用程序可以使用此信息,但他将开始该项目。大家互相道歉和感谢,Stoakes 表示,他将继续实施 pagemap 解决方案的内核端。

由于该问题似乎已得到解决,因此该特性在不久的将来进入 mainline(主线)(mainline) 似乎没有任何严重的障碍。该补丁系列(减去 pagemap 更改)现在位于 linux-next 中,并且最早可以在 6.15 merge window(合并窗口)合并到 upstream(上游)。这应该会带来更轻松、更便宜的用户空间强化,这似乎是值得的。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值