linux加密框架 crypto 算法管理 - 算法检测

参考链接

函数介绍

  • 如前所述,无论是静态算法还是动态算法,算法注册的最后一步都是进行算法正确性检验,一般流程是先调用__crypto_register_alg函数进行通用的算法注册即将待注册的算法添加到算法管理链表中),同时创建对应的检测用算法幼虫,然后调用crypto_wait_for_test函数启动算法正确性检验,并等待检验结束
  • 简单地说,算法正确性检验就是利用样本数据sampledata对算法接口进行计算正确性的验证。算法通过正确性检验的标志是算法标志cra_flags中置算法已检测标志CRYPTO_ALG_TESTED。算法通过正确性检验说明能够提供正常的服务,如加密/解密服务、计算消息摘要服务等。
  • crypto_wait_for_test函数用于启动算法正确性检验,并等待检验结束,输入参数为检测用算法幼虫larval
  • 函数处理流程如下所示。

启动算法检测

static void crypto_wait_for_test(struct crypto_larval *larval)
{
	int err;

	err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult);
	if (err != NOTIFY_STOP) {
		if (WARN_ON(err != NOTIFY_DONE))
			goto out;
		crypto_alg_tested(larval->alg.cra_driver_name, 0);
	}

	err = wait_for_completion_killable(&larval->completion);
	WARN_ON(err);
	if (!err)
		crypto_notify(CRYPTO_MSG_ALG_LOADED, larval);

out:
	crypto_larval_kill(&larval->alg);
}
  • 1)在crypto_wait_for_test函数中,调用crypto_probing_notify函数在加密通知链上发布算法正确性检验CRYPTO_MSG_ALG_REGISTER)的通知,携带的参数为检测用算法幼虫对应的算法成虫,即待检验的算法。
  • 2)静态算法(如AES算法)注册发布算法检验通知时,算法管理链表如下所示,其中aes_larval_t表示检测用算法幼虫,关联到对应的算法成虫(aes_larval_t->adult=aes_alg)。 

算法管理链表

  • 3)动态算法(如"cbc(aes)"算法)注册发布算法检验通知时,算法管理链表如下所示,其中cbc_aes_larval_r表示注册用算法幼虫,cbc_aes_larval_t表示检测用算法幼虫,注册用算法幼虫还未关联到算法成虫,检测用算法幼虫关联到算法成虫(cbc_aes_larval_t->adult=cbc_aes_alg)。 

算法管理链表

算法检测启动

static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
			    void *data)
{
	switch (msg) {
	case CRYPTO_MSG_ALG_REQUEST:
		return cryptomgr_schedule_probe(data);
	case CRYPTO_MSG_ALG_REGISTER:
		return cryptomgr_schedule_test(data);
	case CRYPTO_MSG_ALG_LOADED:
		break;
	}

	return NOTIFY_DONE;
}

static int cryptomgr_schedule_test(struct crypto_alg *alg)
{
	struct task_struct *thread;
	struct crypto_test_param *param;
	u32 type;

	if (!try_module_get(THIS_MODULE))
		goto err;

	param = kzalloc(sizeof(*param), GFP_KERNEL);
	if (!param)
		goto err_put_module;

	memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver));
	memcpy(param->alg, alg->cra_name, sizeof(param->alg));
	type = alg->cra_flags;

	/* Do not test internal algorithms. */
	if (type & CRYPTO_ALG_INTERNAL)
		type |= CRYPTO_ALG_TESTED;

	param->type = type;

	thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
	if (IS_ERR(thread))
		goto err_free_param;

	return NOTIFY_STOP;

err_free_param:
	kfree(param);
err_put_module:
	module_put(THIS_MODULE);
err:
	return NOTIFY_OK;
}
  • cryptomgr_schedule_test函数输入参数为待检测的算法alg,通过创建专门的算法检测线程处理算法正确性检验
  • 处理流程如下所示

启动算法检测

struct crypto_test_param {
	char driver[CRYPTO_MAX_ALG_NAME];
	char alg[CRYPTO_MAX_ALG_NAME];
	u32 type;
};

参数介绍

  • 如上所示,算法正确性检验的参数包括算法驱动名driver、算法名alg和算法类型type。
  • 2)cryptomgr_schedule_test函数将创建名为"cryptomgr_test"的内核线程(即算法检验线程)处理算法正确性检验,处理接口为cryptomgr_test。

	thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
	if (IS_ERR(thread))
		goto err_free_param;

	return NOTIFY_STOP;
  • 3)在cryptomgr_test函数中,调用alg_test函数根据算法驱动名driver、算法名alg和算法类型type实现算法正确性检验。
  • err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED);
static int cryptomgr_test(void *data)
{
	struct crypto_test_param *param = data;
	u32 type = param->type;
	int err = 0;

#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
	goto skiptest;
#endif

	if (type & CRYPTO_ALG_TESTED)
		goto skiptest;

	err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED);

skiptest:
	crypto_alg_tested(param->driver, err);

	kfree(param);
	module_put_and_exit(0);
}

static int cryptomgr_schedule_test(struct crypto_alg *alg)
{
	struct task_struct *thread;
	struct crypto_test_param *param;
	u32 type;

	if (!try_module_get(THIS_MODULE))
		goto err;

	param = kzalloc(sizeof(*param), GFP_KERNEL);
	if (!param)
		goto err_put_module;

	memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver));
	memcpy(param->alg, alg->cra_name, sizeof(param->alg));
	type = alg->cra_flags;

	/* Do not test internal algorithms. */
	if (type & CRYPTO_ALG_INTERNAL)
		type |= CRYPTO_ALG_TESTED;

	param->type = type;

	thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
	if (IS_ERR(thread))
		goto err_free_param;

	return NOTIFY_STOP;

err_free_param:
	kfree(param);
err_put_module:
	module_put(THIS_MODULE);
err:
	return NOTIFY_OK;
}

算法检测结束

void crypto_alg_tested(const char *name, int err)
{
	struct crypto_larval *test;
	struct crypto_alg *alg;
	struct crypto_alg *q;
	LIST_HEAD(list);
	bool best;

	down_write(&crypto_alg_sem);
	list_for_each_entry(q, &crypto_alg_list, cra_list) {
		if (crypto_is_moribund(q) || !crypto_is_larval(q))
			continue;

		test = (struct crypto_larval *)q;

		if (!strcmp(q->cra_driver_name, name))
			goto found;
	}

	pr_err("alg: Unexpected test result for %s: %d\n", name, err);
	goto unlock;

found:
	q->cra_flags |= CRYPTO_ALG_DEAD;
	alg = test->adult;
	if (err || list_empty(&alg->cra_list))
		goto complete;

	alg->cra_flags |= CRYPTO_ALG_TESTED;

	/* Only satisfy larval waiters if we are the best. */
	best = true;
	list_for_each_entry(q, &crypto_alg_list, cra_list) {
		if (crypto_is_moribund(q) || !crypto_is_larval(q))
			continue;

		if (strcmp(alg->cra_name, q->cra_name))
			continue;

		if (q->cra_priority > alg->cra_priority) {
			best = false;
			break;
		}
	}

	list_for_each_entry(q, &crypto_alg_list, cra_list) {
		if (q == alg)
			continue;

		if (crypto_is_moribund(q))
			continue;

		if (crypto_is_larval(q)) {
			struct crypto_larval *larval = (void *)q;

			/*
			 * Check to see if either our generic name or
			 * specific name can satisfy the name requested
			 * by the larval entry q.
			 */
			if (strcmp(alg->cra_name, q->cra_name) &&
			    strcmp(alg->cra_driver_name, q->cra_name))
				continue;

			if (larval->adult)
				continue;
			if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
				continue;

			if (best && crypto_mod_get(alg))
				larval->adult = alg;
			else
				larval->adult = ERR_PTR(-EAGAIN);

			continue;
		}

		if (strcmp(alg->cra_name, q->cra_name))
			continue;

		if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
		    q->cra_priority > alg->cra_priority)
			continue;

		crypto_remove_spawns(q, &list, alg);
	}

complete:
	complete_all(&test->completion);

unlock:
	up_write(&crypto_alg_sem);

	crypto_remove_final(&list);
}
EXPORT_SYMBOL_GPL(crypto_alg_tested);
  • crypto_alg_tested函数输入参数包括算法驱动名name和检验结果err(为0表示检验正确,非0表示检验失败),处理流程如下所示。

检测结束收尾流程

  • 1)检测结束收尾时,需要通过算法幼虫的完成量唤醒等待注册、检验结束的线程。
  • 在crypto_alg_tested函数中,首先根据输入的算法驱动名name查找对应的检测用算法幼虫test,如下所示。
test = (struct crypto_larval *)q;

if (!strcmp(q->cra_driver_name, name))
	goto found;
  • 然后根据检测用算法幼虫test关联到算法成虫alg,如果算法检测通过(err=0)则设置算法成功alg的已检验标志 CRYPTO_ALG_TESTED,同时将检测用算法幼虫设置为已死亡,表示检测用算法幼虫的使命终结,如下所示。
found:
	q->cra_flags |= CRYPTO_ALG_DEAD;
	alg = test->adult;
	if (err || list_empty(&alg->cra_list))
		goto complete;

	alg->cra_flags |= CRYPTO_ALG_TESTED;
  • 再根据算法成虫alg查找对应的注册用算法幼虫larval,并进行关联,通过注册用算法幼虫唤醒所有等待注册结束的线程,如下所示。

  • 与目前版本V5.15.11存在差异 

  • 2)算法检验结束收尾时,算法管理链表如下所示。

算法管理链表

  • 注意:算法检验收尾时,只是通过注册用和检验用算法幼虫唤醒等待算法注册完成的线程,并不清理注册过程中的中间变量(即注册用和检验用算法幼虫) 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值