LWN:让memfd支持 non-executable!

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

Enabling non-executable memfds

By Jonathan Corbet
December 19, 2022
DeepL assisted translation
https://lwn.net/Articles/918106/

memfd 接口是一个有点奇怪的功能,也是 Linux 特有的;最初是为了支持单个系统上多个合作进程之间的数据安全传递而开发出来了。此后,它又有了其他一些用途,但是当一些人知道了给 memfds 创建的内存区域实际上跟(几乎)所有其他的数据区域(memory region)不同,是设置了可执行权限 bit 的时候,可能仍然会感到惊讶。这为恶意攻击提供了便利;Jeff Xu 的这组 patch set 提出了对 memfd API 的补充,以弥补这个漏洞。

memfd 是通过调用 memfd_create()创建出来的,它返回的是一个指向该区域的文件描述符。这个描述符可以被当作一个普通的文件,因为可以用来做读写访问;它也可以被映射到一个进程的地址空间去。通常情况下,第一步是调用 ftruncate()来设置这个区域的 size;之后,可以被填充上数据,并传递给另一个进程。memfd 的一个有趣特点是,它们可以通过调用 fcntl()来 "sealed(密封起来)",这个 seal 操作之后,就不允许对存储的数据做任何进一步的改动了。seal 可以让接收者确信 memfd 的内容不会在操作过程中发生意外的变化。

在这个过程中,作为 memfd 的基础的虚拟文件在创建时就设置了可执行权限 bit;这就允许内存本身被映射为可执行状态的。这样就出现了内核和用户空间的开发者都越来越多地希望去避免的一种权限组合:write 和 execute 权限都被 enable 了。一个既可写又可执行的内存区域给了攻击者一个相对容易的方法来将自己的代码注入到目标进程中。事实上,Xu 在 patch 的 cover letter 中指出,memfd 区域已经被用于攻击 ChromeOS 系统。

人们可能会认为可以无条件地删除底层 memfd 文件的执行权限来应对。但这样以来,这就是对 ABI 的修改了,而且至少已经有了一个已知的(合法)需要可执行权限的 memfd 使用场景。runc 容器运行时(container runtime)就使用带有可执行权限的 memfd 来加载它要运行的容器的映像文件;该功能是为了应对 2019 年的另一个漏洞而添加的。因此,拥有可执行的 memfd 的能力必须保留。

不过,可执行的 memfd 不一定必须是默认行为,进程肯定可以选择创建不可执行的 memfd。 因此,Xu 的 patch set 就基于这个方向,通过为 memfd_create()添加了两个新 flag 来修改了 memfd API。

  • MFD_EXEC 会明确要求 memfd_create()创建一个有可执行权限的 memfd。这只是加强了当前的默认值,但默认值可以按照下面的描述来改变。

  • MFD_NOEXEC_SEAL 则相反,会创建一个没有可执行权限的 memfd,并应用一个 seal,防止这个设置被改变。因此,用这个 flag 创建的 memfd 将永远不会被执行,不管用户空间的攻击者如何努力。

新增了一个 fcntl()操作,F_SEAL_EXEC,对执行权限进行了 seal 封印,防止它在之后被改变。和所有的 seal 封印操作一样,这种改动无法在之后撤销。

这些 patch 还增加了一个新的 sysctl 开关,叫做 vm.memfd_noexec,是当前 PID namespace 特有的 local 开关;它控制着当受影响的进程在没有指定两个新 flag 的情况下创建一个 memfd 时,内核会怎么做。把这个开关设置为 0,会让 memfd_create()的行为表现为 MFD_EXEC 被设置了一样,这是当前缺省行为。把它设置为 1,则会导致 MFD_NOEXEC_SEAL 被设置,基本上就是默认关闭可执行权限。值为 2 会让任何没有明确提供 MFD_NOEXEC_SEAL 的 memfd_create()调用都失败,就完全禁用了可执行的 memfd。当然,默认值必须是 0,以避免破坏任何现有的应用程序。

如果在创建 memfd 时这两个 flag 都没有设置,那么新的代码会向 kernel log 报出 warning,希望能更新应用程序。Peter Xu 观察到,这可能会使系统日志中充斥着许多 warning 信息。经过讨论,大家同意每次启动只发出一次 warning。因此,可能需要启动好几次系统才能发现这个系统上所有需要 fix 的应用程序,但这被认为比无限制的打印 log 要好。

最后,Paul Moore 对为 memfd_create()增加的一个 security-module hook 的做法提出了质疑,因为没有对 security module 进行相应的修改来实际使用这个 hook。因此,这个 hook 有可能会被拿掉,等到有人想针对这个系统调用写一个 policy 的时候再提出来。除此之外,看起来这个系列 patch 应该已经没有什么合并阻碍了。

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

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

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

format,png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值