ccAI 精读(二):不换 GPU 也能机密计算——Adaptor 与 PCIe-SC
接上一篇《ccAI 精读(一):为什么 GPU 跑 AI 需要保密?》:CPU 侧用 TVM 保护好了,但数据一上 PCIe 就是明文。ccAI 的答案是——在 CPU 和 xPU 之间的 PCIe 上插一个门卫,再在软件侧配一个翻译员,让老 GPU 也能机密计算。
本篇讲清四个组件怎么配合:Adaptor(兼容)、Packet Filter(决策)、Packet Handler(执行)、HRoT-Blade(信任),最后落到 §7 作者真做出来的原型。
🗺️ 总架构
1 | Remote User |
| 组件 | 角色 | 解决什么 |
|---|---|---|
| Adaptor | 🧑💼 翻译员/协调员 | G1 兼容性:让老软件不用改 |
| Packet Filter | 🚧 门卫 | 判断每个 packet 该 A1/A2/A3/A4 |
| Packet Handler | 🔐 执行员 | 真的做加解密、完整性检查 |
| HRoT-Blade | 🔑 信任中心 | Secure Boot / 远程证明 / 密钥交换 |
职责分工:Adaptor 解决怎么兼容原来的 xPU 软件,PCIe-SC 解决怎么保护 PCIe 上的数据。
下面沿着一个 packet 的旅程走一遍。
🚧 第一站:Packet Filter——这个包该怎么处理?
为什么不能全都加密?
直觉方案是把 PCIe 流量全部加密。但 PCIe 上跑的东西重要程度完全不同:
- AI 模型参数、输入数据 → 高度机密
- 中断、普通状态寄存器读取 → 不敏感
- 恶意/未知设备的请求 → 压根不该出现
全都加密既浪费性能,也管不住不该出现的包。所以论文走细粒度安全(fine-grained security)路线:按 packet 属性分类处置。
四种安全动作 A1~A4 ⭐
| Action | 全称含义 | 做什么 | 类比 |
|---|---|---|---|
| A1 | Prohibited | 禁止,直接丢弃 | 🚫 不让进 |
| A2 | Write-Read Protected | 加密/解密 + 完整性检查 | 🔐🛡️ 特级安检 |
| A3 | Write Protected | 完整性检查 + 安全校验(如核对 xPU 页表寄存器) | 🛡️ 普通安检 |
| A4 | Full Accessible | 直接通过 | ➡️ 免检 |
安全性从高到低:A2 > A3 > A4。安全性越高,性能代价越大,所以才要分级,而不是一刀切全加密。
Filter 看三个属性
1 | ① Packet Type 这个包是干嘛的?Memory Read / Write / Interrupt / MMIO / DMA |
同样是 Memory Write,发往敏感区域就该 A2,发往普通区域只要 A3;未知设备发来的,A1 直接丢。
L1 / L2 两级表:先挡坏人,再给好人分类
一个包进来,先过两道门:
1 | PCIe Packet |
L1 负责挡坏人(不授权 → A1),L2 负责给好人分类(按敏感度给 A2/A3/A4)。
为了让规则不至于为每种 xPU 写爆,还引入了 Mask:一条规则可以声明它只关心哪几个字段,其余字段忽略。
规则本身也要保护
攻击者若把敏感地址的处理从 A2 改成 A4,保护就全失效了——规则表本身也是攻击面。那么问题来了:规则由谁来定、怎么下发、以什么形式存放?这里藏着三个容易想岔的疑问:
Q1:策略是写死在代码里的吗?为什么能让用户下发?
不是。策略不是代码,而是数据——L1/L2 表里的一条条规则(32 字节一条),内容是每类包该怎么处理。就像防火墙规则可以热更新:管理员下发规则,根本不需要防火墙的源码。
谁来定规则?负载的主人(用户)。因为只有他知道:这段内存装的是模型权重(要 A2 加密),那段只是普通 buffer(A3 就够)。Adaptor 里写死的只是下发规则的通道(
pkt_filter_manage),规则内容永远是动态的。这也正是 ccAI 兼容新 xPU 的底气:厂商想给私有管理包加规则,直接通过 MMIO 寄存器加一条就行,不用重写固件。
用户定规则、Adaptor 搬运规则、Packet Filter 按规则分级
| 角色 | 职责 | 类比 |
|---|---|---|
| 用户(负载所有者) | 制定规则内容:哪些包/地址敏感、该怎么处理 | 🏛️ 立法者 |
| Adaptor | 把用户给好的规则装载进 PCIe-SC 的 L1/L2 表 | 📋 录入员 |
| Packet Filter | 每个包查 L1/L2 表,命中哪条就给哪个动作(A1~A4) | 👮 执法者 |
所以前文说的 Filter 分级 A1~A4 是执行视角(查表贴标签),这里的用户下发是制定视角(规则从哪来)——两句话不矛盾:分级的依据,正是用户预先放进表里的那些规则。另外注意,A1~A4 这四档动作是论文设计好的固定分类,用户能定的是每个包落到哪一档,不能发明第五档。
Q2:Adaptor 是云厂商的闭源模块,用户凭什么信它?
凭度量,不凭源码。云里的 Adaptor(约 2.1K 行)和 PCIe-SC 固件本来就是云厂商的闭源二进制,用户拿不到、也不该拿到源码——机密计算里,平台代码可信不可信不靠读过源码,而靠它被量测过、结果可远程证明(机制见下文第四站)。
所以真正要紧的不是开源,而是够小、可审计:论文把 CPU 侧新增的 TCB 压到约 3.1K 行(Adaptor 2.1K + Trust Modules 1.0K),越小越容易审清楚。
Q3:规则为什么要加密保存、用的时候才解密?
因为保存规则的 configuration space 在 PCIe-SC 上,是总线可达的区域,正落在威胁模型里(攻击者能 snoop / tamper PCIe)。明文放在那里有两个洞:
- 泄露:攻击者读到规则,等于拿到你工作负载的资产地图——哪些地址区间被当敏感数据处理;
- 注入:攻击者把自己的包改成 A4 直通、把别人的包标成 A1 丢弃,防护形同虚设。
所以规则落盘是密文,装载进 L1/L2 表时才用密钥解开——密钥是远程证明后由 HRoT-Blade / 信任模块颁发的。说到底:门禁名单也得加密保存,不然小偷先看名单,再挑没监控的门。
完整例子
TVM-1 向 xPU 写一段模型参数(地址落在敏感区
0x2000~0x3000):
- L1:Requester = TVM-1,是授权方 → ✅ 放行
- L2:Type = Memory Write + 地址敏感 → A2
- 转交 Packet Handler 执行
反过来,未知设备发同样的包:L1 就不授权 → A1,直接丢,根本走不到加密环节。
🔐 第二站:Packet Handler——真正把安全做出来
Filter 只是做决定,真正动手的是 Handler:加解密、安全检查、完整性验证。
为什么光加密不够?
加密解决 Confidentiality(别人看不懂),但不解决 Integrity(别人改不了)。攻击者看不懂密文,却可能篡改它,让 GPU 拿到被改过的数据。所以 A2 要同时上两道:
1 | Confidentiality → 加密(AES) |
Authentication Tag
可以理解成防篡改封条:发送前对数据算出一个 tag(如
ABC123)跟着数据走;接收方拿到数据重算
tag,不一致就说明被动过手脚。
一个 packet 是怎么被处理的?
Handler 不会把整包囫囵处理,而是把 Header 和 Payload 分开:
1 | PCIe Packet |
A2 的完整五步——下面以 D2H 方向(xPU 算完、把结果返回 TVM)为例:此时数据在 PCIe-SC 的 Handler 里才真正被加密(AES 引擎双向工作,H2D 任务下发方向则由 TVM 侧 Adaptor 加密,见下一站):
1 | 1. xPU 结果包到达 PCIe-SC |
任务下发(H2D)方向是镜像流程:payload 在 TVM 侧已被 Adaptor 加密后才上 PCIe,PCIe-SC 的 Handler 收到后负责解密和完整性校验,再以明文交给 xPU——Adaptor 这端留到下一站讲。
为什么这套能兼容各种 xPU?
不同 xPU 的 DMA/MMIO 实现各不相同,但它们的流量最终都是标准格式的 PCIe packet。Filter 只认 packet 属性、Handler 只动 header/payload,跟发起方是 NVIDIA 还是某 NPU 无关。这就是兼容性的技术根源。
🧑💼 第三站:Adaptor——为什么不用改驱动?
你可能会问:PCIe-SC 都能拦包加密了,还要 Adaptor 干嘛?
关键区别:PCIe-SC 只看得见 PCIe packet,看不懂 AI
任务。它看到一个包访问
0x12340000,但不知道这块内存是模型参数、输入数据还是临时
buffer。而 Adaptor 住在 TVM
里,知道当前任务的数据在哪、哪些敏感。所以:
1 | Adaptor(软件语义):这个任务要保护哪些数据 → 准备数据 |
Adaptor 干两件事:
- 通过 MMIO 与 PCIe-SC 交互:查询任务 metadata(数据地址、大小);装载安全规则——注意规则内容由用户授权(见上文 Q1),Adaptor 只负责把它们写进 PCIe-SC 的 L1/L2 表。
- 处理 xPU task:找到敏感数据 → 加密 → 放进 bounce buffer → 传给 xPU。
bounce buffer = 加密后再发货的临时中转仓库:敏感数据不直接上 PCIe,先被 Adaptor 加密到一块安全装货区,PCIe 上跑的已经是密文。
这样做的最大收益是不动老软件:不是去改 AI
App、Runtime、Driver,而是在旁边新增一个兼容层。论文原型里新增的是一个叫
ccAI_adaptor 的 kernel module——原生 xPU
driver 一个字节都不改。
换一种 xPU 怎么办?比如从 NVIDIA A100 换成某个 NPU:不需要重设计 PCIe-SC,只需给 Adaptor 更新 software-based kernel patches(经 secure boot 校验后激活),就能支持新的内存分配方式——这就是论文说的 compatible system updates。
🔑 第四站:Trust Establishment——凭什么信这台机器?
前面解决的是数据怎么保护,但还有个更根本的问题:
你怎么知道这台 PCIe-SC 里跑的还是 ccAI 的代码,而不是被攻击者换成了会偷密钥再加密的木马版?
如果门卫本身不可信,加密就是给贼上锁。§6 用三步建立信任:
1 | Secure Boot(先确认机器没被换) |
Secure Boot + HRoT-Blade
CPU 侧靠 TDX module 这类 TEE 隔离保护 TVM(并有 CPU 平台自带的硬件信任根 HRoT 支撑启动量测),但 PCIe-SC 是另一块独立硬件,CPU 的信任链管不到它,所以论文给 PCIe-SC 配了自己的信任根:HRoT-Blade(一个 TPM-compatible 的信任模块)。注意这里有两类信任组件要分清:平台自带的 CPU HRoT 是 ccAI 借来给 TVM / Adaptor 做安全启动量测的;而前面总架构图里 TVM 中的 TVM Trust Modules,论文明确说是 ccAI 部署进 TVM 的信任模块(ccAI deploys trust modules on both CPU-side TVMs and the PCIe-SC),负责存密钥、参与远程证明——不是 TDX 平台自带的。
启动时 HRoT-Blade 做 Measurement——给每个组件算指纹(hash):
1 | HRoT-Blade |
firmware 被改过 → 指纹不同 → 拒绝启动。
Remote Attestation
用户人在远程,看不到云服务器内部。服务器光说自己没问题没用,必须给出密码学上可验证的证明。Attestation Report 大概是:
1 | r = (n, PCRs, S(PCRs)) |
Nonce 是防重放的:用户每次给一个新随机数,要求把它签进报告里。否则攻击者可以拿机器健康时期的旧报告反复骗人。
Key Exchange
环境可信了,最后一步是把 workload 加密密钥安全交给平台(不能明文走网络)。之后,从用户把任务送进来到结果取回,数据全程的明文/密文状态是这样流转的:
1 | Remote User(明文:模型与输入) |
这里出现了两道加密,不是重复劳动——各管一段:
| ① 网络段 | ② PCIe 段 | |
|---|---|---|
| 密钥 | SessionKey:远程证明后用户与平台协商 | TVM 与 PCIe-SC 在各自信任模块里协商的对称密钥 |
| 保护范围 | 用户 → 云主机:网络与云主机上的窃听 | TVM → xPU 的 PCIe 总线(威胁模型里攻击者可 snoop) |
| 生命周期 | 会话期间 | 任务结束双方销毁,防数据泄露 |
明文只出现在两个可信域:
- TVM 内部;
- 被机箱密封 + 物理传感器守护的 xPU 侧:PCIe-SC ↔︎ xPU 的内部总线与 xPU 内部(论文 §6 的 chassis sealing)。
🛠️ 第五站:Implementation——作者真做出来了
论文用 Intel 服务器 + Intel Agilex 7 SoC FPGA 搭了原型,实现两个东西:
① Adaptor(软件)
- 新增
ccAI_adaptorkernel module(不改 CUDA / GPU Driver / AI Application) - 提供
encrypt_data()/decrypt_data(),用 AES-128 + Intel AES-NI 加速 - 分到 64 KB MMIO 区域 控制 PCIe-SC(装载规则到 L1/L2、启停 H2D/D2H 传输、查状态)
② PCIe-SC(FPGA 硬件)
- 分配 4 KB BAR 空间存放 L1/L2 规则表
- Packet Filter 从 header 提取三要素做匹配:Packet Type(Memory Read/Write…)、Route ID(谁发/发给谁)、Payload Metadata(start/end address,访问哪段内存)
📌 小结
| 组件 | 职责 | 关键点 |
|---|---|---|
| Packet Filter | 决策 | L1 挡坏人 → L2 给好人分级 → A1~A4 |
| Packet Handler | 执行 | Header/Payload 分离,AES + Auth Tag |
| Adaptor | 兼容 | 加密进 bounce buffer、ccAI_adaptor 新增不改老驱动 |
| HRoT-Blade | 信任 | Measurement → PCR → Attestation → Key Exchange |
到这里,能不能做、怎么做都清楚了。剩下最后一个问题:加了这么多安全操作,GPU 会不会慢成蜗牛? 论文实验里号称开销只有 0.05%~5.67%——下一篇就看作者怎么用 RQ1~RQ6 六个实验证明这套东西真的又快又兼容:ccAI 精读(三):实现与实验。
(本系列为 MICRO 2025 论文 ccAI: A Compatible and Confidential System for AI Computing 的入门精读笔记。)