什么在吞噬我的熵?或者 entropy_avail 真正显示了什么?

信息安全 随机的
2021-08-17 06:02:10

下面是/proc/sys/kernel/random/entropy_availRaspberry Pi 上的值的图表。这个可能不正确的答案 将其描述为:

/proc/sys/kernel/random/entropy_avail只是为您提供当前可以从中读取的位数/dev/random尝试读取更多内容将阻塞,直到有更多熵可用。

图案总是以每分钟减少约 130 位的方式达到相同的“稳定”锯齿图案。如果熵增长过多,则某些东西正在“吃掉”它以返回 700-800 范围。如果我重新启动设备,熵仍会每分钟被吃掉,但会以更小的块形式被吃掉,从而使其再次增长到 700-800 范围。

我该如何解释这些图表?怎么了?

我的感觉是,如果只有一个使用随机数生成器的进程,entropy_avail一旦失去平衡(通过使用设备硬件)应该会无限增长或降低到 200 的水平,届时/dev/random将停止提供值。

此外,如果任何监测方法(见下面的检查)影响熵,它应该每秒减少熵,而不是让它每隔一分钟突然增长和下降。

(如果我让机器闲置,稳定的“锯”模式会持续几天,我在更短的时间内截取了截图)


图表

  • 机器长时间闲置:

    在此处输入图像描述

  • 在 19:14:45 左右,另一台机器apt-cacher在 Pi 上访问 - 熵增长(我猜是网络使用情况)。之后在 19:16:30 下降到“正常水平”比平时更大(它也是可重复的 - 如果entropy_avail增长太大,下降得更快):

    在此处输入图像描述

  • 我重新启动机器,熵增长直到达到“通常”水平:

    在此处输入图像描述

    在此处输入图像描述

  • 它再次进入空闲状态:

    在此处输入图像描述

  • 再次重启后,熵减少的时间点发生了变化,但它仍然每分钟发生一次:

    在此处输入图像描述


检查

  • 我停止netdata(监控程序)并使用watch -n1 cat /proc/sys/kernel/random/entropy_avail. 的值entropy_avail以固定的一分钟间隔增长到 ~800 并下降到 ~680。

  • 根据建议“跟踪访问 /dev/random 和 /dev/urandom 的所有进程”我在 Debian VM 上检查过(来自类似问题inotifywait的答案的想法)并且无法访问任何一个目前下降(当然检查手动记录事件)。/dev/random/dev/urandomentropy_avail

  • 我使用entropy-watcher来检查熵,建议不要使用watch. 结果仍然与每分钟稳定增长和急剧下降一致:

    833 (-62)
    836 (+3)
    838 (+2)
    840 (+2)
    842 (+2)
    844 (+2)
    846 (+2)
    848 (+2)
    850 (+2)
    852 (+2)
    854 (+2)
    856 (+2)
    858 (+2)
    860 (+2)
    862 (+2)
    864 (+2)
    866 (+2)
    868 (+2)
    871 (+3)
    873 (+2)
    811 (-62)
    

Unix StackExchange 上的两个问题描述了相同的现象(稍后发现):

1个回答

首先,/proc/sys/kernel/random/entropy_avail简单地为您提供当前可以读取的位数/dev/random的说法是错误的。

entropy_avail字段读取input_pool.entropy_count,“输出”池是指用于urandom(非阻塞池)和random(阻塞池)的池。


正如这个答案中提到的,产生新进程会消耗像 ASLR 这样的熵。watch 程序为每次调用生成一个新进程,也许监控工具也会这样做(可能是通过必须调用外部程序来获取状态的其他监控源之一?)。

要在不耗尽熵池的情况下监控熵池,您可以尝试使用 entropy-watcher 程序(请参阅链接答案)。

仔细观察这些entropy-watcher数字,您似乎每隔一段时间就会丢失大约 64 位熵。根据另一个答案中的分析,这似乎是将熵移动到“输出池”以避免浪费它的结果。这是在 Linux v4.6 上观察到的,未来的实现可能会有所不同。

根据源代码(drivers/char/random.c在 v4.6 中),我可以看到读取输出池(/dev/{u,}randomget_random_bytes())调用extract_entropy{,_user}了哪些调用xfer_secondary_poolaccount阻塞池具有影响这两个功能的属性limit集 ( ):r->limit == 1

  • 因为account()如果它的熵太低,它将不会从阻塞池中返回任何数据。对于非阻塞输出池,将消耗剩余的熵,但仍会返回数据。
  • xfer_secondary_pool()确保输出池中有足够的熵可用。如果阻塞输出池的熵不足,它会从输入池中取一些(如果可能的话)。
  • xfer_secondary_pool()对于非阻塞输出池,根据/proc/sys/kernel/random/urandom_min_reseed_secs参数的特殊行为。如果此值非零,则仅在urandom_min_reseed_secs自上次传输后至少经过几秒后才从输入池中获取熵。默认情况下,此值设置为 60 秒。

最后一点最终解释了为什么您每 60 秒就会在输入池中看到一次熵消耗。如果某些消费者从非阻塞输出池中请求随机字节(TCP 序列号、ASLR、/dev/urandom... getrandom()、...),那么将从输入池中消耗 128 位来重新设置非阻塞输出池的种子。