↓推荐关注↓
Jason Donenfeld 是 WireGuard 的主要开发者,同时他也是 Linux 内核随机数相关代码的维护者,近日在他的领导下,Linux 内核的随机数生成器代码有了巨大幅度的改进。
2014年的时候,getrandom()被加入kernel,当时一个理由是因为LibreSSL project在Linux上抱怨在文件描述符被黑客恶意用光的情况下没有办法生成随机数。此前的获取方法是从/dev/urandom来读取,不过如果攻击者让所有文件都被打开,那么就没法打开/dev/urandom了,也就没法拿到随机苏。这样大家就创建了getrandom()系统调用,能够在不需要文件描述符(甚至像chroom或者container里这种没有/dev/urandom文件节点)的情况下就能拿到随机数了。getrandom()是故意设计成这样的,就是希望在/dev/urandom随机数池初始化好之前阻塞住不返回。在发明getrandom()调用之前,user space没有任何方法能确保系统采集了足够的entropy熵值并生成了随机数池。也就是说/dev/urandom的行为是kernel ABI定义好的,不可以更改,而新加的系统调用则可以不遵循这个限制。要想完成CRNG的初始化,需要有512 bit的entropy,或者说需要有4096次中断。Ts'o觉得这个值选得有些保守。getrandom()的文档里清楚的描述了这个阻塞行为,不过user space开发者仍然有人会错用这个API。
Ts'o认为今后这里肯定会有问题,必须得找个方法,要么能让user space开发者知道这里不能保证启动阶段之后就能使用getrandom,要么让大家能绝对信任Intel和RDRAND指令。否则的话,今后kernel里面哪里又有一个优化导致中断数变少的话,又会导致某人的系统或者application卡死了。
Linus Torvalds指出,RDRAND指令又不是在每个系统上都有的,所以没法依靠RDRAND指令来解决所有问题。他也觉得今后ssd会使用更多的polling而不是中断的情况下,情况会变得更糟,大家要针对这种“更少中断”的环境早作打算。
在之前的 Linux 5.17 中,Jason Donenfeld 就在随机代码用 BLAKE2s 代替了 SHA1,由于 BLAKE2s 自带的特性,前者通常比后者更快更安全。经过测试,通过这个简单的转换就能获得 131% 左右的速度提升。
虽然在 Linux 5.17 中有了速度上的大幅提升,但 Jason Donenfeld 对此并没满足。因此在 Linux 5.18 中他对随机代码作出了更多的改进。通过查看 Linux 的 random.git 仓库的日志能够看出(上图),开发者 Jason Donenfeld 在最近两天时间里进行了大量的代码提交。这些提交内容都将在 3 月下旬 Linux 5.18 的合并窗口启动时引入内核。在邮件中特别强调到,通过使用正在开发的最新代码,用于获取随机字节的 getrandom() 调用能够获得更好的性能。在配备英特尔 Xeon E5-2697 v2 @ 2.70GHz CPU 和 112G 内存的设备上进行 stress-ng getrandom() 基准测试后,更是获得了 8450% 的性能提升。此次更改基本上会将之前的全局结构(实际上是 per-numa 节点结构)更改为 per-cpu 结构,这意味着快速路径上的许多锁都会消失。因此,当在具备多核的 CPU 上同时尝试 getrandom() 时,毫无疑问性能会出现提升。只不过没想到在测试中能带来 8450% 的提升。除此之外,当从 per-numa 更改为 per-cpu 后,也将不再需要被推迟到工作队列上线后才能进行。也正如我之前所说,此次改进将会为高核心数的电脑和服务器带来巨大收益。链接:https://www.oschina.net/news/183698/linux-getrandom