LWN:地址空间隔离的两个patch!(重发)

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

Two address-space-isolation patches get closer

By Jonathan Corbet
October 27, 2020
DeepL assisted translation
https://lwn.net/Articles/835342/

地址空间隔离(address-space isolation)是指从一个或多个地址空间中移除一段内存区域的技术,以此来防止对该内存的意外访问或恶意访问。自从 Meltdown 和 Spectre 漏洞披露以来,内核已经使用了地址空间隔离的一种措施,使用户空间进程完全无法访问内核内存,这就是一个地址空间隔离的例子。人们对在其他情况下使用类似的技术来保护内存,一直很有兴趣。又有两个实现了新的隔离机制的 patch 正在试图合入 mainline 内核中。

memfd_secret()

第一个是 Mike Rapoport 的 memfd_secret()补丁集,之前已经介绍过了(https://lwn.net/Articles/812325/),所以我们这里仅仅再简单介绍一下,详细背景资料请看那篇文章。这项工作的目的是允许用户空间进程创建一个 "秘密 "的内存区域,这个区域尽可能除了此进程之外都无法访问。预期的使用场景包括用在加密函数库中,可以使用秘密区域来保存加密密钥,并保证它们不被窥探。

在最新版本的 patch 中,这个功能已经被移到了一个单独的系统调用中。

int memfd_secret(unsigned long flags);

函数的返回值是文件描述符,可供传递给 mmap()来 map 实际的内存区域。大多数情况下,这个内存看起来(对 map 的进程来说)就像其他内存区域一样,不过还是会有一些区别:

  • 这个范围内的内存 page 将会从内核的 direct map 中移除掉,因为 direct map 会允许内核访问(几乎)系统中任何物理页的部分。这样改动之后,内核更难访问到这些内存了,无论是普通访问还是通过漏洞访问都不可以了。

  • 如果 flags 包含 SECRETMEM_UNCACHED,那么只要底层架构支持,这部分内存将被映射为 uncached。uncached 内存访问速度会慢得多,但它也不会受那些预测执行的漏洞的影响。

秘密区域的内存被 lock 在 RAM 中,无法被 swap。因此,这会被算入此进程的 locked-memory limit 限制之内。

这样的功能一直存在一个问题:从内核的 direct map 中移除 page,这是一个会带来很大性能损失的动作。direct map 使用 huge page,因此使用了尽量少的系统 TLB。从 direct map 中移除这里那里的 page,会破坏这些 huge page,显著增加要使用的 TLB 数量。为了将这种影响降到最低,memfd_secret()patchset 维护了另一个独立的物理连续页面的缓存。

最近这个 patch set 的改动已经不多了,所以它可能已经接近于可以被合入。不过,在实际打上这个 patch 之前,人们很难确定 memory-management patch 是否真的会被合入。

KVM 保护内存

虽然内存泄露漏洞在任何系统上都是坏事,但在运行虚拟化 guest OS 的系统上问题更大。这类机器可能运行着来自完全不相关的人员的 workload,而这些 workload 通常来说是不愿意互相分享秘密信息的。因此,由于很可能与攻击者控制的 guest OS 共享物理系统,使得内存保护成为了一个更加紧迫的问题。作为加固这些系统的一种方式,CPU 厂商一直在增加内存加密机制,使 guest memory 无法被内核以及其他 guest 访问。不过这些功能都会带来一些额外开销,而且目前支持这些功能的硬件还远未普及。

但是, Kirill Shutemov 从这些技术中得出了一个有趣的结论:使用了这些技术的系统仍然可以正常工作,这意味着大多数时候其实内核或 hypervisor 并不需要访问这些内存。所以他整理了一套 patch set,完全采用了软件方法来实现。运行这套代码的系统并不需要对 guest memory 进行加密,而只是简单地将其 unmap 掉。这个功能需要内核和 guest 两边都要支持。

具体来说就是增加了一个 KVM hypercall,允许 guest 请求他们的内存不可被其他人访问到。host kernel 会相应处理,也就是从 direct map 中删除分配给 guest 的这些内存,从而无法访问该内存。用户空间中的方法有点不同:任何属于 guest 的内存仍然保持 mapped 状态,但被标记为 PROT_NONE 这种保护模式,从而使得无法访问了。这将影响像 QEMU 模拟器这样的程序,它会无法直接访问 guest memory。不进行 mapping 的话,自然也会阻止来自其他 guest 的攻击。在 guest 内部,guest kernel 照常控制着内存权限(memory permission)。

这种隔离方式保护了 guest memory,使其不至于因为内核或 QEMU 等组件的漏洞而被意外访问到。但这并不是一种完全的保护。如果 host kernel 被入侵,可以执行任意代码的话,它就可以随意重映射这些 page 并偷取到其中内容。不过对于绝大多数让内核访问野指针指针的漏洞或者 speculative-execution 漏洞来说,这种 unmapping 动作就可以给攻击者增加很大的麻烦。

当然,有些时候,内核必须访问 guest 内部的内存才能执行正常的内核功能。我们为 guest 添加了第二个 hypercall,用来表明它们需要向 host kernel 开放哪些内存。这些范围将被映射到 host kernel 的地址空间内。虚拟化设备的 DMA buffer 就是一个例子,guest 会希望以这种方式与 host kernel 共享内存。

这项工作看起来很有价值,但还是有一些问题需要先解决,才能合入。与 memfd_secret()不同的是,这项工作没有提供避免 page 被移除产生的 direct map 碎片问题的解决方案,因为在这种情况下涉及的内存空间相当大,碎片问题可能会更严重。unmap 的 guest memory 无法被迁移(migration),这就破坏了内核的内存 defragment 机制。这很可能会随着运行的时间变长,而造成各种问题。Shutemov 也承认,需要先解决这个问题再合并 patch。目前如果一个 guest 系统启用了这种内存保护方式的话,也就不可以被 reboot 了。Shutemov 建议这种情况可以直接判定为 "不支持",不过这个想法已经在讨论中引起了抱怨。

这些问题意味着 KVM proected memory 这个功能不会在不久的将来内出现在主线内核中。不过这两个 patch set 很可能都给我们指明了今后发展的一个方向。尽可能的共享内存,这会提高性能,但越来越明显看出与之相关的安全问题很难解决。所以,尽可能地分离地址空间,这看起来是一个相对简单的方法,可以避开许多这类问题。

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值