我有一个MIPSELCI20 开发板那是遭受熵耗竭。该板具有带有硬件 rng 的 JZ4780 SoC(寄存器映射在地址 0x100000DC)。这君正驱动程序出现问题,所以我编写了一个用户层程序来读取寄存器并补充池。
运行程序后我观察到:
$ sudo ./ci20-rng.exe && for((i=1;i<=20;i+=1)); do (cat /proc/sys/kernel/random/entropy_avail; sleep 5); done
3968
3712
3456
3200
2944
2688
2432
2176
1920
1664
1408
1152
896
640
384
128
128
...
类似的问题是是什么在不断消耗熵?排水沟的解释基本上是有道理的。考虑到这些解释,我认为它发生的速度太快了。但看起来排水量应该继续为 0,而不是稳定在 160 或 128 左右。
为什么entropy_avail
稳定在160或128左右?
下面的程序使用ioctl(fd, RNDADDENTROPY, &entropy)
,其中fd
是 的描述符/dev/random
。entropy
是预期的结构:
typedef struct {
int bit_count;
int byte_count;
unsigned char buf[4096];
} entropy_t;
控制寄存器 (*ctrl = 0x00
和*ctrl = 0x01
) 的切换和随后的延迟是由于读取JZ4780程序员手册。这个想法是写入 SC-ROM 控制器,但将其推高不到 1 秒,因为“...对 VDDQ 的最大 2.5V 供电时间必须严格控制在 1 秒以内”。我希望我没有把它搞得太严重或者误读它。
这是程序:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/random.h>
typedef struct {
int bit_count; /* number of bits of entropy in data */
int byte_count; /* number of bytes of data in array */
unsigned char buf[4096];
} entropy_t;
static int print_only;
/* gcc -g2 -O2 -std=c99 ci20-rng.c -o ci20-rng.exe */
int main(int argc, char* argv[])
{
int ret = 1, fd1 = -1, fd2 = -1, fd3 = -1;
void *map1 = MAP_FAILED, *map2 = MAP_FAILED;
const int PAGE_SIZE = sysconf(_SC_PAGESIZE);
const int PAGE_MASK = ~(PAGE_SIZE - 1);
#define CTRL_ADDR 0x100000D8
#define DATA_ADDR 0x100000DC
if(argc >= 2)
{
if(0 == strcmp(argv[1], "-p") || 0 == strcmp(argv[1], "/p") || 0 == strcmp(argv[1], "--print"))
print_only = 1;
}
fd1 = open("/dev/mem", O_RDWR | O_SYNC);
if(fd1 == -1)
{
fprintf(stderr, "Failed to open /dev/mem for reading and writing (error %d)\n", errno);
goto cleanup;
}
fd2 = open("/dev/mem", O_RDONLY | O_SYNC);
if(fd2 == -1)
{
fprintf(stderr, "Failed to open /dev/mem for reading (error %d)\n", errno);
goto cleanup;
}
fd3 = open("/dev/random", O_RDWR);
if(fd3 == -1)
{
fprintf(stderr, "Failed to open /dev/random for writing (error %d)\n", errno);
goto cleanup;
}
map1 = mmap (NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, CTRL_ADDR & PAGE_MASK);
if(map1 == MAP_FAILED)
{
fprintf(stderr, "Failed to map 0x100000D8 for control (error %d)\n", errno);
goto cleanup;
}
map2 = mmap (NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd2, DATA_ADDR & PAGE_MASK);
if(map2 == MAP_FAILED)
{
fprintf(stderr, "Failed to map 0x100000DC for data (error %d)\n", errno);
goto cleanup;
}
const int off1 = CTRL_ADDR % PAGE_SIZE;
volatile uint32_t* volatile ctrl = (uint32_t*)((uint8_t*)map1+off1);
const int off2 = DATA_ADDR % PAGE_SIZE;
volatile uint32_t* volatile data = (uint32_t*)((uint8_t*)map2+off2);
entropy_t entropy = { .bit_count = 4096*8, .byte_count = 4096 };
int count = 4096/4, idx = 0;
while(count--)
{
/* If the delay from the loop drops too low, then we */
/* can watch the random values being shifted in. */
#define DELAY 5000
*ctrl = 0x01;
for(unsigned int i = 0; i < DELAY; i++) {
volatile uint32_t unused = *ctrl;
}
if(!print_only)
{
memcpy(entropy.buf+idx, (const void *)data, 4);
idx += 4;
}
else
{
if(isatty(fileno(stdout)))
fprintf(stdout, "0x%08x\n", *data);
else
write(fileno(stdout), (const void *)data, 4);
}
*ctrl = 0x00;
for(unsigned int i = 0; i < DELAY; i++) {
volatile uint32_t unused = *ctrl;
}
}
if(!print_only)
{
int rc = ioctl(fd3, RNDADDENTROPY, &entropy);
if(rc != 0)
{
fprintf(stderr, "Failed to add entropy (error %d)\n", errno);
goto cleanup;
}
}
ret = 0;
cleanup:
if(map2 != MAP_FAILED) { munmap(map2, PAGE_SIZE); }
if(map1 != MAP_FAILED) { munmap(map1, PAGE_SIZE); }
if(fd3 != -1) { close(fd3); }
if(fd2 != -1) { close(fd2); }
if(fd1 != -1) { close(fd1); }
return ret;
}
答案1
我猜想设备会改变(削弱?)生成“随机”数据的算法,这样你就不会完全用完。也就是说,忽略“真实”随机数据并依赖 CSPNRG。
我刚刚问了一个相关的问题,然后在手册页上找到了答案rngd
:
该rnd-tools
服务调用该程序/usr/sbin/rngd
。向上看Ubuntu 文档可以看到有一个参数:
-W n, --fill-watermark=nnn
一旦我们开始这样做,将熵提供给随机设备直到至少填充水印 熵池中有可用的熵位(默认值:2048)。设置得太高会导致
rngd
来支配熵池的内容。低值会在熵匮乏期间损害系统性能。不设置 填充水印高于熵池的大小(通常为 4096 位)。
我的问题/答案在这里。