中断&内核熵池 entropy pool

注册一个中断处理函数

驱动程序可以通过 request_irq() 注册一个中断处理函数,并且激活给定的中断线,以处理中断。

int request_irq(unsigned int irq,
                irq_handler_t handler,
                unsigned long flags,
                const char *name,
                void *dev);

第三个参数 flags :

 *	Flags:
 *
 *	SA_SHIRQ		Interrupt is shared
 *
 *	SA_INTERRUPT		Disable local interrupts while processing
 *
 *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy

       

当设置为 IRQF_SAMPLE_RANDOM(SA_SAMPLE_RANDOM) 时,表明这个设备产生的中断对内核熵池有贡献。内核熵池负责提供从各种随机事件导出的真正随机数。

Linux内核采用熵来描述数据的随机性。熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大。

计算机本身是可预测的系统,因此,用计算机算法不可能产生真正的随机数。但是机器的环境中充满了各种各样的噪声,如硬件设备发生中断的时间,用户点击鼠标的时间间隔等是完全随机的,事先无法预测。Linux内核实现的随机数产生器正是利用系统中的这些随机噪声来产生高质量随机数序列

内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。

设计与实现

Linux 内核随机数产生器在/drivers/char/random.c中作为字符设备实现。

static struct entropy_store *random_state; /* The default global store */
static struct entropy_store *sec_random_state; /* secondary store */
static struct entropy_store *urandom_state; /* For urandom */

static int __init rand_initialize(void)
{
	int i;

	if (create_entropy_store(DEFAULT_POOL_SIZE, "primary", &random_state))
		goto err;
	if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state))
		goto err;
	if (create_entropy_store(SECONDARY_POOL_SIZE, "secondary",
				 &sec_random_state))
		goto err;
	if (create_entropy_store(SECONDARY_POOL_SIZE, "urandom",
				 &urandom_state))
		goto err;
	clear_entropy_store(random_state);
	clear_entropy_store(sec_random_state);
	clear_entropy_store(urandom_state);
	init_std_data(random_state);
	init_std_data(sec_random_state);
	init_std_data(urandom_state);
#ifdef CONFIG_SYSCTL
	sysctl_init_random(random_state);
#endif
	for (i = 0; i < NR_IRQS; i++)
		irq_timer_state[i] = NULL;
	memset(&input_timer_state, 0, sizeof(struct timer_rand_state));
	memset(&extract_timer_state, 0, sizeof(struct timer_rand_state));
	extract_timer_state.dont_count_entropy = 1;
	return 0;
err:
	return -1;
}
module_init(rand_initialize);

创建熵池

在模块初始化函数rand_initialize()中调用 create_entropy_store()分别创建名为random_state的缺省熵池,一个名为sec_random_state和一个名为 urandom_state的熵池。

获取系统环境的噪声数据,并加入熵池

熵池用struct entropy_store来表示。内核实现了一系列接口函数用于获取系统环境的噪声数据,并加入熵池,分别是:

void add_interrupt_randomness(int irq);
void add_keyboard_randomness(unsigned char scancode);
void add_mouse_randomness(__u32 mouse_data);
void add_disk_randomness(struct gendisk *disk);

其中add_interrupt_randomness()函数利用设备两次中断的间隔时间作为噪声源将随机数据加入熵池。要使设备的中断作为系统噪声,必须用SA_SAMPLE_RANDOM标志注册其中断服务程序。这样,每当设备发生中断时,中断系统会自动调用add_interrupt_randomness()将熵加入熵池。

add_keyboard_randomness()将按键的扫描码和两次按键之间的时间间隔作为噪声源;而add_mouse_randomness()则利用鼠标位置和连续两次鼠标中断时间间隔填充熵池;最后 add_disk_randomness()函数则以连续两次磁盘操作之间的间隔产生随机数。

将熵加入熵池

上面的函数最终都是通过调用 add_timer_randomness()函数将熵加入熵池的。Add_timer_randomness()首先估算所加数据的熵,再调用 batch_entropy_store()函数将数据加入熵池。为了避免中断的延迟过长影响系统性能,batch_entropy_store()并不直接将熵加入熵池,而是将其加入队列中。当队列长度达到一定长度后,由keventd内核线程通过调用batch_entropy_process()函数将队列中的熵加入池中。

当系统启动的时候,由于启动过程是个确定的可预测的过程,这种情况下,熵池的熵值将非常小,导致产生的随机数序列质量下降,从而给攻击者破解的可能。

为了克服系统启动过程的可预测性带来的影响,Linux操作系统在系统关机的时候保存当前熵池的内容,当系统下次启动的时候恢复上次关机时熵池的数据,这样就有效增加了熵池的熵估算值,避免了随机数序列质量的下降。

你可能感兴趣的:(linux,运维,服务器)