memfd_secret():它应该如何工作?

ave*_*rdo 3 c linux memory linux-kernel

memfd_secret()已合并到内核中,但我没有看到它真正的安全优势。我的意思是,这有避免旁路攻击的想法,但这就像车钥匙被锁了而没有人知道它们在哪里一样。

AFAIK,在内核模式下,提供给应用程序的页面根本没有被映射,但这不能用于隔离病毒或内核本身的任何内容。

隔离内核的一段内存范围应该如何更安全?

有人可以提供一个代码示例来说明如何保护幽灵或类似的东西吗?

更新

int main(int argc, char *argv[]) {
    while(true) {
        int rc = fork();
        if(rc == -1) {
            perror("fork error");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Luc*_*ito 8

memfd_secret()允许用户空间进程拥有“秘密”内存区域。在这种情况下,“秘密”意味着其他进程无法访问该内存区域(甚至内核本身也不能访问,或者至少不是偶然的)。

此系统调用允许进程以更安全的方式存储机密信息(例如密码或私钥),因为恶意软件更难访问该秘密内存区域。这个系统调用还应该防止像 Spectre 这样的漏洞,因为秘密内存区域是未缓存的;并且还应该保护(虽然不完全,但至少部分)免受内核错误的影响,因为内核无法访问该内存区域。

为了使用这个系统调用(在 Linux 5.14 中可用),您首先要调用memfd_secret()来获取文件描述符;然后调用 来ftruncate()选择秘密内存区域的大小;最后你用它mmap()来映射秘密内存,这样你就可以像平常一样通过指针访问它。

其他详细信息请参见此处

memfd_secret()编辑:不幸的是,由于担心性能问题,“未缓存”功能已被删除,该功能不易受到 Spectre 等攻击。

编辑2:关于为什么获得的秘密内存区域memfd_secret()使程序更安全的其他细节(源代码,为了清晰起见,我稍微修改了):

  • 针对ROP 攻击的增强保护(与所有其他内核内攻击预防系统结合)。秘密内存使得“简单”的 ROP 不足以执行渗透,这增加了攻击所需的复杂性。除了内核堆栈大小限制和地址空间布局随机化等其他保护措施(这些保护措施使得查找小工具非常困难)之外,缺乏任何用于访问秘密内存的内核原语意味着单小工具 ROP 攻击无法发挥作用。由于访问秘密内存的唯一方法是重建丢失的映射条目,因此攻击者必须恢复物理页并在内核中插入指向它的 PTE,然后检索内容。这至少需要三个小工具,这超出了大多数标准攻击的难度。

  • 防止跨进程秘密用户空间内存暴露。一旦分配了秘密内存,用户就不会意外地将其传递到内核中以传输到某个地方。秘密内存页面无法通过直接映射访问,并且在 GUP 中是不允许的。

  • 针对被利用的内核缺陷进行强化。为了访问秘密内存,内核端攻击需要遍历页表并创建新页表,或者生成新的特权用户空间进程以使用 ptrace 执行秘密泄露。

编辑3:只是我认为可能相关的一条注释:秘密内存区域可以由使用创建的子进程访问fork(),因此必须谨慎。至少,使用标志O_CLOEXEC(传递给memfd_secret()),进程不会使秘密内存可供使用 创建的进程使用execve()

  • 我不确定你是否回答了这个问题。他不想知道如何使用它,而是内核如何创建一个它自己无法访问的内存区域?memfd 驱动不是在内核中吗? (4认同)
  • @Barmar OP 说“有人可以提供一个代码示例吗?”,我认为他们的意思是如何在 C 程序中使用。`memfd` 已经存在于内核中,但尚不支持秘密内存区域(这些只能通过 `memfd_secret()` 系统调用获得,该系统调用将在 Linux 5.14 中实现)。 (2认同)
  • @avelardo 嗯,虽然我个人对这个选择并不满意,但从这些秘密区域窃取内存信息的可能性应该非常低,即使没有未缓存的功能。 (2认同)
  • @avelardo 我添加了秘密内存增强程序安全性的其他原因。 (2认同)