NDIS 虚拟机 (VM) 共享内存的安全问题

本主题讨论为虚拟机队列 (VMQ) 接收缓冲区分配虚拟机 (VM) 共享内存所涉及的潜在安全问题。 本主题包含以下各节:

注意 在 Hyper-V 中,子分区也称为 VM。

VM 共享内存的安全问题概述

VM 不是受信任的软件实体。 也就是说,恶意 VM 不得干扰 Hyper-V 父分区中运行的其他 VM 或管理操作系统。 本部分提供背景信息和要求,以确保驱动程序编写者了解 VMQ 安全问题和共享内存的要求。 有关共享内存的详细信息,请参阅编写 VMQ 驱动程序部分中的共享内存资源分配主题。

在虚拟化环境中,VM 可以查看或修改 VM 共享内存。 但是,不允许查看或修改与其他 VM 关联的数据。 VM 也不允许访问管理操作地址空间。

接收的数据包的标头部分必须受到保护。 不允许 VM 影响网络虚拟服务提供商中的 Hyper-V 可扩展交换机的行为, (VSP) 。 因此,VLAN (虚拟 LAN) 筛选必须在网络适配器使用 DMA 将数据传输到 VM 共享内存之前进行。 此外,媒体访问控制 (MAC) 交换机的地址学习不会受到影响。

如果连接到 VM 的 Hyper-V 可扩展交换机端口具有关联的 VLAN 标识符,则主机必须确保目标 MAC 地址和传入帧的 VLAN 标识符与端口的相应属性匹配,然后主机将数据包转发到 VM 的虚拟网络适配器。 如果帧的 VLAN 标识符与端口的 VLAN 标识符不匹配,则会丢弃数据包。 从主机内存中分配虚拟网络适配器的接收缓冲区时,主机可以检查 VLAN 标识符,并在必要时删除帧,然后再使帧的内容对目标 VM 可见。 如果未将帧复制到 VM 的地址空间,则该 VM 无法访问该帧。

但是,当 VMQ 配置为使用共享内存时,网络适配器使用 DMA 将传入帧直接传输到 VM 地址空间。 此传输引入了一个安全问题,即 VM 可以检查接收的帧的内容,而无需等待可扩展交换机应用所需的 VLAN 筛选。

Windows Server 2008 R2 如何解决安全问题

在 Windows Server 2008 R2 中,在 VSP 将 VM 队列配置为使用从 VM 地址空间分配的共享内存之前,它将对队列使用以下筛选测试。

(MAC address == x) && (VLAN identifier == n)

如果网络适配器硬件可以在 DMA 传输到接收缓冲区之前支持此测试,则网络适配器可以删除具有无效 VLAN 标识符的帧,或将它们发送到默认队列,以便可扩展交换机可以将其筛选掉。 如果微型端口驱动程序在请求中成功通过此测试对队列设置筛选器,则可扩展交换机可以为该队列使用 VM 共享内存。 但是,如果网络适配器硬件无法根据目标 MAC 地址和 VLAN 标识符筛选帧,则可扩展交换机将使用该队列的主机共享内存。

可扩展开关检查接收帧的源 MAC 地址,以配置传输帧的路由信息,也就是说,它类似于物理学习交换机。 可以在主机堆栈中安装防火墙筛选器驱动程序;例如,在网络适配器硬件的微型端口驱动程序上方和可扩展交换机驱动程序下方。 防火墙筛选器驱动程序可以在可扩展开关之前访问接收到的帧中的数据。 如果每个帧的整个接收缓冲区是从 VM 地址空间分配的,则恶意 VM 可能会访问由筛选器驱动程序或主机中运行的可扩展交换机检查的帧部分。

若要解决此安全问题,在将 VM 共享内存用于 VM 队列时,网络适配器必须以至少为预期大小(即预先确定的固定值)的字节偏移量拆分数据包。 任何 lookahead 数据(即先于查找大小字节偏移量的数据)都必须使用 DMA 传输到为查找数据分配的共享内存。 应将后查找数据(帧有效负载的其余部分)与 DMA 一起传输到为后查找数据分配的共享内存。

下图显示了当传入数据拆分为 lookahead 和 lookahead 后共享内存缓冲区时,网络数据结构的关系。

说明 VMQ 数据包结构的关系图,其中显示了单独的共享内存缓冲区中的查看头和后查看数据。

VMQ 共享内存的摘要要求如下:

  • 网络适配器可以在大于预期大小的网络标头边界处拆分收到的帧。 但是,当 NDIS 请求时,无一例外地,接收并分配给 VMQ 的所有帧都必须在 NDIS 请求的探头大小边界内或超出该边界进行拆分。

  • 必须使用 DMA 将头数据传输到微型端口驱动程序分配的共享内存。 微型端口驱动程序必须在分配调用中指定内存将用于查找数据。

  • 后查看数据必须与 DMA 一起传输到微型端口驱动程序分配的共享内存。 微型端口驱动程序必须在分配调用中指定内存将用于后查找数据。

  • 微型端口驱动程序不得依赖于 NDIS 将用于完成共享内存分配请求的地址空间。 也就是说,用于查找头数据或后查找数据的共享内存地址空间是特定于实现的。 在许多情况下,NDIS 或可扩展交换机可能满足来自主机内存地址空间的所有请求,包括用于后期查看的请求。

  • 在驱动程序堆栈上指示 VMQ 接收队列中的帧时,必须保留该队列中的帧接收顺序。

  • 网络适配器必须在每个回溯后缓冲区中分配足够的回填内存空间。 此分配允许将预报数据复制到后回填缓冲区的回填部分,并允许将帧传递到连续缓冲区中的 VM。

如果硬件中没有任何机制来满足 VMQ 共享内存的这些要求,则支持接收端散点收集 DMA 的硬件可能通过为每个接收帧分配两个接收缓冲区来实现相同的结果。 在这种情况下,第一个缓冲区的大小限制为请求的先行大小。

如果网络适配器无法通过任何方法满足 VMQ 共享内存的这些要求,VSP 将从主机地址空间为 VMQ 接收缓冲区分配内存,并将接收的数据包从网络适配器接收缓冲区复制到 VM 地址空间。

Windows Server 2012 及更高版本如何解决安全问题

从 Windows Server 2012 开始,VSP 不会为 VMQ 接收缓冲区分配 VM 中的共享内存。 相反,VSP 会从主机地址空间为 VMQ 接收缓冲区分配内存,然后将接收的数据包从网络适配器接收缓冲区复制到 VM 地址空间。

以下几点适用于在 Windows Server 2012 及更高版本的 Windows 上运行的 VMQ 微型端口驱动程序:

  • 对于 NDIS 6.20 VMQ 微型端口驱动程序,无需更改。 但是,当 VSP 通过发出 OID (对象标识符) OID_RECEIVE_FILTER_ALLOCATE_QUEUE 的方法请求来分配 VM 队列时,它将NDIS_RECEIVE_QUEUE_PARAMETERS结构的 LookaheadSize 成员设置为零。 这将强制微型端口驱动程序不将数据包拆分为预查看和后查看缓冲区。

  • 从 NDIS 6.30 开始,VMQ 微型端口驱动程序不得播发对将数据包拆分为预查找缓冲区和后查找缓冲区的支持。 当微型端口驱动程序注册其 VMQ 功能时,它必须在初始化 NDIS_RECEIVE_FILTER_CAPABILITIES 结构时遵循以下规则:

    • 微型端口驱动程序不得在 Flags 成员中设置NDIS_RECEIVE_FILTER_LOOKAHEAD_SPLIT_SUPPORTED标志。

    • 微型端口驱动程序必须将 MinLookaheadSplitSizeMaxLookaheadSplitSize 成员设置为零。

    有关如何注册 VMQ 功能的详细信息,请参阅 确定网络适配器的 VMQ 功能