
合盖挂起本该是安全状态,这次回归让这道防线悄悄失效。图:Gre123gr/CC0
有一类安全漏洞最让我后背发凉,不是那种被人写成exploit满天飞的,而是这种:一道防线明明该起作用,结果它悄无声息地失效了,好几个内核版本里没人发现,直到有人偶然翻出来。这次的主角是Linux上的全盘加密,LUKS。
简单说结论:自Linux 6.9起,你合上笔记本、让它挂起的时候,本该从内存里被抹掉的磁盘加密密钥,其实没被抹掉,它还老老实实躺在内核内存里。也就是说,如果你以为"挂起=安全",那这个假设,从6.9开始就不成立了。发现并公开这件事的是Ingo Blechschmidt,他还把问题git-bisect到了具体的内核改动上。
先讲清楚,全盘加密到底靠什么保命
很多人对全盘加密(FDE)有个美好的误解,觉得只要开了LUKS,硬盘就是块砖,谁拿去都读不出来。这话只说对了一半。
加密的原理决定了一件事:机器一旦开机、系统一旦跑起来,那把用来解密硬盘的主密钥(master key,也叫volume key),就必须待在内存里。它不待在内存里,硬盘上每一个扇区就没法实时解密,你连桌面都进不去。dm-crypt这套东西就是这么工作的——密钥常驻内核内存,随时供解密调用。
所以真正的安全模型是这样的:机器关机、彻底断电,硬盘是块砖,这时候加密最硬。可只要机器在运行,哪怕锁了屏,那把钥匙就明晃晃地放在内存里。这时候如果有人能物理接触到你的机器——偷走、扣押、趁你去接杯水——内存就成了攻击面。加密再强,钥匙露在外面,等于门锁很结实但钥匙插在锁孔上。

全盘加密运行时,主密钥必须待在内存里,这也让内存成了攻击面。图:PantheraLeo1359531/CC BY 4.0
冷启动攻击:内存里的钥匙没你想的那么快消失
这里要插一段背景,不然后面讲不透。为什么"钥匙在内存里"是个实打实的风险?因为有一种叫冷启动攻击(cold boot attack)的手法。
普林斯顿的研究者2008年就把这事捅破了。DRAM内存有个特性叫"数据残留"(data remanence)——断电之后,内存里的数据不是瞬间归零,而是会残留几秒甚至几分钟,温度越低残留越久。攻击者的玩法很直接:趁机器还在运行或挂起,强行冷重启,从U盘引导一个小系统把整块内存dump下来;或者干脆把内存条拔下来,插到自己控制的机器上读。研究里,断电五分钟后还能从内存里捞出可用的AES密钥。BitLocker、FileVault、dm-crypt、TrueCrypt,当年全中招。
所以你能理解,为什么"机器被物理拿走时,内存里别留着钥匙"是全盘加密安全模型里极其关键的一环。
luksSuspend的意义,就是"锁屏时把钥匙从内存抹掉"
cryptsetup里有个命令叫luksSuspend,它就是为堵这个洞设计的。你合盖挂起之前,系统调用luksSuspend,它做两件事:冻结加密卷,让硬盘暂时不可读;同时把那把主密钥从内核内存里清零。等你回来唤醒机器,它会重新问你要一次口令,把钥匙再放回去。
这套设计很聪明。它把"挂起状态"从安全模型的软肋,变成了一个相对可控的状态——机器躺在包里挂着,内存里没钥匙,就算被人冷启动、被人做内存取证,也捞不到那把能解全盘的主密钥。不少讲究安全的发行版和配置(比如NixOS的相关模块)都依赖它。
回归发生在哪儿:一次内核重构,抹掉动作没了
问题就出在这道防线本身悄悄失效了。
cryptsetup管理密钥时,用到了内核的thread keyring(线程钥匙环)。它依赖一个被写进手册的承诺:thread keyring会在引用它的那个线程结束时被销毁。cryptsetup就是靠这个语义来确保密钥被清掉的。可Linux 6.9的一次内核重构,把这个语义给破坏了——线程结束了,那份密钥的副本却没跟着销毁,仍旧留在内核内存里。
最阴的地方在这儿:从用户角度看,一切正常。你唤醒机器,它照样弹出口令框让你重新输入,看起来luksSuspend忠实地干了活。但底层其实存着一份你不知道的volume key副本。cryptsetup自己都被蒙在鼓里,它以为钥匙擦干净了,实际没有。这种"表面上一切照旧、防护却已归零"的状态,比明目张胆的报错危险得多,因为没人会去怀疑一个"看起来在正常工作"的功能。
好消息是,这事已经修了,而且补上了回归测试(regression test),防止它以后再溜回来。我核对了目前的公开信源,没有看到有人给它分配CVE编号,所以我不编——这是个确凿的安全回归,但别的号我不替它安。
我怎么看,普通人该怎么办
先说我的判断。开源安全最让人踏实的一点是"多眼睛盯着",但这次恰好暴露了它的另一面:一个被众多上层工具默默依赖的底层语义,可能因为一次看似无关的重构就变了味,而依赖它的人根本收不到通知。cryptsetup没写错,内核也不是恶意,两边各自合理,缝隙就出在中间那份没人明说的契约上。沉默的回归可怕,就可怕在它不报警——你以为的安全,早已不是那个安全。
那普通人要不要慌?我的看法是,别慌,但要认清自己在什么威胁模型里。这个洞要被利用,前提是有人能物理接触到你处于挂起状态的机器,还得有本事对内存做取证。对大多数人来说,你的日常对手是钓鱼邮件和弱口令,不是拿着液氮和内存读卡器的人。所以该做的还是那几件老实事:内核和cryptsetup保持更新,把这个修复吃进去;真要过境、进敏感场合、机器可能离开你视线,别用挂起,直接关机,断电才是全盘加密最硬的状态;条件允许就叠上TPM、Secure Boot这些机制,别把宝全押在一层上。
说到底,加密从来不是一个"开了就万事大吉"的开关,而是一整套关于"钥匙在哪、什么时候在、谁能碰到"的假设。这次的教训是:这些假设会因为你看不见的底层改动而失效。懂它的模型,比信它的名字,重要得多。
资料来源:Ingo Blechschmidt(@iblech)Mathstodon贴文、Hacker News讨论(item 48763035)、Privacy Guides社区、cryptsetup与NixOS相关记录,及普林斯顿"Lest We Remember"冷启动攻击研究。技术细节以内核与cryptsetup官方提交为准,未见分配CVE编号。
你出门在外,是习惯合盖挂起,还是干脆关机?说说你的看法。