不可执行 mfd 简介¶
- 作者:
Daniel Verkamp <dverkamp@chromium.org> Jeff Xu <jeffxu@chromium.org>
- 贡献者:
Aleksa Sarai <cyphar@cyphar.com>
自从 Linux 引入 memfd 功能以来,memfd 始终设置了其执行位,并且 memfd_create() 系统调用不允许以不同的方式设置它。
然而,在默认安全的系统中,例如 ChromeOS(其中所有可执行文件都应来自受验证启动保护的 rootfs),memfd 的这种可执行性质为 NoExec 绕过打开了一扇门,并启用了“confused deputy attack”(混淆代理攻击)。 例如,在 VRP 漏洞 [1] 中:cros_vm 进程创建了一个 memfd 以与外部进程共享内容,但是 memfd 被覆盖并用于执行任意代码和 root 提权。[2] 列出了更多此类 VRP。
另一方面,可执行 memfd 有其合法的用途:runc 使用 memfd 的 seal 和可执行功能来复制二进制文件的内容,然后执行它们。 对于这样的系统,我们需要一种解决方案来区分 runc 对可执行 memfd 的使用和攻击者的使用 [3]。
- 为了解决以上问题
允许 memfd_create() 在创建时设置 X 位。
当 NX 被设置时,允许 memfd 被密封以修改 X 位。
添加一个新的 pid 命名空间 sysctl:vm.memfd_noexec,以帮助应用程序迁移和强制执行不可执行的 MFD。
用户 API¶
int memfd_create(const char *name, unsigned int flags)
MFD_NOEXEC_SEAL
当
flags
中设置了 MFD_NOEXEC_SEAL 位时,memfd 使用 NX 创建。 设置 F_SEAL_EXEC,并且 memfd 无法被修改以稍后添加 X。 MFD_ALLOW_SEALING 也被暗示。 这是应用程序使用 memfd 的最常见情况。MFD_EXEC
当
flags
中设置了 MFD_EXEC 位时,memfd 使用 X 创建。- 注意
MFD_NOEXEC_SEAL
意味着MFD_ALLOW_SEALING
。 如果应用程序不希望密封,则可以在创建后添加 F_SEAL_SEAL。
Sysctl:¶
pid 命名空间 sysctl vm.memfd_noexec
新的 pid 命名空间 sysctl vm.memfd_noexec 有 3 个值
- 0:MEMFD_NOEXEC_SCOPE_EXEC
没有 MFD_EXEC 或 MFD_NOEXEC_SEAL 的 memfd_create() 行为就像设置了 MFD_EXEC 一样。
- 1:MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL
没有 MFD_EXEC 或 MFD_NOEXEC_SEAL 的 memfd_create() 行为就像设置了 MFD_NOEXEC_SEAL 一样。
- 2:MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED
没有 MFD_NOEXEC_SEAL 的 memfd_create() 将被拒绝。
该 sysctl 允许对未设置可执行位的旧软件进行更精细的 memfd_create 控制; 例如,vm.memfd_noexec=1 的容器意味着旧软件将默认创建不可执行的 memfd,而新软件可以通过设置 MFD_EXEC 来创建可执行的 memfd。
vm.memfd_noexec 的值在创建时传递给子命名空间。 此外,该设置是分层的,即在 memfd_create 期间,我们将从当前 ns 搜索到 root ns,并使用最严格的设置。
[2] https://bugs.chromium.org/p/chromium/issues/list?q=type%3Dbug-security%20memfd%20escalation&can=1