现代计算机内部包含了许多更小的计算机,从主处理器到硬盘、网卡甚至线缆里的芯片,无不如此。本文盘点了这些组件,并解释了它们隐藏的计算能力为何攸关安全。
为什么你的「电脑」里,有那么多地方能藏匿后门和怪异机器(weird machines)?
因为大东西都是由小东西组成的:你的电脑实际上由几十、几百甚至可能上千块芯片构成。其中许多芯片承载着怪异机器,在显性或隐性地执行图灵完备的计算(许多芯片比过去时代的台式机还要强大),它们协同工作,共同制造出这是一台「单一计算机」的错觉。
后门、漏洞、怪异机器以及安全问题,才不在乎你怎么想——它们只在乎去哪里能找到资源,并将其编排成一场计算。
如果说「现在的网络就是计算机」,那么「现在的计算机就是(由众多计算机组成的)网络」,这话同样不假。 也许像 Altair PC 这样最早期的计算机里,真的只有一台「计算机」,所有图灵完备的任务都必须从同一个地方通过。但那个时代早就结束了。如今的「计算机」由无数组件构成,其中许多组件要是放在过去,本身就是一台好用的计算机。 「计算机」这个称呼只是为了图方便,并非什么泾渭分明的界限。 真正重要的是输入和输出:作为一个整体,系统能力有多强?需要什么资源?怎样才能重新编程这些组件?
层次
没人关心谷歌底层究竟是 50 台超级计算机、5 万台大型机、500 万台服务器,还是 5000 万个嵌入式/移动处理器,抑或是上面这些硬件的大杂烩。它们利用了五花八门的芯片,从定制的「张量处理单元(TPU)」到定制的片上硅(英特尔曾为几个大客户在至强芯片上做过这种定制),从 FPGA 到 GPU 再到 CPU,甚至还有更稀奇古怪的硬件,比如定制的 YouTube 视频编码芯片或处于原型阶段的 D-Wave 量子计算机——只要谷歌能跟其他科技巨头一较高下,并以合理的成本提供服务,这就够了。 (如今的「超级计算机」大体上就是一大批机架式服务器,塞进了多得异乎寻常的 GPU,再用快得异乎寻常的 InfiniBand 网络连起来,跟数据中心也没太大区别。) 这些硬件,任何一块都能根据其运行机制,在诸多不同的计算层级上支撑起多台怪异机器。 这个系统可以从多个层级去审视,每个层级的视角虽说都不完全严谨,却各有各的用处。 你到底是一个「单一的生物智能体」,还是由人体细胞、神经元、细菌、酵母菌、病毒和寄生虫组成的群落/生态系统?这究竟要紧吗?
计算机嵌套计算机

插图:XKCD #2166,「堆栈」。
这个问题本身边界模糊,这里有个现成的例子:此时此刻,不管是你的桌面上还是口袋里,你到底有几台计算机? 你的「计算机」里有多少台计算机?你以为只有一台吗?咱们仔细瞧瞧——里面全是大大小小的计算机。 你可能以为,除了主板上占据 C 位的那个大个头 CPU,顶多再算上 GPU,就没别的了。但实际上,整个系统可调用的计算能力远远超出了 CPU 和 GPU 的范畴。原因有很多:大规模量产使得晶体管和处理器核心变得极度廉价,因此在很多情况下,出于实时性或高性能的要求,为了提供安全保障,为了避免主操作系统因某项任务而不堪重负,或者为了兼容老旧架构与现有软件包,人们往往觉得干脆单拉一个核心出来处理更划算。此外,由于给 DSP 或通用核心写程序,比专门去造一个特定的 ASIC 来得快,或者说,随手拍上一块小 CPU 才是最快捷的解决方案,根本不值得为了省那几毛钱去费心思……[1] (Halvar Flake 将这种现象戏称为「廉价的复杂性」。) 只要有外设或设备被制造出来,「轮回之轮」就开始转动了。 更有甚者,许多组件哪怕原本并非用作计算,或者刻意隐藏了计算功能,依然可以被当作计算单元来使唤。 (比如,Commodore 64 的软驱里运行 Commodore DOS 的 CPU ,就被拿来当成额外的备用算力,或者用来破解防拷贝机制,因为它跟主 CPU 一样强;你可以把计算分形、为演示动画做 3D 数学运算、跑国际象棋程序等任务甩给这个「协处理器」……)
往下探究
由此可见:
- 一块普通的 AMD/Intel x86 CPU 拥有数十亿个晶体管,它们被分配给许多独立运作的组件:
- 这两个以上的 CPU 核心,每一个都能独立运行,视需要开启或关闭。它们各自拥有专属的 L1 到 L3 缓存(这些缓存通常比几十年前台式机的全部内存还要大[2],物理尺寸恐怕也比当年的整个 CPU 还要大),因此必须把它们视为一个个独立的个体。此外,CPU 整体上还能通过微码重新编程,比如用来修补芯片设计上的错误,因此这些 CPU 具体计算的内容也是会变的。
- CPU 身上不透明的功能越来越多。比如管理引擎和安全飞地,像英特尔管理引擎(Intel ME)(自带 JVM 以支持可编程性;Ruan 2014 与 SGX),或者 AMD 的平台安全处理器(PSP)、Android 的 TEE(可信执行环境)以及 Titan 芯片。这些硬件模块本质上往往是完整的计算机,它们独立于主机运行,甚至能对主机动手脚(这也导致了术语上的混乱:过去简简单单的 0 到 3 级保护环,如今不得不补上「−1 环」、「−2 环」和「−3 环」)。英特尔的 ME 运行的是闭源且无法审计的 MINIX 分支(MINIX 作为一个操作系统,更为人熟知的是它在 Linux 诞生过程中扮演的角色)。此举带来的安全隐患让谷歌大为光火,干脆立项把 MINIX 从其 CPU 及 Titan 芯片里给移除了。
- 任何浮点运算单元,只要借鉴 FRACTRAN 的精神,把程序编码成浮点运算,都可能是图灵完备的。[3]
- 内存管理单元(MMU)可以被编程为一台由 CPU 存根驱动的缺页故障怪异机器(见上文)。
- DSP 单元与定制硅片:诸如 h.264 这类视频格式的 ASIC 大概不是图灵完备的(尽管它们支持复杂的增量和压缩技术,或许能实现类似王氏砖的效果),但拿苹果 A9 移动端系统级芯片(SoC)来说,它可远不止是双核 ARM CPU 加 GPU 那么简单。和英特尔/AMD 的桌面端 CPU 一样,它不仅包含安全飞地(一个物理隔离的独立 CPU 核心),还内置了图像协处理器、运动/语音识别协处理器(部分用于支持 Siri),而且显然还有好几个别的核心。有些 ASIC 是为了支持 AI 任务,想必擅长神经网络的矩阵乘法;既然循环神经网络是图灵完备的……其他公司,像摩托罗拉或高通,也在争先恐后地往自家的 SoC 里塞东西。
- Mark Ermolov 指出,在一块给定的系统级芯片(SoC)上,不但有多个 CPU,而且轻轻松松就能凑齐 5 种不同的 CPU 架构:
英特尔 Silvermont 架构的 Moorefield SoC(ANN)里居然塞了这么多异构的 CPU 核心,实在令人惊叹:x86、ARC、LMT、8051、音频 DSP。它们各自跑着自己的固件,还都支持 JTAG 接口。
- 还有更古怪的专用芯片,比如 Macbook Touch Bar(触控栏)里的芯片。它们在独立于笔记本操作系统的 Apple T1/T2 SoC(采用了 ARM CPU)上,运行着小型的 WatchOS 应用并进行指纹认证。毫无疑问,这种芯片也能被黑掉,用来跑 Linux。
苹果智能手机里的「息屏常显(Always-on)处理器」,不仅能让手机在「关机」状态下依然被追踪定位,还实现了 Siri 的唤醒功能。 - 主板 BIOS 与管理引擎(在 CPU 对应的引擎之上),通常具备网络访问权限。
出厂的设备上,这类用于管理或调试的芯片可能被「不小心」保持在开启状态,比如 Via C3 CPU 里面嵌入的 ARM CPU。 - GPU 拥有数以百计简单的 GPU 核心,它们跑起神经网络来得心应手(极其擅长表达能力或图灵完备任务),也能做通用计算(哪怕比 CPU 慢一些)。[4]
- 智能手机:除了上面提到的所有单元外,手机里还有个独立的基带处理器。它运行着闭源的实时操作系统,负责处理与蜂窝基站、GPS 等设备的无线电通信,或者可能利用类似 L4 的微内核虚拟出多个处理器。基带处理器除了自身漏洞百出,还被发现过留有后门。
鉴于大多数这类嵌入式应用都用上了 ARM CPU,无怪乎 ARM 会得意洋洋地吹嘘:「一部现代智能手机大概包含 8 到 14 个 ARM 处理器,其中一个是应用处理器(运行 Android、iOS 或其他系统),而另一个则是负责基带协议栈的处理器。」 - 智能手机的 SIM 卡 绝非只是记录你入网信息的简单存储卡,它们可是能独立运行 Java Card 应用程序的智能卡(显然 NFC 芯片大概也是这副德行),有点像英特尔管理引擎里的 JVM。
理所当然,SIM 卡也能被黑入,沦为监视工具等。[5] - 磁带机、机械硬盘、闪存盘或 SSD 硬盘的 I/O 控制器等,通常也都带有 ARM 处理器。它们运行盘内固件,负责对操作系统隐藏坏道、加速磁盘加密或进行磨损均衡等任务。这玩意儿也能被黑。
- 网络芯片负责针对直接内存访问(DMA)进行独立处理。(正是因为有了这种独立性,再结合主板和 CPU 管理引擎,像用于网络引导启动的局域网唤醒(Wake-on-LAN)这类功能才能奏效。)
- USB / 雷电(Thunderbolt)线缆与设备,或是接在主板上的设备:至少在线缆、电池和充电器上,就得有个嵌入式处理器去协商数据和电源协议[6]。甚至在 WiFi 适配器、键盘、鼠标或 SD 卡等设备上,还要搞出带多个额外专用处理器的大阵仗。
理论上,这些东西大多是隔绝的,至少中间有 IOMMU 单元拦着,不让它们通过 DMA 直接把主机端掉,但魔鬼藏在细节里…… - 显示器内置的 CPU 负责控制并将 GPU 发来的信号统统显示出来(这项传统可以追溯到智能电传打字机时代)。
- ……
我们是群落
所以,一台台式机或智能手机里理所当然地藏着 15 到几千台不等的「计算机」(所谓「计算机」,是指图灵完备的设备,能够以通用的方式进行实用编程,且几乎不需要在「官方」计算机上运行代码)。它们拥有的强大算力,足以跑得动计算史上形形色色的许多程序;而对手自然能利用它们来监视、窃取数据,或是对系统的其余部分发动攻击。
纵观历史,这不足为奇。哪怕是最早的大型机,往往也是由多台计算机组成的:主计算机负责批处理,额外的小型计算机则接管高速 I/O 操作;如果不这么安排,光是中断请求就能把主计算机给憋死。
实际中,除了计算机安全圈(因为这些计算机通通不安全,正好成了好用的攻击路径),一般用户才不在乎我们的计算机底层有多么错综复杂,更不在乎它准确来说就是数百台被生硬拼凑在一起、大杂烩般的计算机群落。只要它运转正常,用户就会觉得这就是一台功能强大的独立计算机,并拿它当一台来用。
直到它不再按预期运转为止。
外部链接
- 讨论版:HN
- 俄语译本(2018-11-11)
- 《开源固件:一段爱情故事》,Zaolin(CCC 演讲,35C3,2018 年)
- 《你的计算机是一个分布式系统》
- 《扑灭硬件垃圾堆里的火灾》,Fiedler 等人,2023 年
- 《仓库级计算机:利用请求级与数据级并行》,Hennessy 与 Patterson,2011 年
- 《文件充满危险》,Dan Luu
尾注
[1] pkaye 在 HN 上举了这种心态的一个例子:
让我想起以前做固件开发时,ASIC 团队跑来问能不能顺手塞个额外的 Cortex-M3 核心进去,好解决特定的控制问题。这些核心会被当成可编程的状态机来用。对 ASIC 团队来说,跟专门去设计定制逻辑电路相比,随便扔个核心进去根本不花什么成本。然而,对固件团队来说,这就意味着又多了一份编写和测试固件的差事。我们有的设计里塞了多达 10 个 Cortex-M3 核心。我听在另一家公司上班的朋友说,他们那边塞了差不多 32 个这种核心,调试起来简直生不如死。
[2] 例如,2017 年的 Intel Core i9-7900X CPU 拥有总计约 24MB 的缓存,这比 1996 年的台式机 Power Macintosh 5200 LC 那 16MB 的内存(CPU 缓存只有 16KB!)还要大得多。
[3] 或者它们跑着看似无害的浮点运算,实际上却利用开启非线性的浮点运算设置编码了一个(深层)神经网络。另见《神经网络的对抗性重编程》,Elsayed 等人,2018 年与 Neekhara 等人,2018 年(说得更宽泛点,参考 GPT-3 / CLIP 的「提示编程」,或 Goyal 与 Bengio,2020 年 / Lu 等人,2021 年)。一个相关的话题是「机器教学」:Zhu,2013 年,Zhu,2015 年,Wang 等人,2018 年,Sucholutsky 与 Schonlau,2020 年。
[4] Arrigo Triulzi 在 2008 年演示过一套漏洞利用系统,该系统结合了对网卡(计算能力有限)和 GPU 的黑客攻击,使其能够独立于主机操作系统 / CPU 运行:《Project Maux Mk.II:「网卡已拿下,现在我想要个 Shell!」》 / 《绝地武士的数据包戏法接管死星(或者:「将网卡后门提升到新高度」)》。
[5] 每年我都把同一张 SIM 卡从旧智能手机里拔出来,再插进新手机,这总让我浮想联翩:它就像一个长生不老的微缩「蜂窝小矮人」——它到底在想些什么,又真正效忠于谁?
[6] Ken Shirriff 在拆解分析 Macbook 充电器时打趣道:「一块带微控制器的微型电路板成了意料之外的组件,如上图所示。这个 16 位处理器不间断地监控着充电器的电压和电流。当充电器连接到 Macbook 时,它开启输出;断开连接时,关闭输出;一旦出现问题,直接切断充电器电源。这个处理器是一块德州仪器的 MSP430 微控制器,性能跟初代 Macintosh 里的处理器差不多。[充电器里的处理器是一块 MSP430F2003 超低功耗微控制器,拥有 1kB 闪存和区区 128 字节的内存。它内置了一个高精度的 16 位模数转换器。更多信息在这里]。」
Thoughts Memo 汉化组译制
感谢主要译者 gemini-3.1-pro,校对 Jarrett Ye
原文:How Many Computers Are In Your Computer? · Gwern.net