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

为什么 /dev/urandom 中的 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

在这种情况下,仅存储 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

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

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

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

我猜文档暗示存在某种最大读取大小urandom

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

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

答案1

如果你检查从 /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.

所以如果你添加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

这实际上得到了确认dd,如果您省略iflag并增加读取的计数32,即大致的字节数32 x 33554431(或乘法后缀上的每个页面部分),它将输出一个简短的警告:= 10737417921G1.1GBdd 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

答案2

我以前没有意识到 urandom 的这种奇怪之处,但是你遇到了 dd 的“短读”。看:

dd什么时候适合复制数据? (或者,什么时候 read() 和 write() 是部分的)

在第一个示例中,您所做的是要求内核在一次 read() 调用中使用随机数据填充 1GB 内存。由于内存是延迟分配的,因此您实质上是要求内核在第一次调用时向您的进程分配 1GB 内存。他们提早停止的原因可能有很多。另外,如果它按照您的要求进行操作,您可能会耗尽内存,具体取决于您正在尝试的系统。

哦,我怀疑这和你的熵池有什么关系。 urandom 很有用,因为即使熵池耗尽,它也会继续返回数据。

相关内容