linux 下关于 getrandom 和 /dev/urandom

问题遇到的现象和发生背景

在嵌入式设备中,使用 dropbear 提供 ssh 服务,但是发现 ssh 服务需要设备开机 10min 之后才能连通。能连通的时候,会有如下内核打印

[ 7043.317660] random: crng init done

同时跟进 dropbear 代码,发现获取随机数时,返回失败,并且 errno 置为 EAGAIN,对应获取随机数的语句如下

ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK);

查看 getrandom 函数的 man page,发现这个函数默认相当于从 /dev/urandom 读取数据,但是我通过 cat 命令直接读取这个设备,发现设备工作正常

/tmp # cat /dev/urandom | od -x
0000000 1072 7e85 03dc bbd9 30cc 1951 a39e 2f82
0000020 7163 5640 77c3 4bdb cd29 f4a6 8ff1 af7d
0000040 255c 1abb 4da8 d809 94eb 2d65 589e 52ab
0000060 1f9f 7471 da45 0664 c43d 753e 11cc ee37
我想要达到的结果

有没有熟悉这部分的朋友帮忙分析一下,为什么 getrandom 需要系统启动十多分钟之后才能获取成功呢?有没有办法缩短这个时间呢

getrandom

点击查看参考资料 http://man7.org/linux/man-pages/man2/getrandom.2.html

getrandom 封装了对 /dev/urandom 字符设备文件的读取操作,用于获取高质量的随机数,/dev/urandom 会以 /dev/random 的值做为 seed 参考,/dev/random 值则来自硬件运行的噪音 (随机质量很高)。这种机制也决定了 /dev/urandom 在操作系统刚启动时生成的随机数质量不高(刚启动,/dev/random 中噪音不足,生成慢,随机性差,容易被预测,间接导致了 /dev/urandom 的起始 seed 质量低下),所以 /dev/urandom 内部对其质量设置了三种状态:

0 = 未初始化,但是 /dev/urandom 已经可用;
1 = 快速初始化,使用了少量熵数进行了快速初始化,在刚启动时就尽快可以被用起来,质量还行,但是仍然不被建议用于加密场景,通常发生在操作系统启动后的几秒内;
2 = 完全初始化,随机数的质量达到最高,可以用于加密场景,操作系统启动后约几十秒 – 几分钟的时间才能达到。
在默认情况下,getrandom 读取 /dev/urandom 前会去检测 /dev/urandom 的质量状态,如果尚未完全初始化,则会阻塞,直到其完全初始化,以此来保障通过此接口获得到的随机数质量高且速度快,为安全领域提供可靠的依赖。
了解了 getrandom 接口的作用和表现后,再去翻看内核的启动日志,找到了时间相关性极高的点。

img


可以看到,23:10:48 时 /dev/urandom 完全初始化后,随即 getrandom 的调用阻塞也被解除了,再多次重复验证后,关联性被确认。此时的结论以及建议解决办法为:原因:操作系统初始化随机数熵池速度较慢,导致 ssh 登录时使用到随机数的一条命令时被阻塞。
建议:禁用 motd 或者删除 landscape-sysinfo 来达到加速 ssh 登录的目的。

应该是/dev/urandom初始化慢,看看这篇文章是否对你有帮助。
https://zhuanlan.zhihu.com/p/92996084

https://blog.csdn.net/beebeeyoung/article/details/115388686?spm=1005.2026.3001.5635&utm_medium=distribute.pc_relevant_ask_down.none-task-blog-2~default~OPENSEARCH~Rate-12.pc_feed_download_top3ask&depth_1-utm_source=distribute.pc_relevant_ask_down.none-task-blog-2~default~OPENSEARCH~Rate-12.pc_feed_download_top3ask

如其他回答,主要原因是系统的熵值太少,导致 /dev/urandom 的起始 seed 质量底下。对于这个问题,网上找到的解决方案主要有两种:

  1. 配置内核,启动 CONFIG_RANDOM_TRUST_CPU 选项。但是这只对 x86 等少数 CPU 有效。嵌入式中,我使用的是 aarch64,所以,此方案无效
  2. 使用伪随机数投喂熵池,让熵的数量达到要求。这里,我使用的是 rngd 工具