LWN订户已向您提供以下仅限订阅的内容。成千上万的订阅者依靠LWN从Linux和自由软件社区获得最好的消息。如果您喜欢这篇文章,请考虑订阅LWN。感谢您访问LWN。网
内核中的阻塞';s随机数生成器(RNG)-导致进程等待";够了";熵产生强随机数一直是有争议的。多年来,它还导致了各种各样的问题,从用户空间程序中的误用导致的超时和延迟,到引导过程中的死锁和其他问题。在过去的几年里,这种行为已经发生了很多变化,而且看起来很有可能,依赖和#34;好";和";密码强度";在即将到来的内核版本中,随机数可能会消失。
内核RNG的历史很长,有些曲折;内核中有两个随机数设备,/dev/random和/dev/urandom,可以读取它们以获取随机数据/dev/Uradom一直被认为是几乎所有东西都可以使用的设备,因为它不会阻塞;它只是提供了内核在读取时能够提供的最佳随机数/另一方面,当dev/random没有足够的熵来提供密码强度时,它就会阻塞。这种熵来自各种设备(如磁盘、键盘、网络)的中断时间和硬件RNG(如果可用)/dev/Uradom将记录一条警告消息(一次),如果在初始化其池之前调用它(一旦使用收集的熵初始化了随机池),但它将提供其伪随机数生成器(PRNG)的输出,并且从不阻塞。
2014年,对于Linux 3.17,添加了getrandom()系统调用,为用户空间应用程序提供了一种可靠的方式,即使在文件描述符耗尽或无法访问随机设备的情况下,也可以请求随机数(对于在容器中运行的应用程序可能会发生这种情况)。getrandom()旨在使用Uradom池,但只有在从随机池完全初始化之后。因此,虽然对/dev/uradom的读取不会被阻塞,但对getrandom()的调用会被阻塞,直到收集到所需的熵。getrandom()调用者可以通过一个标志选择使用随机池,这使得调用受制于来自该池的数据的完整熵要求。
2019年,对ext4文件系统的一次不相关的更改导致系统无法启动,因为它减少了生成的中断次数,因此urandompool没有初始化,对getrandom()的调用被阻止。由于这些调用是在引导过程的早期进行的,因此系统无法达到可以收集足够熵的程度,因为引导过程正在等待getrandom()返回,从而导致死锁。5.3内核暂时恢复了ext4更改,LinusTorvalds为5.4添加了一个更持久的解决方案。它使用CPU执行时间抖动作为熵源,以确保随机池在大约一秒钟内初始化。这项技术有点争议,甚至托瓦尔兹也对此持怀疑态度,但它已经存在了好几年,而且一直在尽可能地发挥作用。
2020年,/dev/random的阻塞性质被更改为与getrandom()类似,因为它只会在初始化之前阻塞一次,然后提供加密强度随机数。安迪·卢托米尔斯基(Andy Lutomirski)为这一变化提供了补丁,他说:";Linux';CRNGS生成的输出足以用于密钥生成。阻塞池在任何物质方面都不强大,保持它的存在需要大量价值可疑的基础设施" 这些补丁还为getrandom()添加了一个GRND#u unsecure标志,该标志将返回";尽力而为";随机数,即使池没有被细化。
可以看出,随着时间的推移,两台设备之间的线路变得越来越模糊。更多关于内核RNG的历史,甚至可以追溯到更远的时间,可以在LWN内核索引中找到。考虑到这两种设备已经发展到一起,一个有效消除这种差异的新提议被提出或许并不令人惊讶。
Jason A.Donenfeld,作为内核的共同维护者';几个月前,s RNG子系统在最近的清理工作中相当活跃,并对代码进行了其他更改。2月11日,他发布了RFC,可能是a";请求赔偿损失";实际上,补丁建议在池初始化之前删除/dev/uradom返回数据的功能。这意味着内核RNG子系统将始终阻塞等待初始化,但此后始终返回加密强度随机数(除非使用getrandom()的GRND_unsecure标志)。因为Torvalds在5.4中所做的修改,Donenfeld称之为";莱纳斯吉特舞";,初始化的最大等待时间是最小的,因此Donenfeld建议进行更改:因此,考虑到内核从无到有地发展了这种播种机制,并且这个过程发生得非常快,可能有#39;不再需要/dev/uradom提供不安全的字节。过去我们没有';我不希望启动过程死锁,这是可以理解的。但现在,在最坏的情况下,一秒钟过去了,问题就解决了。似乎我们';我们终于可以摆脱臭名昭著的";Uradom read hole";。
然而,要做到这一点,还有一些潜在的障碍。抖动entropytechnique依赖于运行同一代码时的时间差异,这需要一个高分辨率的CPU周期计数器和一个看起来不确定的CPU(由于缓存、指令重新排序、推测等)。但是,有些体系结构并没有提供这样的功能,可以通过这种方式收集声熵。Donenfeld指出,非Amiga M68K系统、两种MIPS型号(R6000和R6000A)以及RISC-V可能会受到影响;他想知道是否还有其他受到类似影响的建筑。然而,他认为RISC-V代码并不是一个真正的问题,目前还没有人对此提出异议。同时,把其他平台放在一边可能是正确的方法:如果我的总体分析是正确的,那么这些古老的平台真的值得保留吗?我有一半希望收到一些西红柿,一个愤怒的拳头和一个";离开我的草坪", 如果是';s_all_Ihear,我';我给你一个暗示,我们可以忘记我曾经提出过这个建议。如上所述,我不打算合并,除非有';这是一个广泛的共识。但是,人们可能会有不同的感觉,也许莱纳斯抖动舞最终是解决多年来/dev/uradomkvetch问题的方法。
提议的补丁相当小;它只是删除了/dev/uradom的文件操作结构,并在其位置重用了/dev/random的一个,从而使这两个设备的行为相同。这也缩短了GRND_不安全旗的行为,但他后来说这有点分散注意力。他的提议的主要目的是:
托瓦尔兹对RFC有积极的反应。他说,这个补丁对于有循环计数器的架构是有意义的;抖动熵变已经活跃了两年半,没有多少抱怨,因此";我认为我们可以称之为成功;。对此可能有一些抱怨,但:";老实说,我认为所有的抱怨都来自那些不';无论如何,我没有任何实际的建议;。众所周知,托瓦尔兹对密码学的理论担忧(事实上,对其他任何事情的理论担忧)几乎没有耐心。
他确实反对为那些不能跳抖动舞的架构移除不安全的GRND#U,因为这是一种让用户空间解决启动时间熵不足的方法,即使它一点也不安全:从随机性的角度来看,这些系统可以说是被破坏的——如果存在';没有什么东西能产生熵——但不管破碎与否,我怀疑它们仍然存在。这些可怕的事情在嵌入式网络中非常常见(路由器、接入点——应该关注的地方)[……]几乎没有人测试这些坏平台:即使是为那些嵌入式网络设备构建新内核的人,最终也可能会在现有的用户空间设置中使用这些内核——在那里,人们有一些已保存的伪熵源。因此,它们甚至可能不会触发";第一次开机问题";这往往是最糟糕的情况。
但是,他说,他愿意应用补丁:";在某个时刻';担心平台破损';最终成为了一个软弱的借口,不去运用它";。据约书亚·基纳德(Joshua Kinard)称,这两个MIPS模型都是20世纪80年代的,从未在系统中使用过,而内核测试则是在随机代码中进行的#34;很可能是作为一种心理练习,在一本处理器手册或诸如此类的内容之后添加的;。Maciej W.Rozycki说,可能有一些系统使用这些模型,但从来没有为它们制作过Linuxport。这可能意味着唯一的问题是";一些m68kmuseum作品";,多恩菲尔德说。
然而,正如Geert Uytterhoeven指出的那样,Linux通用体系结构的循环计数器代码(新体系结构的默认值和起点)硬连接为返回零" 有几种体系结构不实现get_cycles(),也不使用';它与一般版本非常相似或相同" David Laight补充了一些架构的例子(旧x86、nios2)。
卢托米尔斯基有一个更平淡无奇的抱怨:我不喜欢这个补丁,因为它与安全无关。某个地方有一台Linux机器,可以在50毫秒内直接引导到Nethack。如果Nethack从/dev/uradom获得了256位惊人的熵,那么机器的所有者就必须真正玩了。如果它偶尔重复同样的游戏,主人可能会感到失望或好笑。如果它得到了一个可以用蛮力强迫的弱种子,那么主人可以用蛮力强迫它。另一方面,如果它等待750ms,等待足够的抖动熵达到完美状态,那就是完全失败。没有人想等750ms后再玩Nethack。
更严重的是,他担心备份摄像头或灯泡等需要开机的设备;立即";,而且随机数的质量可能不是真正的问题。GRND_不安全逃生舱就是因为这个原因。与此类似,LennartPoettering担心systemd需要等待一秒钟才能为其哈希表获取种子,而它已经有了为这些表重新设定种子的机制:因此,systemd使用(可能是半初始化的)/dev/uradom放弃其哈希表种子。对于这一点,如果随机值最初是低熵的,那就没关系了,就像我们';当发生太多散列冲突时,我们将自动重新设定种子,然后使用更新的(因此有望更好)种子,再次通过/dev/uradom获取。i、 e.如果种子最初不足以阻止哈希冲突攻击,一旦哈希表实际受到攻击,我们';I’我会用更好的东西代替种子。为此,我们所需要的只是随机池最终变得更好,即';就这些。
事实证明,systemd已经在可用的系统上使用了GRND#U Unsecure,因此,如果不像最初提议的那样改变这种行为,就可以很好地修复Poettering';斯肯森。多恩费尔德完全可以把格恩德的伤残从他的补丁中拉出来;如前所述,这并不是他的主要关注点。
基于托瓦尔兹';当然,在我们的回应中,除了名称之外,似乎没有太大的障碍来消除/dev/random和/dev/uradom之间的最终区别。但是,如果有更多的体系结构不能使用抖动技术,那么这种区别可能会继续存在,因为托瓦尔兹也认为保持";那些愚蠢的东西就像';不';不要伤害好平台,可以帮助坏平台'". Donenfeld说,代码删除量不会很大,因此它并不能真正简化代码;更重要的是能够消除关于在Linux上使用哪种随机性源的无休止的争论。为此,这似乎是一个值得追求的目标。
(登录发表评论)
具有讽刺意味的是,nethack的内部RNG非常弱,因此即使内核RNG非常完美,也很容易被粗暴对待&书信电报;https://nethackwiki.com/wiki/Random_number_generator>
谢谢你的总结。受您对讨论的阅读鼓舞,我最终提交了一个真正的补丁v1:https://lore.kernel.org/lkml/20220217162848.303601-1-Jaso...
让我直截了当地说:目前,/dev/random和/dev/uradom都会阻塞,直到它们有足够的熵。然而,它们的熵源不同/开发/随机抽取自";真正随机,crpto就绪#34;直接来自某种硬件源的位,其中as/dev/urandom从/dev/random'的种子PRNG中提取;它的硬件支持位。但我们没有';不在乎,因为通过伪RNG的位具有硬件位99%的随机性,并且是";足够好";crypto需要依靠什么?(即使他们可能会有点过时,如果PRNG重新播种已经有一段时间了)我想那是从/dev/uradom开始的;第一次使用/dev/random中的位作为种子可能与使用/dev/urandom中的位一样好,但是什么';他们最糟糕的情况有什么不同?如果我';我是一个攻击者,后来我从PRNG中提取了10亿个数字,然后下一次它';重新播种。
不,除了初始阻塞行为,它们已经是相同的,它们使用相同的熵池和相同的crng算法。如果还没有足够的熵,一个阻塞,而另一个警告,并返回可能不是随机数据。