Skip to content

第一百六十九章:影子诅咒

渡劫期

涉及内核源码:

林小源在安全山脉的深处停下了脚步。空气变得凝滞,四周的岩石开始发出细微的、不规则的脉动,像一颗心脏在地底深处跳动。

"你感觉到了?"

一个声音从岩石内部传来,低沉、扭曲,仿佛被什么东西紧紧束缚着。林小源循声望去,看到岩石的表面浮现一个模糊的影子——它没有实体,只有轮廓,轮廓的边缘在不断闪烁、扭曲。

"我是 Spectre。"

林小源的瞳孔骤然收缩。这个名字他在安全典籍中见过,写在最危险的那一页上。

"你……不是一种攻击吗?"

"我是一种诅咒,"Spectre 的声音带着苦涩,"来自 CPU 的推测执行。你看到的这个分支——"影子指向岩石中一条细小的裂缝,"CPU 会猜测它是否会被执行。如果猜对了,性能提升;猜错了,回滚状态。但是——"

影子的轮廓剧烈扭曲了一下。

"回滚不会清除缓存。"

林小源感到一阵寒意。CPU 提前执行的那些指令——读取的数据、计算的结果——即使分支预测错误,那些数据仍然留在缓存中。攻击者通过测量缓存访问的时间差,就能推断出本不该被读取的敏感信息。

"训练分支预测器,"Spectre 的影子演示着,"先用合法的索引调用多次,让 CPU 学会预测'条件成立'。然后突然传入一个越界索引——CPU 按照旧的预测,提前执行了越界访问。等它发现自己猜错了,数据已经在缓存里了。"

c
/*
 * Spectre 攻击原理:
 *
 * 1. 推测执行 (Speculative Execution)
 *    CPU 提前执行可能需要的指令
 *    分支预测猜测执行路径
 *    如果猜测错误,回滚状态
 *
 * 2. 缓存侧信道
 *    回滚不清除缓存
 *    推测执行的数据留在缓存中
 *    通过缓存时序可以推断数据
 *
 * 3. 攻击步骤
 *    训练分支预测器
 *    触发越界读取
 *    推测执行访问敏感数据
 *    通过缓存时序泄漏数据
 *
 * Spectre 变种:
 *   v1 — 边界检查绕过
 *   v2 — 分支目标注入
 *   v3 — Meltdown (Rogue Data Cache Load)
 *   v3a — 指令寄存器泄漏
 *   v4 — 投机存储绕过
 *
 * 缓解措施:
 *   retpoline — 间接分支防护
 *   IBRS — 间接分支限制
 *   STIBP — 分支预测器隔离
 *   缓存刷新 — mfence/lfence
 */

/* 模拟易受攻击的代码 */
unsigned int array_size = 16;
uint8_t array[256];
char *secret = "SECRET";

/* 模拟秘密数据 */
uint8_t secret_data[] = {0x53, 0x45, 0x43, 0x52, 0x45, 0x54};

/* 模拟训练后的分支预测 */
int branch_predictor_trained = 0;

/* 易受攻击的函数 */
int vulnerable_function(unsigned long idx) {
    /* 边界检查 */
    if (idx < array_size) {
        /* 推测执行: 即使 idx >= array_size */
        /* CPU 可能提前执行这里 */
        return array[idx];
    }
    return -1;
}

/* 模拟 Spectre 攻击 */
void spectre_attack(void) {
    printf("  攻击步骤:\n");
    printf("  1. 训练分支预测器\n");
    printf("     多次调用 vulnerable_function(合法索引)\n\n");
    printf("  2. 触发越界读取\n");
    printf("     调用 vulnerable_function(越界索引)\n\n");
    printf("  3. 推测执行\n");
    printf("     CPU 提前读取 secret_data\n");
    printf("     数据进入缓存\n\n");
    printf("  4. 缓存时序攻击\n");
    printf("     测量访问时间\n");
    printf("     推断 secret_data 内容\n");
}

printf("=== 影子诅咒 — Spectre 攻击 ===\n\n");

printf("Spectre 利用推测执行泄漏数据:\n\n");

printf("--- 推测执行 ---\n");
printf("CPU 的行为:\n");
printf("  if (idx < size)\n");
printf("      访问 array[idx]\n\n");
printf("CPU 的推测:\n");
printf("  猜测 idx < size\n");
printf("  提前访问 array[idx]\n");
printf("  如果猜错,回滚\n\n");

printf("--- Spectre 攻击 ---\n");
spectre_attack();

printf("\n--- Spectre 变种 ---\n");
printf("v1: 边界检查绕过\n");
printf("  最基本的变种\n\n");
printf("v2: 分支目标注入\n");
printf("  攻击间接分支\n\n");
printf("v3: Meltdown\n");
printf("  利用异常处理延迟\n\n");

printf("\n--- 缓解措施 ---\n");
printf("1. retpoline:\n");
printf("  替换间接分支\n");
printf("  防止分支目标注入\n\n");
printf("2. lfence:\n");
printf("  内存屏障\n");
printf("  防止推测执行\n\n");
printf("3. IBRS/STIBP:\n");
printf("  硬件支持\n");
printf("  限制分支预测\n\n");

printf("--- 查看缓解状态 ---\n");
printf("cat /sys/devices/system/cpu/vulnerabilities/spectre_v1\n");
printf("cat /sys/devices/system/cpu/vulnerabilities/spectre_v2\n");

林小源蹲下身,仔细观察岩石中那些残留的缓存痕迹。每一个痕迹都对应着一次内存访问——时间长的是缓存未命中,时间短的是缓存命中。

"时序攻击,"他喃喃道。

"没错,"Spectre 的声音变得更加低沉,"缓存的访问时间是可测量的。命中和未命中之间有数十个时钟周期的差异。攻击者不需要读取缓存内容,只需要测量时间,就能逐字节推断出秘密数据。"

林小源站起身,神色凝重:"有什么办法防御?"

"retpoline,"Spectre 说,"用一个无限循环替换间接分支,让分支预测器无法被训练。还有 lfence——内存屏障,阻止推测执行跨越屏障。以及 IBRS、STIBP,硬件级别的分支预测器限制。"

"但这些都要付出性能代价。"

Spectre 的影子沉默了。岩石的脉动变得缓慢而沉重。

"是的。每一次缓解,都是用性能换安全。retpoline 让间接分支变慢,lfence 阻断了推测执行的优化。没有免费的安全。"

林小源站在岩石前,与 Spectre 的影子对视。

"你为什么告诉我这些?"

"因为我没法被消灭,"Spectre 的声音中带着无奈,"我存在于 CPU 的微架构中。除非重新设计 CPU,否则推测执行的副作用永远存在。软件能做的,只是缓解。"

林小源伸出手,触碰岩石表面。那些脉动从指尖传来,微弱但持续——像一个无法根除的暗伤。

"硬件缺陷,软件来补。"他低声说。

"对,"Spectre 的影子开始消散,"记住:没有完美的防御。但每一次缓解,都让攻击变得更难、更慢、更容易被发现。这就够了。"

影子消散后,岩石恢复了平静。但林小源知道,那些脉动还在——在每一次推测执行中,在每一个分支预测中,在缓存的每一次命中与未命中中。Spectre 不会消失,它会一直存在,提醒着安全的代价。


道藏笔记

内核启示

Spectre 利用的是 CPU 推测执行的副作用。CPU 提前执行了分支路径上的指令,猜错后回滚状态,但缓存不会回滚。攻击者先训练分支预测器(用合法索引多次调用),再突然传入越界索引——CPU 按旧预测提前执行越界访问,数据就留在缓存里了。通过测量缓存访问时间差,逐字节推断秘密数据。

v1 是边界检查绕过,v2 是分支目标注入,v3 就是 Meltdown。缓解靠 retpoline(用无限循环替换间接分支让预测器无法训练)、lfence(内存屏障阻断推测执行)、IBRS/STIBP(硬件级分支预测器限制)。每种缓解都有性能代价,但这是硬件缺陷只能软件来补。

Spectre 是诅咒——硬件的缺陷,软件的负担。


破关试炼

Spectre 之试

影子诅咒利用分支预测和缓存侧信道泄露信息,本章对应的漏洞家族叫什么?

答对后才能继续滑动和进入下一章。

以修仙之名,悟内核之道