为什么来自 /dev/urandom 的 dd 提前停止?

mal*_*lat 14 dd

在我当前的 Linux 系统(Debian Jessie amd64)上,我的dd使用行为有所不同/dev/urandom/dev/random行为已正确记录)。如果我天真地想要 1G 的随机数据:

$ dd if=/dev/urandom of=random.raw bs=1G count=1
0+1 records in
0+1 records out
33554431 bytes (34 MB) copied, 2.2481 s, 14.9 MB/s
$ echo $?
0
Run Code Online (Sandbox Code Playgroud)

在这种情况下,只存储了 34MB 的随机数据,而如果我使用多次读取:

$ dd if=/dev/urandom of=random.raw bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 70.4749 s, 14.9 MB/s
Run Code Online (Sandbox Code Playgroud)

然后我正确地得到了我的 1G 随机数据。

的文档/dev/urandom相当难以捉摸:

从 /dev/urandom 设备读取不会阻塞等待更多熵。因此,如果熵池中没有足够的熵,则返回值理论上容易受到对驱动程序使用的算法的加密攻击。当前未分类的文献中没有关于如何做到这一点的知识,但理论上可能存在这种攻击。如果这是您的应用程序中的一个问题,请改用 /dev/random。

我猜文档暗示urandom.

我还猜测我的系统上熵池的大小是 34MB,这可以解释为什么read1G 中的第一个失败了大约 34MB。

但我的问题是我怎么知道我的熵池的大小?或者被dd另一个因素阻止(与urandom?相关的某种计时问题)。

don*_*sti 18

如果您检查从 /dev/urandom 读取在 33554431 字节后给出 EOF并遵循讨论,它会指向另一个错误报告,其中 Ted Tso 指出...

...提交 79a8468747c5 导致读取大于 32MB 导致 read(2) 系统调用仅返回 32MB。也就是说,它会导致短读。POSIX 总是允许短读(2),任何程序都必须检查短读。

dd 的问题在于 POSIX 要求 count=X 参数基于读取,而不是基于字节。这可以通过 iflag=fullblock 更改。

根据gnu dd 手册

Note if the input may return short reads as could be the case when reading from
a pipe for example, ‘iflag=fullblock’ will ensure that ‘count=’ corresponds to
complete input blocks rather than the traditional POSIX specified behavior of
counting input read operations.
Run Code Online (Sandbox Code Playgroud)

所以如果你添加iflag=fullblock

dd if=/dev/urandom of=random.raw bs=1G count=1 iflag=fullblock
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB) copied, 65.3591 s, 16.4 MB/s
Run Code Online (Sandbox Code Playgroud)

这实际上由 确认dd,如果您省略iflag并增加32读取计数,即大致32 x 33554431字节= 1073741792字节1G(或1.1GB根据dd man乘法后缀的每个页面部分),它将输出一个简短的警告:

dd if=/dev/urandom of=random.raw bs=1G count=32
dd: warning: partial read (33554431 bytes); suggest iflag=fullblock
0+32 records in
0+32 records out
1073741792 bytes (1.1 GB) copied, 59.6676 s, 18.0 MB/s
Run Code Online (Sandbox Code Playgroud)