如何确定哪些进程正在使用 /dev/urandom 中的多少熵

如何确定哪些进程正在使用 /dev/urandom 中的多少熵

这样做fuser -v /dev/urandom告诉我哪些进程当前已/dev/urandom打开,但仅此而已。是否有任何方法可以确定每个人随着时间的推移消耗了多少熵?例如,一个进程可能每分钟消耗大约 1 位熵,而另一个进程每秒消耗大约 8 位;我想要某种方法来确定这一点。

答案1

简短的答案是 0,因为熵没有被消耗。

有一个常见的误解熵被消耗——每次读取随机位时,都会从随机源中删除一些熵。这是错误的。你不会“消耗”熵。是的,Linux 文档弄错了

Linux系统的生命周期分为两个阶段:

  1. 最初,没有足够的熵。/dev/random会阻塞直到它认为已经积累了足够的熵;/dev/urandom很高兴提供低熵数据。
  2. 一段时间后,随机生成器池中就会出现足够的熵。/dev/random分配一个虚假的“熵韭菜”率并时不时地阻止;/dev/urandom很高兴提供加密质量的随机数据。

FreeBSD 的做法是对的:在 FreeBSD 上,/dev/random(或/dev/urandom,这是同一件事)如果没有足够的熵就会阻塞,一旦有足够的熵,它就会不断地喷出随机数据。在 Linux 上,这两者都/dev/random没有/dev/urandom什么用处。

在实践中,请使用/dev/urandom,并确保在配置系统时提供熵池(来自磁盘、网络和鼠标活动、来自硬件源、来自外部计算机……)。

虽然您可以尝试读取从中读取了多少字节/dev/urandom,但这完全没有意义。读取/dev/urandom不会耗尽熵池。每个消费者在您指定的任何时间单位内使用 0 位熵。

答案2

虽然不是自动化的,但您可以使用 strace 等工具来监视与 urandom 相关的文件描述符的读取。然后查看在特定时间段内读取了多少数据以获得读取率。

答案3

如果您不知道(或不怀疑)哪个进程可能会耗尽 Linux 上的 entropy_available,可以通过几种方法来解决该问题。

如前所述,您可以使用 strace,这对于深入了解您可能想要查看的进程非常有用。

您可以使用auditd来审计哪些进程打开/dev/random 或 /dev/urandom,但这不会告诉您读取了多少数据(以防止记录问题)。以下是一些命令,列出规则,然后添加两个手表

auditctl -l
auditctl -w /dev/random
auditctl -w /dev/urandom
auditctl -l

现在通过 SSH 进入盒子(或者执行其他您知道会导致打开 /dev/urandom 或类似操作的操作,例如 dd)。

ausearch -ts 最近 | aureport-f

就我而言,我看到类似以下内容:

[root@metrics-d02 vagrant]# ausearch -ts recent | aureport -f

File Report
===============================================
# date time file syscall success exe auid event
===============================================
1. 07/01/20 01:13:36 /dev/urandom 2 yes /usr/bin/dd 1000 6383
2. 07/01/20 01:16:43 /dev/urandom 2 yes /usr/sbin/sshd -1 6389
3. 07/01/20 01:16:43 /dev/urandom 2 yes /usr/sbin/sshd -1 6388
4. 07/01/20 01:16:43 /dev/urandom 2 yes /usr/sbin/sshd -1 6390
5. 07/01/20 01:16:44 /dev/urandom 2 yes /usr/sbin/sshd 1000 6408

请禁用这些手表

auditctl -W /dev/random
auditctl -W /dev/urandom

请记住,这只会捕获非读/写等系统调用的数据,因此如果有任何内容已打开,您将不会看到它被读取。

然而,我注意到(使用 Prometheus 和 node_exporter)我仍然看到锯齿模式,其中 VM(CentOS 7,没有任何可收集熵的内容)报告 entropy_available 上升到接近 200,然后会骤降到 0。

lsof(如果你愿意的话,可以是fuser)提供什么吗?

[root@metrics-d02 vagrant]# lsof /dev/random /dev/urandom
COMMAND  PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
chronyd 2184 chrony    3r   CHR    1,9      0t0 5339 /dev/urandom
tuned   2525   root    5r   CHR    1,9      0t0 5339 /dev/urandom

请注意字符设备的主设备号和次设备号;测试另一种方式...(我不确定这是否有用,只是考虑像 Docker 这样的东西,它不在这个虚拟机上运行)

[root@metrics-d02 vagrant]# ls -l /dev/*random
crw-rw-rw-. 1 root root 1, 8 Dec 19 01:24 /dev/random
crw-rw-rw-. 1 root root 1, 9 Dec 19 01:24 /dev/urandom

[root@metrics-d02 vagrant]# lsof | grep '1,[89]'
chronyd    2184           chrony    3r      CHR                1,9      0t0       5339 /dev/urandom
tuned      2525             root    5r      CHR                1,9      0t0       5339 /dev/urandom
gmain      2525  2714       root    5r      CHR                1,9      0t0       5339 /dev/urandom
tuned      2525  2715       root    5r      CHR                1,9      0t0       5339 /dev/urandom
tuned      2525  2717       root    5r      CHR                1,9      0t0       5339 /dev/urandom
tuned      2525  2754       root    5r      CHR                1,9      0t0       5339 /dev/urandom

好的,我们有两个进程:chronyd 和tuned。让我们使用strace。 lsof 告诉我们 chrony 已打开 /dev/urandom 以便使用 file-discriptor 3 进行读取

[root@metrics-d02 vagrant]# strace -p 2184 -f
strace: Process 2184 attached
select(6, [1 2 5], NULL, NULL, {98, 516224}
.... (I'm waiting)

因此 chronyd 正在等待某些活动,从启动此系统调用起的超时时间为 98 秒。

在等待期间,我应该强调我在系统上的活动可能会增加内核对可用随机位的估计。 (entropy_available)...所以坐下来看看 Prometheus 图表...

Prometheus 图表显示了随时间变化的 node_entropy_available_bits 以及描述

我们也可以用tuned重复...(这次为文件描述符5添加一些时间戳和grep过滤器(读取等调用将其作为第一个参数)

[root@metrics-d02 vagrant]# strace -p 2525 -f -tt -T 2>&1 | grep '(5,'

Red Hat 有一个博客进一步讨论CSPRNG(加密安全伪随机数生成器)。它讨论了进程可以访问随机数的一些其他方法:

  • getrandom() 系统调用 <-- 推荐用于 RHEL7.4+,熵池初始化后高质量无阻塞
  • /dev/random <-- 很容易阻塞
  • /dev/urandom <-- 在池启动之前使用时出现问题。将“永远不会阻塞”;应该是大多数应用程序应该使用的。
  • AT_RANDOM <-- 在执行时设置 16 个随机字节一次

虽然 AT_RANDOM 没有用,但它存在于每个进程中,因此仅启动进程的行为就应该至少消耗一点点。

现在您会意识到,我上面使用 lsof 展示的内容是不够的,它没有揭示 getrandom() 的使用。但由于 getrandom() 是一个系统调用,我们应该能够使用auditctl 揭示它的使用

[root@metrics-d02 vagrant]# auditctl -a exit,always -F arch=b64 -S getrandom
[root@metrics-d02 vagrant]# auditctl -l
-a always,exit -F arch=b64 -S getrandom
[root@metrics-d02 vagrant]# tail -F -n0 /var/log/audit/audit.log 
... (now we wait)

我感到无聊,通过 ssh 进入盒子,我看到了很多有趣的很酷的东西,但没有 getrandom(),这应该不足为奇,因为我们之前看到它使用 /dev/urandom API。

因此,试图解释图表中的凹陷,没有任何东西打开 /dev/*random,并且没有任何打开它的东西当前正在使用它,并且似乎没有任何东西在调用 getrandom()...是否还有其他东西可以使用 [/dev/random 后面的池] 中的数据吗?那么内核呢?考虑地址空间布局随机化 (ASLR) 等功能:

https://access.redhat.com/solutions/44460 [需要订阅]

[root@metrics-d02 vagrant]# cat /proc/sys/kernel/randomize_va_space 
2

这里的“2”意味着除了随机化 mmap 和堆栈(等)等内容的加载位置之外,它还将启用堆随机化。如果我们关闭它会发生什么

[root@metrics-d02 vagrant]# echo 0 > /proc/sys/kernel/randomize_va_space
[root@metrics-d02 vagrant]# cat /proc/sys/kernel/randomize_va_space 
0

(答案:同样的事情......也许其他人可以进一步说明这一点)

内核也将是设置 AT_RANDOM 的地方。这是一个简单的示例,您可以使用 strace 观察它没有调用 /dev/*random 或 getrandom()

[vagrant@metrics-d02 ~]$ cat at_random.c 
#include <stdio.h>
#include <stdint.h>
#include <sys/auxv.h>

#define AT_RANDOM_LEN 16

int main(int argc, char *argv[])
{
    uintptr_t at_random;
    int i;

    at_random = getauxval(AT_RANDOM);

    for (i=0; i<AT_RANDOM_LEN; i++) {
        printf("%02x", ((uint8_t *)at_random)[i]);
    }
    printf("\n");

    /* show that it's a one-time thing */

    for (i=0; i<AT_RANDOM_LEN; i++) {
        printf("%02x", ((uint8_t *)at_random)[i]);
    }
    printf("\n");
}
[vagrant@metrics-d02 ~]$ make at_random
cc     at_random.c   -o at_random
[vagrant@metrics-d02 ~]$ ./at_random 
255f8d5711b9aecf9b5724aa53bc968b
255f8d5711b9aecf9b5724aa53bc968b
[vagrant@metrics-d02 ~]$ ./at_random 
ef4b25faf9f435b3a879a17d0f5c1a62
ef4b25faf9f435b3a879a17d0f5c1a62

希望这有用。

实际上,我首先会关注 Java 工作负载,因为这通常是我最受困扰的地方。看https://blogs.oracle.com/luzmestre/why-does-my-weblogic-server-takes-a-long-time-to-start举个例子。

相关内容