1. 项目概述在虚拟化技术已成为云计算和嵌入式系统基石的今天内存隔离是保障整个系统安全的生命线。想象一下你在一台物理服务器上运行着多个租户的虚拟机或者在一辆智能汽车的域控制器内同时运行着信息娱乐系统和关键的刹车控制单元。这些环境的核心安全假设是一个虚拟机VM无法访问另一个虚拟机或宿主机Hypervisor的内存。为了实现这一隔离硬件厂商提供了输入输出内存管理单元IOMMU。它的角色类似于CPU的MMU但专门为总线上的DMA设备服务。当一个虚拟机通过I/O透传Passthrough方式直接控制一个网卡或存储控制器时IOMMU会确保这个设备发起的DMA请求只能访问到该虚拟机被授权的物理内存页从而构建了一道坚固的硬件防线。然而安全研究就像一场永无止境的攻防博弈。我们通常认为只要IOMMU配置正确DMA攻击的威胁就被解除了。但最近的研究揭示了一个被忽视的角落动态虚拟化环境。在这种环境下虚拟机及其资源包括DMA设备可以在运行时被动态创建和销毁。当一台不怀好意的虚拟机被销毁它曾经控制的DMA设备被重新分配给宿主机或另一个虚拟机时会发生什么如果这台设备内部还“记得”前一个虚拟机下达的、但尚未执行的DMA指令会发生什么这正是“延迟DMA攻击”瞄准的窗口期。这项攻击的核心洞察非常巧妙它不直接对抗IOMMU的访问检查而是利用时间差。攻击者在一个恶意虚拟机内操控一个DMA能力设备例如SD卡控制器精心编排一个DMA操作序列并人为地、或利用设备特性引入一个显著的延迟使得关键的恶意DMA访问操作恰好发生在设备被IOMMU重新映射到“新主人”例如宿主机的内存空间之后。这样一来设备执行的DMA操作虽然是由已销毁的恶意虚拟机发起的但其访问的目标却是宿主机或其他虚拟机的内存从而成功绕过了IOMMU基于源虚拟机上下文建立的访问控制。这就像你给一个快递机器人DMA设备下达了“去A仓库恶意VM内存取件但两小时后再出发”的指令然后在它出发前你恶意VM消失了仓库管理系统Hypervisor把机器人重新分配给了B公司宿主机。两小时后机器人出发但它去的却是B公司的仓库宿主机内存而指令来源却是早已不存在的你。本文旨在深入拆解这项由Jean de Bonfils Lavernelle等研究者提出的新型攻击。我们将从IOMMU的基础防护原理讲起逐步深入到攻击的威胁模型、核心机制并以他们在Jailhouse hypervisor上利用SD主机控制器SDHC实现的概念验证PoC为蓝本详细解析攻击的实施步骤、关键代码逻辑以及实测数据。最后我们会探讨该攻击的适用范围、局限性以及从系统设计者到开发者层面可以采取的防御思路。无论你是虚拟化平台的安全架构师、嵌入式系统开发者还是对底层系统安全感兴趣的研究者理解这种“时间维度”上的攻击对于构建真正健壮的隔离方案都至关重要。2. IOMMU防护原理与动态虚拟化的安全挑战2.1 IOMMUDMA访问的守门人要理解攻击为何能生效首先必须清楚IOMMU是如何工作的以及它的防护边界在哪里。DMA允许像网卡、GPU、存储控制器这类外设在不经过CPU参与的情况下直接与系统内存交换数据。这极大地提升了I/O性能但也带来了安全风险一个被恶意虚拟机控制的DMA设备理论上可以读写任何物理内存地址从而破坏虚拟机间的隔离。IOMMU的引入就是为了解决这个问题。它的核心功能是地址转换和访问控制。地址转换Address Translation类似于CPU MMU将虚拟地址VA转换为物理地址PAIOMMU将设备发起的DMA请求中的设备地址通常是总线地址如I/O虚拟地址IOVA或客户物理地址GPA转换为最终的物理地址PA。每个设备或一组设备会被分配一个唯一的标识符如PCIe的Requester ID ARM SMMU中的Stream ID。访问控制Access ControlIOMMU为每个设备标识符维护一套独立的页表或称为上下文。这套页表不仅定义了地址转换规则还包含了每个内存页的访问权限读、写。当设备发起DMA请求时IOMMU会查找该设备标识符对应的页表进行地址转换并检查权限。如果请求的地址不在页表映射范围内或权限不足例如尝试写入一个只读页IOMMU会触发一个错误Page Fault或Fault并通常终止此次DMA事务。在虚拟化环境中Hypervisor负责为每个虚拟机创建和维护其专属的IOMMU页表。当将一个DMA设备通过I/O透传给某个虚拟机时Hypervisor会将该设备的标识符与该虚拟机的IOMMU页表上下文绑定。从此该设备发起的任何DMA访问都会被IOMMU限制在该虚拟机被允许访问的内存区域内。这被称为操作系统间Inter-OS保护是虚拟化隔离的基石。2.2 动态虚拟化与设备重映射的“灰色地带”传统的静态分区Hypervisor如某些嵌入式RTOS Hypervisor在启动时就将CPU、内存、I/O设备固定分配给各个虚拟机运行时不再改变。这种模式简单但缺乏灵活性。而动态Hypervisor如Xen, KVM以及本文涉及的Jailhouse的特定模式允许在运行时创建、销毁虚拟机并动态地分配和回收资源包括DMA设备。这就引入了一个关键的生命周期管理问题设备重映射Device Remapping。当一个拥有DMA设备的虚拟机被销毁时Hypervisor需要回收该设备并将其重新分配给其他实体通常是宿主机自身或另一个新创建的虚拟机。这个过程通常涉及停止虚拟机。解除该设备标识符与原虚拟机IOMMU上下文的绑定。清理设备状态理想情况下应重置设备。将该设备标识符绑定到新实体如宿主机的IOMMU上下文。将设备控制权移交给新实体。攻击就潜伏在第2步到第4步之间以及第3步是否被严格执行。如果Hypervisor在解除绑定后、重新绑定前没有确保设备内部所有由前一个虚拟机发起的DMA操作都已彻底完成或失效那么设备可能仍然“记得”旧指令。更危险的是如果设备支持复杂的、可延迟执行的DMA命令链而Hypervisor在重映射过程中没有**重置Reset**设备那么这些“滞留”的命令可能会在新的IOMMU上下文下被执行。2.3 攻击成立的核心假设与威胁模型延迟DMA攻击的成功建立在以下几个关键假设之上这也构成了其威胁模型存在不信任的驱动攻击者控制了一个虚拟机并且该虚拟机拥有一个DMA-capable设备的直接访问权I/O透传及其驱动程序。这个驱动程序是恶意的可以任意编程设备。设备支持延迟操作目标DMA设备允许驱动程序下发一个DMA操作命令但该操作的实际执行即对内存的读/写可以在命令下发后的某个时间点才发生。这个延迟可以是设备固有的如等待外部事件也可以是驱动程序通过复杂描述符链人为构造的。设备会被动态重映射Hypervisor支持在运行时将DMA设备从一个虚拟机动态地重新映射到另一个实体如宿主机。并且在重映射过程中设备不会被执行硬重置或确保其内部所有待处理操作被清空。攻击者无法精确控制销毁时机攻击者通常无法精确知道或控制自己的虚拟机何时被销毁例如由宿主机管理员或监控系统触发。因此攻击策略必须是“守株待兔”式的持续准备攻击一旦检测到或等待自己被销毁就让滞后的攻击生效。这个威胁模型在嵌入式虚拟化场景中尤为现实。在这些场景中为了满足实时性和性能要求I/O透传非常普遍同时为了灵活管理资源动态创建/销毁虚拟机也是常见需求。Jailhouse hypervisor就是一个典型例子它通常被视为静态分区但其“根细胞root cell”即宿主机可以动态回收和分配设备从而满足了上述攻击条件。注意许多云服务器环境使用VFIO框架为虚拟机分配PCIe设备并在虚拟机销毁时通常会触发设备Function Level Reset (FLR)。这种重置机制能有效防御此类攻击。然而在嵌入式SoC中许多内存映射MMIO设备缺乏标准化的硬重置机制这为攻击留下了可乘之机。3. 攻击机制深度解析以SD主机控制器为例研究者选择SD主机控制器SDHC作为攻击载体极具代表性。SDHC是嵌入式系统中极其常见的DMA设备用于读写SD卡或eMMC存储。其DMA引擎称为ADMA2的工作机制恰好为构造延迟攻击提供了所需的“原材料”。3.1 SDHC ADMA2引擎与描述符表SDHC通过一种叫做“描述符表”Descriptor Table的机制来编程DMA操作。这个表本质上是一个存储在系统内存RAM中的指令链表每个描述符占8字节64位。描述符主要有两种类型链接描述符Linked Descriptor不执行DMA数据传输只包含一个指向下一个描述符表地址的指针。用于构建复杂的描述符链。缓冲区描述符Buffer Descriptor包含一个目标数据缓冲区的内存地址和长度指示SDHC执行一次DMA传输从卡到内存或从内存到卡。驱动程序在内存中构建好这个描述符表将表的基地址写入SDHC的特定控制寄存器然后发送一个读或写命令如CMD18/CMD25。SDHC的DMA引擎便会开始遍历并执行描述符表中的指令。关键特性在于描述符的获取和执行本身也是通过DMA操作完成的。SDHC需要不断地从内存中读取描述符表的内容。这意味着描述符表所在的内存区域也必须被映射到该SDHC所属虚拟机的IOMMU页表中否则SDHC在获取描述符时就会触发IOMMU错误。3.2 构造延迟利用描述符表与存储卡的“乒乓”操作直接构建一个很长的描述符链表来引入延迟是低效的因为这会占用大量连续的虚拟机内存且延迟长度受限于可用内存。研究者设计了一种更精巧的方法利用SD卡MMC本身的存储空间来“放大”延迟。其核心思想是让SDHC不断地用SD卡上的数据覆写描述符表的第一个条目形成一个循环。攻击准备阶段在SD卡上预埋数据攻击者在SD卡的连续扇区中写入大量例如数GB的“数据”。这些数据的绝大部分内容都是重复的、无害的“链接描述符”但在序列的末尾放置一个恶意的缓冲区描述符。这个恶意描述符指向攻击者想要读写的宿主机或其他虚拟机的内存地址。在内存中构建初始描述符表在恶意虚拟机内存中分配一个小型的描述符表。这个表的第一个条目是一个缓冲区描述符其作用是命令SDHC从SD卡的起始地址MMC_ADDR读取8字节数据并写入到描述符表自身的第一个条目所在的内存地址DESC_TABLE。简言之就是“用SD卡上的第一个描述符覆盖我自己”。表的后续条目全部是链接描述符它们形成一个环让SDHC在执行完最后一个描述符后跳回表头重新开始。攻击执行流程恶意虚拟机驱动程序启动SDHC命令。SDHC读取第一个描述符缓冲区描述符执行它从SD卡地址MMC_ADDR读取8字节即预埋的第一个描述符将其写入DESC_TABLE。覆盖完成后MMC_ADDR自动增加8字节。SDHC继续读取后续的链接描述符在环中循环最终又回到第一个描述符位置。此时第一个描述符已经被覆盖成了SD卡上预埋的描述符实际上和原来一样。SDHC再次执行它从MMC_ADDR8读取下一个8字节预埋的第二个描述符再次覆盖第一个条目。MMC_ADDR再次增加。如此循环往复。SDHC就像一台“读卡器”不断地用SD卡上预埋的描述符序列覆写内存中描述符表的第一个“槽位”。这个循环过程本身不进行恶意DMA访问只是不断地进行“自我覆写”从而消耗时间。当循环进行到SD卡上预埋的恶意缓冲区描述符时该描述符会被读入并覆盖内存中的第一个槽位。在下一个循环中SDHC读取并执行这个已被替换为恶意描述符的第一个条目。此时该描述符指令SDHC进行DMA传输目标地址是宿主机内存的某个区域。如果此时设备已经被重新映射到宿主机的IOMMU上下文那么这次DMA访问将顺利通过从而完成对宿主机内存的篡改或窃取。3.3 攻击的“看门狗”机制与时机把握由于攻击者不知道虚拟机何时被销毁他需要一种机制来防止恶意DMA操作在重映射发生前执行那会触发IOMMU错误导致攻击失败。SDHC的描述符支持“中断描述符”INT flag。攻击者可以在描述符表中定期插入中断描述符。当SDHC处理到该描述符时会向CPU发起一个中断。在虚拟机内部驱动程序可以捕获这个中断。这个中断就像一个“心跳”或“定时器”告诉驱动程序“SDHC已经循环了N圈快要执行到恶意描述符了”。驱动程序的中断处理例程可以做一件事重置并重启SDHC的命令。只要虚拟机还在运行驱动程序就不断地在恶意操作即将发生前“踩刹车”重置设备然后重新启动整个循环过程。这就像一个看门狗Watchdog只要主人虚拟机还活着就会定期喂狗防止它咬人执行恶意DMA。一旦Hypervisor决定销毁该虚拟机驱动程序的看门狗例程自然也随之停止。SDHC不会再被重置循环会继续进行直到执行到那个滞后的恶意描述符。而此时设备极有可能已经被重新映射到了宿主机攻击便成功了。实操心得这种“看门狗”机制是此类异步攻击的精髓。它不依赖于精确计时而是依赖于事件中断驱动。在编写恶意驱动时中断处理函数的效率至关重要必须确保能在下一个“心跳”到来前完成重置操作否则攻击会提前触发。在实际测试中需要仔细调整描述符表中中断描述符的间隔平衡延迟长度和中断处理负担。4. 在Jailhouse Hypervisor上的概念验证实现4.1 实验环境搭建研究团队在Xilinx Zynq UltraScale MPSoC (ZCU104)开发板上实现了攻击验证。该平台配备了符合ARM SMMUv2规范的IOMMU。攻击目标是一个运行Jailhouse hypervisor的系统。软件栈Jailhouse v0.12。Jailhouse启动后Linux系统作为特权虚拟机称为“根细胞”或root cell运行。从该根细胞可以创建和销毁其他“非特权细胞”即普通虚拟机。攻击者VM创建一个非特权细胞并将SDHC设备通过I/O透传直接分配给它。该细胞运行一个修改过的、包含攻击代码的Linux内核驱动。调试工具使用Lauterbach硬件调试器连接JTAG接口。这是关键因为它允许研究者实时监控CPU、SMMU状态、内存访问以及SDHC控制寄存器的变化精确观察攻击每一步的执行情况。4.2 攻击步骤分解准备阶段在恶意虚拟机内加载恶意SDHC驱动模块。驱动分配一块内存作为描述符表DESC_TABLE。根据DESC_TABLE的地址计算并生成一系列描述符数据将其写入SD卡的连续扇区。序列的末尾是恶意缓冲区描述符其目标地址设置为宿主内核的某个已知函数指针或数据区域例如系统调用表入口。驱动在内存中构建初始描述符表第一个条目是用于“自我覆写”的缓冲区描述符后续是形成环路的链接描述符并在环路中插入中断描述符。驱动将描述符表基地址和SD卡起始地址写入SDHC控制寄存器并发送一个读命令例如CMD18。此时SDHC开始工作进入“读卡-覆写-循环”的状态。等待与监控阶段恶意虚拟机内的驱动中断处理程序持续工作监控SDHC的进度。每当收到中断意味着即将到达恶意操作点就重置SDHC并重新启动命令让循环从头开始。攻击者或实验人员从根细胞执行命令jailhouse cell destroy 恶意细胞ID。攻击触发阶段Jailhouse开始销毁恶意细胞。关键步骤在于其SMMU驱动代码见论文附录B它将SDHC的Stream IDSID直接从被销毁细胞的IOMMU上下文直接切换到根细胞的上下文。在这个过程中SDHC对描述符表所在内存区域的访问没有被阻断。恶意细胞的进程被杀死其看门狗中断处理程序停止运行。SDHC继续其循环。由于不再被重置它最终会从SD卡中读出恶意描述符并将其覆盖到内存描述符表的第一个位置。在下一个循环SDHC执行该恶意描述符发起DMA写操作目标地址是根细胞的内存空间。由于此时SDHC的SID已属于根细胞上下文IOMMU允许此次访问。宿主机的内存被成功篡改。在PoC中研究者通过写入一个特定的“魔数”payload到宿主机的某个空闲内存区域然后通过调试器读取该区域验证了攻击成功。在实际攻击中这可以用于覆盖函数指针、修改内核代码实现提权或系统崩溃。4.3 延迟能力与资源消耗实测攻击的可行性很大程度上取决于能引入多长的延迟。延迟必须长于虚拟机销毁和设备重映射所需的时间窗口。研究者推导出了延迟公式总延迟 (ms) 0.02607 * (描述符表大小_KB) * (128 * SD卡上描述符数据大小_KB)其中0.02607 ms/KB是SDHC在该平台获取描述符的速率。关键在于延迟与SD卡上预埋的数据量成线性关系。实测数据示例内存中描述符表大小4 MBSD卡上预埋数据大小32 KB计算延迟0.02607 * 4 * (128 * 32) ≈ 427秒超过7分钟这意味着仅用32KB的SD卡空间对应4096个描述符就能制造超过7分钟的延迟。而一张普通的SD卡有数GB容量理论上可以制造数天甚至数周的延迟这为攻击提供了巨大的时间窗口。注意事项虽然可以制造极长延迟但攻击驱动无法依赖虚拟机的系统时钟来精确判断何时该“踩刹车”。因为Hypervisor可能会控制虚拟时钟如ARM的CNTVOFF_EL2导致虚拟机内的时间感知不准确。因此依赖设备中断如SDHC的中断描述符作为同步信号是更可靠的方法。5. 攻击的适用性、局限性与缓解措施5.1 攻击的普适性分析这种延迟DMA攻击并非对所有虚拟化系统和设备都有效。其成功取决于一个黄金链条在设备重映射的整个时间窗口内设备必须能持续访问到其执行攻击所需的关键状态对于SDHC就是描述符表所在的内存。对Jailhouse有效的原因Jailhouse在销毁细胞时直接将设备的SID切换到根细胞上下文没有中间状态阻止设备访问原内存。描述符表所在的内存在两个上下文中可能都有映射或切换瞬间访问未被阻止。对Xen无效的原因研究者在Xen上测试发现当使用xen,passthrough属性将设备分配给一个VM后该设备从一开始就不在Dom0宿主的IOMMU上下文中。当VM销毁时Xen会将设备置于一种“未映射”状态使其无法访问任何内存导致SDHC无法继续获取描述符攻击链中断。对VFIO/KVM的挑战在Linux VFIO框架下当释放一个设备时通常会尝试对设备进行重置如PCIe FLR。一个彻底的硬件重置会清除设备内部所有状态包括进行中的DMA操作从而从根本上杜绝此类攻击。这是VFIO相比许多嵌入式Hypervisor更安全的一点。5.2 关键制约因素设备内部状态存储位置攻击的可行性高度依赖于DMA设备如何存储其“工作指令”如描述符依赖外部内存如SDHC描述符表存储在系统RAM中。在重映射过程中如果Hypervisor切断了设备对原VM内存的访问即使是很短的时间设备就会因取指失败而停止攻击失败。这是主要的限制。依赖设备内部内存一些更复杂的DMA控制器如NXP的SDMA有自己的内部RAM和可编程内核。它们的“脚本”或描述符可以加载到内部RAM中运行。在这种情况下即使设备与系统RAM的链接被暂时切断其内部状态依然保持攻击更容易成功。这类设备是更理想的攻击载体。5.3 可行的缓解策略从系统设计者和Hypervisor开发者的角度可以采取以下措施来防御此类攻击强制设备重置最有效在将DMA设备从一个虚拟机回收并重新分配给其他实体之前必须对设备执行一次完整的、硬件级别的重置。这能确保设备内部所有由前一个驱动留下的状态包括未完成的DMA命令都被清除。对于PCIe设备应使用Function Level Reset (FLR)。对于嵌入式SoC上的内存映射设备需要芯片厂商提供或驱动实现明确的重置例程如操作特定的复位控制寄存器。安全的上下文切换流程在IOMMU上下切换时不应采用简单的“直接切换”模式。可以引入一个短暂的“故障上下文”或“空上下文”作为中间态。即先将设备的SID绑定到一个所有访问都会触发IOMMU错误的上下文等待一个安全时间窗口确保所有未完成DMA操作超时或失败再绑定到新的目标上下文。这能确保任何滞后的DMA访问都会被拦截。内存访问隔离在设备重映射期间Hypervisor可以主动取消映射设备原虚拟机内存的所有相关页面。对于像SDHC这样需要持续访问描述符表的设备这会导致其DMA引擎立刻停止工作。但这种方法需要Hypervisor精确知道设备正在使用哪些内存页实现起来较复杂。驱动与设备增强设备驱动可以在释放设备前主动停止并清空设备的所有DMA队列。IOMMU驱动也可以在解除映射前向设备发送“停止”或“刷新”命令。但这依赖于设备的配合和驱动的良好行为不能作为唯一的安全假设。给开发者的建议在设计和评审使用I/O透传的虚拟化系统安全时必须将“设备重置”作为安全生命周期管理的强制要求。在缺乏硬件重置机制的平台上需要与硬件团队合作定义并实现一个软件可触发的重置序列。安全评审清单上必须包含这一问题“当从一个不信任的实体回收DMA设备时我们如何确保设备内部没有遗留任何可能危害新实体的状态”6. 总结与延伸思考延迟DMA攻击揭示了一个在动态虚拟化安全评估中常被忽略的维度时间。它提醒我们安全不仅仅是空间的隔离内存页的划分也是时间的隔离操作生命周期的严格管理。IOMMU提供了强大的空间隔离但如果设备状态的“时间线”在所有权转移时发生了错位隔离就会被打破。这项研究的意义在于它从一个非常具体的角度SDHC的设备特性与Jailhouse的重映射实现出发揭示了一类具有普适性的威胁模式。虽然PoC是在特定平台上实现的但其攻击思想可以迁移到其他支持复杂、可编程DMA操作且缺乏重置机制的设备上例如某些网络控制器、GPU或自定义的FPGA加速器。从更广阔的视角看随着异构计算和硬件加速的普及越来越多的专用加速器DPU IPU AI加速器会以DMA方式接入系统。这些设备往往拥有更强的自主性和更复杂的内部状态机。确保它们在多租户、动态调度的环境下的安全生命周期管理将是未来系统安全设计的一大挑战。对于安全从业者来说这项研究提供了一个清晰的测试用例在评估虚拟化平台时除了检查静态的IOMMU配置还应设计动态测试验证在虚拟机热迁移、创建、销毁过程中DMA设备的重置和上下文切换流程是否真正安全。可以尝试构造类似的延迟DMA负载看看系统是否会崩溃或被侵入。最后我认为防御此类攻击最根本的哲学是“无状态移交”。当一个设备被回收时它应该被还原到一个干净的、确定性的初始状态就像交还一把钥匙前必须清空里面所有的个人物品和设置。任何依赖于前一个使用者状态的“记忆”都可能成为攻击的跳板。在追求极致性能的嵌入式虚拟化领域如何在“快速回收重用”和“彻底安全重置”之间找到平衡将是架构师们需要持续面对的课题。