Skip to content

L22:安全(Security

MIT 6.5900 Fall 2024 · Joel Emer 主题:侧信道(side channel)、信息泄露、攻击的通信模型、Cache 信道、推测执行攻击(Meltdown / Spectre


一、安全与信息泄露的根源

  • 像虚拟内存这样的硬件隔离机制保证了体系结构状态不会被其他进程直接看到……但是;
  • ISA 是一个与时序无关timing-independent)的接口:它规定"应该发生什么",而不规定"何时发生"
  • ISA 只规定体系结构状态更新(寄存器、内存、PC……),微架构变化未被规定
  • 因此,实现细节与时序行为(如微架构状态、功耗等)被用来突破安全机制;
  • 具体而言,它们被当作信道channel)来泄露信息。

二、攻击的通信模型(Communication Model of Attacks

标准通信模型

  1. 发送方拿到一条消息;
  2. 发送方调制modulate)信道;
  3. 接收方在信道上检测到调制;
  4. 接收方把调制解码为消息。

攻击模型的术语 [Belay, Devadas, Emer]

  • Domain):体系结构状态不共享的不同体系结构域(如受害者域、攻击者域);
  • 秘密Secret):在信道上传输、被接收方检测的"消息";
  • 信道Channel):某种可被"发送方"改变(调制)、且其调制可被"接收方"检测到的"状态"。

因为该信道不是"直接"通信信道,故常称为"侧信道"(side channel)。

攻击四步:

  1. 发送方访问秘密;
  2. 发送方基于秘密用消息调制信道(微架构状态);
  3. 接收方在信道上检测调制;
  4. 接收方把调制解码为含秘密的消息。

例:ATM 声学信道。秘密 = PIN;发送方 = 键盘;信道 = 空气;调制 = 声波;接收方 = 廉价麦克风;解码器 = 机器学习模型。


三、信道类型

类型调制载体攻击者要求
物理信道Physical功耗、电磁、声音……需测量设备、物理接触
时序信道Timing处理器响应时间可远程(如经网络连接)
微架构信道Microarchitectural微架构事件(如时序、性能计数器)可远程或同处一地

这些信道能做什么

  • 违反特权边界:跨进程通信、推断应用秘密;
  • (半侵入式)应用画像(profiling)。

与传统软件/物理攻击不同:

  • 隐蔽:需要复杂机制才能检测信道;
  • 通常没有被利用过的永久痕迹

四、时序信道示例

python
def check(input):
    size = len(passwd)        # passwd 含 8 位数字
    for i in range(0, size):
        if input[i] != password[i]:
            return "error"
    return "success"

执行时间取决于输入与正确密码匹配了多少个字符。攻击者可逐字符暴力破解,最多尝试 10×8=80 次;而盲猜需最多 108 次。


五、历史与"主动接收方"

1977 年的侧信道

源于磁盘臂优化:请求按柱面号升序入队,按"电梯算法"出队执行。

示例:接收方先请求柱面 55 并暂停;发送方请求 53 或 57;接收方再同时请求 52 与 58。若接收方先收到 52 的数据,就能推断发送方此前请求了哪个柱面。 若去掉第一步(接收方对 55 的请求),攻击不再成立——说明需要一个"主动接收方"来预置(precondition)信道。

主动接收方(Active Receiver

  • 主动接收方可能需要预置信道以便检测调制;
  • 还需处理预置、传输(调制)、接收(解调)三者之间的同步问题。

六、基于 Cache 的信道

简单 Cache 信道

进程 1(发送方)          进程 2(接收方)
write to set            if (send '0')
                            idle
                        else
                            write to a set
                        t1 = rdtsc()
                        read from the set
                        t2 = rdtsc()
                        if t2 - t1 > hit_time: decode '1'
                        else                   decode '0'

类似调幅AM)无线电发射:

python
secret = oneof(0..1)
if secret == 1:
    x = channel

RSA 中的"AM 发送方" [Percival 2005]

平方-乘(square-and-multiply)幂运算中存在依赖秘密的内存访问,从而成为发送方:

r = 1
for i = n-1 down to 0 do
    r = sqrt(r); r = mod(r, m)
    if e_i == 1 then              # 依赖秘密的分支
        r = mul(r, b); r = mod(r, m)
end
return r

多路组相联 Cache 信道:Prime + Probe

  • 预置(Prime):填满一个 set;
  • 传输:发送方按秘密决定是否写该 set;
  • 接收(Probe):读整个 set 并计时;
  • 解码:超过命中时间则解码 '1',否则 '0'。

推广到其他资源

任何"被使用后状态改变、并可被计时检测"的硬件资源都可作信道:

资源共享范围
私有 Cache(L1、L2)核内
共享 Cache(LLC)同 socket 跨核
Cache 目录跨 socket
DRAM 行缓冲跨 socket
TLB(私有/共享)核内/核间
分支预测器核内
片上网络(NoC)同 socket 跨核

七、信道噪声

  1. 另一个(或同一个)发送方可能向信道引入状态变化(噪声),混淆接收方(接收方可能把噪声当信号);
  2. 接收因此变成概率性的,需要对接收方做随机分析来解码;
  3. 可通过改进消息编码(如重复发送)提升接收可靠性。

多子信道发送:subchannel[secret] = 1,秘密取值 0..3,噪声使各子信道的信号呈概率分布。


八、缓解手段(Mitigations

1. 不使用信道:常时编程

与秘密无关的信道调制Secret-independent modulation)——即"数据无关执行"(data-oblivious execution)或"常时编程"(constant-time programming)。

把 RSA 中依赖秘密的分支改为无分支的条件移动:

p = (e_i == 1)
r2 = mul(r, b)
r2 = mod(r, m)
cmov [p] r, r2          # 无依赖秘密的分支/访存/浮点操作

常时编程很难:去掉依赖秘密的分支后,还要追问这些函数内部是否仍有泄露。

2. 扰乱时钟

"我们发现,找出系统中所有精确时钟,比找出所有可能的时序信道要容易得多。……若让时钟不那么精确,系统中所有时序信道的有效带宽都会降低。"(1991)

3. 不相交信道(Disjoint Channels

  • 使信道不相交可让通信变得不可能;
  • 信道可按"域"分配,并在进程进入/离开运行态时清理,使下一个进程看不到任何调制(如 DAWG,Kirianski et al., Micro'18)。

4. 混淆信道(Obfuscation

  • 加单个哈希:使接收方难以构造监视特定 set 的地址(各进程地址不再一一对应),但接收方仍可逆向推出会被调制的子信道;
  • 加进程相关哈希:使所需的 Cache 冲突变成概率性,接收方需额外步骤去探测多种"信道";
  • 接收方校准Calibration):校准单元确定接收方需用哪些子信道来检测调制——可观察已知传输,或主动激发发送方做特定传输。

九、发送方的类型

  1. 预先存在:受害者自身泄露秘密(如 RSA 密钥);
  2. 由攻击者编写并调用(如 Meltdown);
  3. 从受害者已有代码合成、由攻击者调用(如 Spectre v2)。

十、推测执行攻击

提醒:推测执行(Speculative Execution

在 x86 中,页表可含仅内核态可访问的内核页(避免上下文切换时换页表)。硬件推测性地假设不会发生非法访问,于是非法指令之后的指令被推测执行。

c
val = *kernel_address;   // 用户态执行:触发保护故障,
                         // 但 kernel_address 的数据被推测性读入 val

Meltdown [Lipp et al. 2018]

  1. 预置:接收方分配数组 subchannels[256] 并刷出所有 Cache 行;
  2. 传输:攻击者控制的发送方执行:
c
uint8_t secret = *kernel_address;
subchannels[secret] = 1;
  1. 接收:处理完保护故障后,接收方对 subchannels[256] 全部计时,找出被"调制"的子信道,解出秘密。

结果:攻击者可读取任意内核数据!为提高性能可用事务内存(异常时事务中止而非进内核)。 缓解:内核页表隔离(KPTI,不把内核数据映射进用户页表);或在权限检查失败时返回零(支持精确异常)。

Spectre variant 1 [Kocher et al. 2018]

利用条件分支误预测,让内核推测执行受分支保护的"发送方"代码:

c
if (x < array1_size)
    y = array2[array1[x] * 4096];
  1. 预置:刷出 array2 全部元素;
  2. 训练:用小 x 反复调用,把分支预测器训练成"taken";
  3. 传输:用越界 x 调用,使 &array1[x] 指向目标内核地址;核误预测分支,推测性地把 &array2[array1[x]*4096] 取入 Cache;
  4. 接收:探测 Cache,推断 array2 哪一行被取入,得知内核地址的数据。

Spectre variant 2 [Kocher et al. 2018]

利用间接分支预测器(多数 BTB 只存源地址部分 tag):

  1. 训练:多次触发 victim_branch → xmit
  2. 传输:让 victim_branchtraining_branch 在 BTB 中别名,从而推测性触发 victim_branch → xmit
  3. 接收:与 Spectre v1 类似。

Spectre 变体与缓解

  • Spectre 依赖推测执行,而非延迟的异常处理 → 比 Meltdown 更难修复
  • 还有多种变体:利用推测存储缓冲、返回地址栈、泄露特权寄存器等;
  • 可攻击任意类型的 VM,包括 OS、VMM、浏览器中的 JavaScript 引擎、以及 OS 网络栈(NetSpectre);
  • 短期缓解:微码更新(尽量禁止共享推测状态)、OS 与编译器补丁(选择性避免推测);
  • 长期缓解:禁用推测?关闭侧信道?

小结

  • ISA 是与时序无关的接口,只规定"做什么"而不规定"何时做",也不规定微架构状态;
  • 实现细节(如推测执行)与时序行为(微架构状态、功耗)被用来突破安全机制;
  • 作为软硬件契约的 ISA,不足以对微架构安全进行推理

相关后续课程:Secure Hardware Design 6.5950/1(旧号 6.S983 / 6.888,https://shd.mit.edu


注:本讲涉及计算机安全攻击与防御,属于敏感主题,整理目的为体系结构学习。若用于实际系统安全评估,请遵循相关法律与道德规范。