Commit f4f5d7cf authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull virtio updates from Michael Tsirkin:

 - vdpa generic device type support

 - more virtio hardening for broken devices (but on the same theme,
   revert some virtio hotplug hardening patches - they were misusing
   some interrupt flags and had to be reverted)

 - RSS support in virtio-net

 - max device MTU support in mlx5 vdpa

 - akcipher support in virtio-crypto

 - shared IRQ support in ifcvf vdpa

 - a minor performance improvement in vhost

 - enable virtio mem for ARM64

 - beginnings of advance dma support

 - cleanups, fixes all over the place

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost: (33 commits)
  vdpa/mlx5: Avoid processing works if workqueue was destroyed
  vhost: handle error while adding split ranges to iotlb
  vdpa: support exposing the count of vqs to userspace
  vdpa: change the type of nvqs to u32
  vdpa: support exposing the config size to userspace
  vdpa/mlx5: re-create forwarding rules after mac modified
  virtio: pci: check bar values read from virtio config space
  Revert "virtio_pci: harden MSI-X interrupts"
  Revert "virtio-pci: harden INTX interrupts"
  drivers/net/virtio_net: Added RSS hash report control.
  drivers/net/virtio_net: Added RSS hash report.
  drivers/net/virtio_net: Added basic RSS support.
  drivers/net/virtio_net: Fixed padded vheader to use v1 with hash.
  virtio: use virtio_device_ready() in virtio_device_restore()
  tools/virtio: compile with -pthread
  tools/virtio: fix after premapped buf support
  virtio_ring: remove flags check for unmap packed indirect desc
  virtio_ring: remove flags check for unmap split indirect desc
  virtio_ring: rename vring_unmap_state_packed() to vring_unmap_extra_packed()
  net/mlx5: Add support for configuring max device MTU
  ...
parents e729dbe8 ad6dc1da
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -3,8 +3,11 @@ config CRYPTO_DEV_VIRTIO
	tristate "VirtIO crypto driver"
	tristate "VirtIO crypto driver"
	depends on VIRTIO
	depends on VIRTIO
	select CRYPTO_AEAD
	select CRYPTO_AEAD
	select CRYPTO_AKCIPHER2
	select CRYPTO_SKCIPHER
	select CRYPTO_SKCIPHER
	select CRYPTO_ENGINE
	select CRYPTO_ENGINE
	select CRYPTO_RSA
	select MPILIB
	help
	help
	  This driver provides support for virtio crypto device. If you
	  This driver provides support for virtio crypto device. If you
	  choose 'M' here, this module will be called virtio_crypto.
	  choose 'M' here, this module will be called virtio_crypto.
+2 −1
Original line number Original line Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio_crypto.o
obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio_crypto.o
virtio_crypto-objs := \
virtio_crypto-objs := \
	virtio_crypto_algs.o \
	virtio_crypto_skcipher_algs.o \
	virtio_crypto_akcipher_algs.o \
	virtio_crypto_mgr.o \
	virtio_crypto_mgr.o \
	virtio_crypto_core.o
	virtio_crypto_core.o
+585 −0
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
 /* Asymmetric algorithms supported by virtio crypto device
  *
  * Authors: zhenwei pi <pizhenwei@bytedance.com>
  *          lei he <helei.sig11@bytedance.com>
  *
  * Copyright 2022 Bytedance CO., LTD.
  */

#include <linux/mpi.h>
#include <linux/scatterlist.h>
#include <crypto/algapi.h>
#include <crypto/internal/akcipher.h>
#include <crypto/internal/rsa.h>
#include <linux/err.h>
#include <crypto/scatterwalk.h>
#include <linux/atomic.h>

#include <uapi/linux/virtio_crypto.h>
#include "virtio_crypto_common.h"

struct virtio_crypto_rsa_ctx {
	MPI n;
};

struct virtio_crypto_akcipher_ctx {
	struct crypto_engine_ctx enginectx;
	struct virtio_crypto *vcrypto;
	struct crypto_akcipher *tfm;
	bool session_valid;
	__u64 session_id;
	union {
		struct virtio_crypto_rsa_ctx rsa_ctx;
	};
};

struct virtio_crypto_akcipher_request {
	struct virtio_crypto_request base;
	struct virtio_crypto_akcipher_ctx *akcipher_ctx;
	struct akcipher_request *akcipher_req;
	void *src_buf;
	void *dst_buf;
	uint32_t opcode;
};

struct virtio_crypto_akcipher_algo {
	uint32_t algonum;
	uint32_t service;
	unsigned int active_devs;
	struct akcipher_alg algo;
};

static DEFINE_MUTEX(algs_lock);

static void virtio_crypto_akcipher_finalize_req(
	struct virtio_crypto_akcipher_request *vc_akcipher_req,
	struct akcipher_request *req, int err)
{
	virtcrypto_clear_request(&vc_akcipher_req->base);

	crypto_finalize_akcipher_request(vc_akcipher_req->base.dataq->engine, req, err);
}

static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request *vc_req, int len)
{
	struct virtio_crypto_akcipher_request *vc_akcipher_req =
		container_of(vc_req, struct virtio_crypto_akcipher_request, base);
	struct akcipher_request *akcipher_req;
	int error;

	switch (vc_req->status) {
	case VIRTIO_CRYPTO_OK:
		error = 0;
		break;
	case VIRTIO_CRYPTO_INVSESS:
	case VIRTIO_CRYPTO_ERR:
		error = -EINVAL;
		break;
	case VIRTIO_CRYPTO_BADMSG:
		error = -EBADMSG;
		break;

	case VIRTIO_CRYPTO_KEY_REJECTED:
		error = -EKEYREJECTED;
		break;

	default:
		error = -EIO;
		break;
	}

	akcipher_req = vc_akcipher_req->akcipher_req;
	if (vc_akcipher_req->opcode != VIRTIO_CRYPTO_AKCIPHER_VERIFY)
		sg_copy_from_buffer(akcipher_req->dst, sg_nents(akcipher_req->dst),
				    vc_akcipher_req->dst_buf, akcipher_req->dst_len);
	virtio_crypto_akcipher_finalize_req(vc_akcipher_req, akcipher_req, error);
}

static int virtio_crypto_alg_akcipher_init_session(struct virtio_crypto_akcipher_ctx *ctx,
		struct virtio_crypto_ctrl_header *header, void *para,
		const uint8_t *key, unsigned int keylen)
{
	struct scatterlist outhdr_sg, key_sg, inhdr_sg, *sgs[3];
	struct virtio_crypto *vcrypto = ctx->vcrypto;
	uint8_t *pkey;
	unsigned int inlen;
	int err;
	unsigned int num_out = 0, num_in = 0;

	pkey = kmemdup(key, keylen, GFP_ATOMIC);
	if (!pkey)
		return -ENOMEM;

	spin_lock(&vcrypto->ctrl_lock);
	memcpy(&vcrypto->ctrl.header, header, sizeof(vcrypto->ctrl.header));
	memcpy(&vcrypto->ctrl.u, para, sizeof(vcrypto->ctrl.u));
	vcrypto->input.status = cpu_to_le32(VIRTIO_CRYPTO_ERR);

	sg_init_one(&outhdr_sg, &vcrypto->ctrl, sizeof(vcrypto->ctrl));
	sgs[num_out++] = &outhdr_sg;

	sg_init_one(&key_sg, pkey, keylen);
	sgs[num_out++] = &key_sg;

	sg_init_one(&inhdr_sg, &vcrypto->input, sizeof(vcrypto->input));
	sgs[num_out + num_in++] = &inhdr_sg;

	err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, num_out, num_in, vcrypto, GFP_ATOMIC);
	if (err < 0)
		goto out;

	virtqueue_kick(vcrypto->ctrl_vq);
	while (!virtqueue_get_buf(vcrypto->ctrl_vq, &inlen) &&
	       !virtqueue_is_broken(vcrypto->ctrl_vq))
		cpu_relax();

	if (le32_to_cpu(vcrypto->input.status) != VIRTIO_CRYPTO_OK) {
		err = -EINVAL;
		goto out;
	}

	ctx->session_id = le64_to_cpu(vcrypto->input.session_id);
	ctx->session_valid = true;
	err = 0;

out:
	spin_unlock(&vcrypto->ctrl_lock);
	kfree_sensitive(pkey);

	if (err < 0)
		pr_err("virtio_crypto: Create session failed status: %u\n",
			le32_to_cpu(vcrypto->input.status));

	return err;
}

static int virtio_crypto_alg_akcipher_close_session(struct virtio_crypto_akcipher_ctx *ctx)
{
	struct scatterlist outhdr_sg, inhdr_sg, *sgs[2];
	struct virtio_crypto_destroy_session_req *destroy_session;
	struct virtio_crypto *vcrypto = ctx->vcrypto;
	unsigned int num_out = 0, num_in = 0, inlen;
	int err;

	spin_lock(&vcrypto->ctrl_lock);
	if (!ctx->session_valid) {
		err = 0;
		goto out;
	}
	vcrypto->ctrl_status.status = VIRTIO_CRYPTO_ERR;
	vcrypto->ctrl.header.opcode = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION);
	vcrypto->ctrl.header.queue_id = 0;

	destroy_session = &vcrypto->ctrl.u.destroy_session;
	destroy_session->session_id = cpu_to_le64(ctx->session_id);

	sg_init_one(&outhdr_sg, &vcrypto->ctrl, sizeof(vcrypto->ctrl));
	sgs[num_out++] = &outhdr_sg;

	sg_init_one(&inhdr_sg, &vcrypto->ctrl_status.status, sizeof(vcrypto->ctrl_status.status));
	sgs[num_out + num_in++] = &inhdr_sg;

	err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, num_out, num_in, vcrypto, GFP_ATOMIC);
	if (err < 0)
		goto out;

	virtqueue_kick(vcrypto->ctrl_vq);
	while (!virtqueue_get_buf(vcrypto->ctrl_vq, &inlen) &&
	       !virtqueue_is_broken(vcrypto->ctrl_vq))
		cpu_relax();

	if (vcrypto->ctrl_status.status != VIRTIO_CRYPTO_OK) {
		err = -EINVAL;
		goto out;
	}

	err = 0;
	ctx->session_valid = false;

out:
	spin_unlock(&vcrypto->ctrl_lock);
	if (err < 0) {
		pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n",
			vcrypto->ctrl_status.status, destroy_session->session_id);
	}

	return err;
}

static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request *vc_akcipher_req,
		struct akcipher_request *req, struct data_queue *data_vq)
{
	struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx;
	struct virtio_crypto_request *vc_req = &vc_akcipher_req->base;
	struct virtio_crypto *vcrypto = ctx->vcrypto;
	struct virtio_crypto_op_data_req *req_data = vc_req->req_data;
	struct scatterlist *sgs[4], outhdr_sg, inhdr_sg, srcdata_sg, dstdata_sg;
	void *src_buf = NULL, *dst_buf = NULL;
	unsigned int num_out = 0, num_in = 0;
	int node = dev_to_node(&vcrypto->vdev->dev);
	unsigned long flags;
	int ret = -ENOMEM;
	bool verify = vc_akcipher_req->opcode == VIRTIO_CRYPTO_AKCIPHER_VERIFY;
	unsigned int src_len = verify ? req->src_len + req->dst_len : req->src_len;

	/* out header */
	sg_init_one(&outhdr_sg, req_data, sizeof(*req_data));
	sgs[num_out++] = &outhdr_sg;

	/* src data */
	src_buf = kcalloc_node(src_len, 1, GFP_KERNEL, node);
	if (!src_buf)
		goto err;

	if (verify) {
		/* for verify operation, both src and dst data work as OUT direction */
		sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len);
		sg_init_one(&srcdata_sg, src_buf, src_len);
		sgs[num_out++] = &srcdata_sg;
	} else {
		sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len);
		sg_init_one(&srcdata_sg, src_buf, src_len);
		sgs[num_out++] = &srcdata_sg;

		/* dst data */
		dst_buf = kcalloc_node(req->dst_len, 1, GFP_KERNEL, node);
		if (!dst_buf)
			goto err;

		sg_init_one(&dstdata_sg, dst_buf, req->dst_len);
		sgs[num_out + num_in++] = &dstdata_sg;
	}

	vc_akcipher_req->src_buf = src_buf;
	vc_akcipher_req->dst_buf = dst_buf;

	/* in header */
	sg_init_one(&inhdr_sg, &vc_req->status, sizeof(vc_req->status));
	sgs[num_out + num_in++] = &inhdr_sg;

	spin_lock_irqsave(&data_vq->lock, flags);
	ret = virtqueue_add_sgs(data_vq->vq, sgs, num_out, num_in, vc_req, GFP_ATOMIC);
	virtqueue_kick(data_vq->vq);
	spin_unlock_irqrestore(&data_vq->lock, flags);
	if (ret)
		goto err;

	return 0;

err:
	kfree(src_buf);
	kfree(dst_buf);

	return -ENOMEM;
}

static int virtio_crypto_rsa_do_req(struct crypto_engine *engine, void *vreq)
{
	struct akcipher_request *req = container_of(vreq, struct akcipher_request, base);
	struct virtio_crypto_akcipher_request *vc_akcipher_req = akcipher_request_ctx(req);
	struct virtio_crypto_request *vc_req = &vc_akcipher_req->base;
	struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx;
	struct virtio_crypto *vcrypto = ctx->vcrypto;
	struct data_queue *data_vq = vc_req->dataq;
	struct virtio_crypto_op_header *header;
	struct virtio_crypto_akcipher_data_req *akcipher_req;
	int ret;

	vc_req->sgs = NULL;
	vc_req->req_data = kzalloc_node(sizeof(*vc_req->req_data),
		GFP_KERNEL, dev_to_node(&vcrypto->vdev->dev));
	if (!vc_req->req_data)
		return -ENOMEM;

	/* build request header */
	header = &vc_req->req_data->header;
	header->opcode = cpu_to_le32(vc_akcipher_req->opcode);
	header->algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA);
	header->session_id = cpu_to_le64(ctx->session_id);

	/* build request akcipher data */
	akcipher_req = &vc_req->req_data->u.akcipher_req;
	akcipher_req->para.src_data_len = cpu_to_le32(req->src_len);
	akcipher_req->para.dst_data_len = cpu_to_le32(req->dst_len);

	ret = __virtio_crypto_akcipher_do_req(vc_akcipher_req, req, data_vq);
	if (ret < 0) {
		kfree_sensitive(vc_req->req_data);
		vc_req->req_data = NULL;
		return ret;
	}

	return 0;
}

static int virtio_crypto_rsa_req(struct akcipher_request *req, uint32_t opcode)
{
	struct crypto_akcipher *atfm = crypto_akcipher_reqtfm(req);
	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(atfm);
	struct virtio_crypto_akcipher_request *vc_akcipher_req = akcipher_request_ctx(req);
	struct virtio_crypto_request *vc_req = &vc_akcipher_req->base;
	struct virtio_crypto *vcrypto = ctx->vcrypto;
	/* Use the first data virtqueue as default */
	struct data_queue *data_vq = &vcrypto->data_vq[0];

	vc_req->dataq = data_vq;
	vc_req->alg_cb = virtio_crypto_dataq_akcipher_callback;
	vc_akcipher_req->akcipher_ctx = ctx;
	vc_akcipher_req->akcipher_req = req;
	vc_akcipher_req->opcode = opcode;

	return crypto_transfer_akcipher_request_to_engine(data_vq->engine, req);
}

static int virtio_crypto_rsa_encrypt(struct akcipher_request *req)
{
	return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_ENCRYPT);
}

static int virtio_crypto_rsa_decrypt(struct akcipher_request *req)
{
	return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_DECRYPT);
}

static int virtio_crypto_rsa_sign(struct akcipher_request *req)
{
	return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_SIGN);
}

static int virtio_crypto_rsa_verify(struct akcipher_request *req)
{
	return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_VERIFY);
}

static int virtio_crypto_rsa_set_key(struct crypto_akcipher *tfm,
				     const void *key,
				     unsigned int keylen,
				     bool private,
				     int padding_algo,
				     int hash_algo)
{
	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);
	struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx;
	struct virtio_crypto *vcrypto;
	struct virtio_crypto_ctrl_header header;
	struct virtio_crypto_akcipher_session_para para;
	struct rsa_key rsa_key = {0};
	int node = virtio_crypto_get_current_node();
	uint32_t keytype;
	int ret;

	/* mpi_free will test n, just free it. */
	mpi_free(rsa_ctx->n);
	rsa_ctx->n = NULL;

	if (private) {
		keytype = VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
		ret = rsa_parse_priv_key(&rsa_key, key, keylen);
	} else {
		keytype = VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
		ret = rsa_parse_pub_key(&rsa_key, key, keylen);
	}

	if (ret)
		return ret;

	rsa_ctx->n = mpi_read_raw_data(rsa_key.n, rsa_key.n_sz);
	if (!rsa_ctx->n)
		return -ENOMEM;

	if (!ctx->vcrypto) {
		vcrypto = virtcrypto_get_dev_node(node, VIRTIO_CRYPTO_SERVICE_AKCIPHER,
						VIRTIO_CRYPTO_AKCIPHER_RSA);
		if (!vcrypto) {
			pr_err("virtio_crypto: Could not find a virtio device in the system or unsupported algo\n");
			return -ENODEV;
		}

		ctx->vcrypto = vcrypto;
	} else {
		virtio_crypto_alg_akcipher_close_session(ctx);
	}

	/* set ctrl header */
	header.opcode =	cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION);
	header.algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA);
	header.queue_id = 0;

	/* set RSA para */
	para.algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA);
	para.keytype = cpu_to_le32(keytype);
	para.keylen = cpu_to_le32(keylen);
	para.u.rsa.padding_algo = cpu_to_le32(padding_algo);
	para.u.rsa.hash_algo = cpu_to_le32(hash_algo);

	return virtio_crypto_alg_akcipher_init_session(ctx, &header, &para, key, keylen);
}

static int virtio_crypto_rsa_raw_set_priv_key(struct crypto_akcipher *tfm,
					      const void *key,
					      unsigned int keylen)
{
	return virtio_crypto_rsa_set_key(tfm, key, keylen, 1,
					 VIRTIO_CRYPTO_RSA_RAW_PADDING,
					 VIRTIO_CRYPTO_RSA_NO_HASH);
}


static int virtio_crypto_p1pad_rsa_sha1_set_priv_key(struct crypto_akcipher *tfm,
						     const void *key,
						     unsigned int keylen)
{
	return virtio_crypto_rsa_set_key(tfm, key, keylen, 1,
					 VIRTIO_CRYPTO_RSA_PKCS1_PADDING,
					 VIRTIO_CRYPTO_RSA_SHA1);
}

static int virtio_crypto_rsa_raw_set_pub_key(struct crypto_akcipher *tfm,
					     const void *key,
					     unsigned int keylen)
{
	return virtio_crypto_rsa_set_key(tfm, key, keylen, 0,
					 VIRTIO_CRYPTO_RSA_RAW_PADDING,
					 VIRTIO_CRYPTO_RSA_NO_HASH);
}

static int virtio_crypto_p1pad_rsa_sha1_set_pub_key(struct crypto_akcipher *tfm,
						    const void *key,
						    unsigned int keylen)
{
	return virtio_crypto_rsa_set_key(tfm, key, keylen, 0,
					 VIRTIO_CRYPTO_RSA_PKCS1_PADDING,
					 VIRTIO_CRYPTO_RSA_SHA1);
}

static unsigned int virtio_crypto_rsa_max_size(struct crypto_akcipher *tfm)
{
	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);
	struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx;

	return mpi_get_size(rsa_ctx->n);
}

static int virtio_crypto_rsa_init_tfm(struct crypto_akcipher *tfm)
{
	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);

	ctx->tfm = tfm;
	ctx->enginectx.op.do_one_request = virtio_crypto_rsa_do_req;
	ctx->enginectx.op.prepare_request = NULL;
	ctx->enginectx.op.unprepare_request = NULL;

	return 0;
}

static void virtio_crypto_rsa_exit_tfm(struct crypto_akcipher *tfm)
{
	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);
	struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx;

	virtio_crypto_alg_akcipher_close_session(ctx);
	virtcrypto_dev_put(ctx->vcrypto);
	mpi_free(rsa_ctx->n);
	rsa_ctx->n = NULL;
}

static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = {
	{
		.algonum = VIRTIO_CRYPTO_AKCIPHER_RSA,
		.service = VIRTIO_CRYPTO_SERVICE_AKCIPHER,
		.algo = {
			.encrypt = virtio_crypto_rsa_encrypt,
			.decrypt = virtio_crypto_rsa_decrypt,
			.set_pub_key = virtio_crypto_rsa_raw_set_pub_key,
			.set_priv_key = virtio_crypto_rsa_raw_set_priv_key,
			.max_size = virtio_crypto_rsa_max_size,
			.init = virtio_crypto_rsa_init_tfm,
			.exit = virtio_crypto_rsa_exit_tfm,
			.reqsize = sizeof(struct virtio_crypto_akcipher_request),
			.base = {
				.cra_name = "rsa",
				.cra_driver_name = "virtio-crypto-rsa",
				.cra_priority = 150,
				.cra_module = THIS_MODULE,
				.cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx),
			},
		},
	},
	{
		.algonum = VIRTIO_CRYPTO_AKCIPHER_RSA,
		.service = VIRTIO_CRYPTO_SERVICE_AKCIPHER,
		.algo = {
			.encrypt = virtio_crypto_rsa_encrypt,
			.decrypt = virtio_crypto_rsa_decrypt,
			.sign = virtio_crypto_rsa_sign,
			.verify = virtio_crypto_rsa_verify,
			.set_pub_key = virtio_crypto_p1pad_rsa_sha1_set_pub_key,
			.set_priv_key = virtio_crypto_p1pad_rsa_sha1_set_priv_key,
			.max_size = virtio_crypto_rsa_max_size,
			.init = virtio_crypto_rsa_init_tfm,
			.exit = virtio_crypto_rsa_exit_tfm,
			.reqsize = sizeof(struct virtio_crypto_akcipher_request),
			.base = {
				.cra_name = "pkcs1pad(rsa,sha1)",
				.cra_driver_name = "virtio-pkcs1-rsa-with-sha1",
				.cra_priority = 150,
				.cra_module = THIS_MODULE,
				.cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx),
			},
		},
	},
};

int virtio_crypto_akcipher_algs_register(struct virtio_crypto *vcrypto)
{
	int ret = 0;
	int i = 0;

	mutex_lock(&algs_lock);

	for (i = 0; i < ARRAY_SIZE(virtio_crypto_akcipher_algs); i++) {
		uint32_t service = virtio_crypto_akcipher_algs[i].service;
		uint32_t algonum = virtio_crypto_akcipher_algs[i].algonum;

		if (!virtcrypto_algo_is_supported(vcrypto, service, algonum))
			continue;

		if (virtio_crypto_akcipher_algs[i].active_devs == 0) {
			ret = crypto_register_akcipher(&virtio_crypto_akcipher_algs[i].algo);
			if (ret)
				goto unlock;
		}

		virtio_crypto_akcipher_algs[i].active_devs++;
		dev_info(&vcrypto->vdev->dev, "Registered akcipher algo %s\n",
			 virtio_crypto_akcipher_algs[i].algo.base.cra_name);
	}

unlock:
	mutex_unlock(&algs_lock);
	return ret;
}

void virtio_crypto_akcipher_algs_unregister(struct virtio_crypto *vcrypto)
{
	int i = 0;

	mutex_lock(&algs_lock);

	for (i = 0; i < ARRAY_SIZE(virtio_crypto_akcipher_algs); i++) {
		uint32_t service = virtio_crypto_akcipher_algs[i].service;
		uint32_t algonum = virtio_crypto_akcipher_algs[i].algonum;

		if (virtio_crypto_akcipher_algs[i].active_devs == 0 ||
		    !virtcrypto_algo_is_supported(vcrypto, service, algonum))
			continue;

		if (virtio_crypto_akcipher_algs[i].active_devs == 1)
			crypto_unregister_akcipher(&virtio_crypto_akcipher_algs[i].algo);

		virtio_crypto_akcipher_algs[i].active_devs--;
	}

	mutex_unlock(&algs_lock);
}
+5 −2
Original line number Original line Diff line number Diff line
@@ -56,6 +56,7 @@ struct virtio_crypto {
	u32 mac_algo_l;
	u32 mac_algo_l;
	u32 mac_algo_h;
	u32 mac_algo_h;
	u32 aead_algo;
	u32 aead_algo;
	u32 akcipher_algo;


	/* Maximum length of cipher key */
	/* Maximum length of cipher key */
	u32 max_cipher_key_len;
	u32 max_cipher_key_len;
@@ -129,7 +130,9 @@ static inline int virtio_crypto_get_current_node(void)
	return node;
	return node;
}
}


int virtio_crypto_algs_register(struct virtio_crypto *vcrypto);
int virtio_crypto_skcipher_algs_register(struct virtio_crypto *vcrypto);
void virtio_crypto_algs_unregister(struct virtio_crypto *vcrypto);
void virtio_crypto_skcipher_algs_unregister(struct virtio_crypto *vcrypto);
int virtio_crypto_akcipher_algs_register(struct virtio_crypto *vcrypto);
void virtio_crypto_akcipher_algs_unregister(struct virtio_crypto *vcrypto);


#endif /* _VIRTIO_CRYPTO_COMMON_H */
#endif /* _VIRTIO_CRYPTO_COMMON_H */
+5 −1
Original line number Original line Diff line number Diff line
@@ -297,6 +297,7 @@ static int virtcrypto_probe(struct virtio_device *vdev)
	u32 mac_algo_l = 0;
	u32 mac_algo_l = 0;
	u32 mac_algo_h = 0;
	u32 mac_algo_h = 0;
	u32 aead_algo = 0;
	u32 aead_algo = 0;
	u32 akcipher_algo = 0;
	u32 crypto_services = 0;
	u32 crypto_services = 0;


	if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
	if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
@@ -348,6 +349,9 @@ static int virtcrypto_probe(struct virtio_device *vdev)
			mac_algo_h, &mac_algo_h);
			mac_algo_h, &mac_algo_h);
	virtio_cread_le(vdev, struct virtio_crypto_config,
	virtio_cread_le(vdev, struct virtio_crypto_config,
			aead_algo, &aead_algo);
			aead_algo, &aead_algo);
	if (crypto_services & (1 << VIRTIO_CRYPTO_SERVICE_AKCIPHER))
		virtio_cread_le(vdev, struct virtio_crypto_config,
				akcipher_algo, &akcipher_algo);


	/* Add virtio crypto device to global table */
	/* Add virtio crypto device to global table */
	err = virtcrypto_devmgr_add_dev(vcrypto);
	err = virtcrypto_devmgr_add_dev(vcrypto);
@@ -374,7 +378,7 @@ static int virtcrypto_probe(struct virtio_device *vdev)
	vcrypto->mac_algo_h = mac_algo_h;
	vcrypto->mac_algo_h = mac_algo_h;
	vcrypto->hash_algo = hash_algo;
	vcrypto->hash_algo = hash_algo;
	vcrypto->aead_algo = aead_algo;
	vcrypto->aead_algo = aead_algo;

	vcrypto->akcipher_algo = akcipher_algo;


	dev_info(&vdev->dev,
	dev_info(&vdev->dev,
		"max_queues: %u, max_cipher_key_len: %u, max_auth_key_len: %u, max_size 0x%llx\n",
		"max_queues: %u, max_cipher_key_len: %u, max_auth_key_len: %u, max_size 0x%llx\n",
Loading