aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFarhan Ali <alifm@linux.vnet.ibm.com>2018-06-19 11:41:34 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2018-07-01 09:00:46 -0400
commitd0d859bb87ac3b4df1cb6692531fc95d093357c5 (patch)
tree98479955d47077a57822c4a3472fce79477c8808
parentb551bac14acab9c601269e2007a6b6cad2250a4c (diff)
crypto: virtio - Register an algo only if it's supported
Register a crypto algo with the Linux crypto layer only if the algorithm is supported by the backend virtio-crypto device. Also route crypto requests to a virtio-crypto device, only if it can support the requested service and algorithm. Signed-off-by: Farhan Ali <alifm@linux.ibm.com> Acked-by: Gonglei <arei.gonglei@huawei.com> Acked-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--drivers/crypto/virtio/virtio_crypto_algs.c112
-rw-r--r--drivers/crypto/virtio/virtio_crypto_common.h11
-rw-r--r--drivers/crypto/virtio/virtio_crypto_mgr.c81
3 files changed, 159 insertions, 45 deletions
diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c
index af6a908dfa7a..7a104f636f11 100644
--- a/drivers/crypto/virtio/virtio_crypto_algs.c
+++ b/drivers/crypto/virtio/virtio_crypto_algs.c
@@ -49,12 +49,18 @@ struct virtio_crypto_sym_request {
49 bool encrypt; 49 bool encrypt;
50}; 50};
51 51
52struct virtio_crypto_algo {
53 uint32_t algonum;
54 uint32_t service;
55 unsigned int active_devs;
56 struct crypto_alg algo;
57};
58
52/* 59/*
53 * The algs_lock protects the below global virtio_crypto_active_devs 60 * The algs_lock protects the below global virtio_crypto_active_devs
54 * and crypto algorithms registion. 61 * and crypto algorithms registion.
55 */ 62 */
56static DEFINE_MUTEX(algs_lock); 63static DEFINE_MUTEX(algs_lock);
57static unsigned int virtio_crypto_active_devs;
58static void virtio_crypto_ablkcipher_finalize_req( 64static void virtio_crypto_ablkcipher_finalize_req(
59 struct virtio_crypto_sym_request *vc_sym_req, 65 struct virtio_crypto_sym_request *vc_sym_req,
60 struct ablkcipher_request *req, 66 struct ablkcipher_request *req,
@@ -312,15 +318,21 @@ static int virtio_crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
312 unsigned int keylen) 318 unsigned int keylen)
313{ 319{
314 struct virtio_crypto_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); 320 struct virtio_crypto_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm);
321 uint32_t alg;
315 int ret; 322 int ret;
316 323
324 ret = virtio_crypto_alg_validate_key(keylen, &alg);
325 if (ret)
326 return ret;
327
317 if (!ctx->vcrypto) { 328 if (!ctx->vcrypto) {
318 /* New key */ 329 /* New key */
319 int node = virtio_crypto_get_current_node(); 330 int node = virtio_crypto_get_current_node();
320 struct virtio_crypto *vcrypto = 331 struct virtio_crypto *vcrypto =
321 virtcrypto_get_dev_node(node); 332 virtcrypto_get_dev_node(node,
333 VIRTIO_CRYPTO_SERVICE_CIPHER, alg);
322 if (!vcrypto) { 334 if (!vcrypto) {
323 pr_err("virtio_crypto: Could not find a virtio device in the system\n"); 335 pr_err("virtio_crypto: Could not find a virtio device in the system or unsupported algo\n");
324 return -ENODEV; 336 return -ENODEV;
325 } 337 }
326 338
@@ -571,57 +583,85 @@ static void virtio_crypto_ablkcipher_finalize_req(
571 virtcrypto_clear_request(&vc_sym_req->base); 583 virtcrypto_clear_request(&vc_sym_req->base);
572} 584}
573 585
574static struct crypto_alg virtio_crypto_algs[] = { { 586static struct virtio_crypto_algo virtio_crypto_algs[] = { {
575 .cra_name = "cbc(aes)", 587 .algonum = VIRTIO_CRYPTO_CIPHER_AES_CBC,
576 .cra_driver_name = "virtio_crypto_aes_cbc", 588 .service = VIRTIO_CRYPTO_SERVICE_CIPHER,
577 .cra_priority = 150, 589 .algo = {
578 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 590 .cra_name = "cbc(aes)",
579 .cra_blocksize = AES_BLOCK_SIZE, 591 .cra_driver_name = "virtio_crypto_aes_cbc",
580 .cra_ctxsize = sizeof(struct virtio_crypto_ablkcipher_ctx), 592 .cra_priority = 150,
581 .cra_alignmask = 0, 593 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
582 .cra_module = THIS_MODULE, 594 .cra_blocksize = AES_BLOCK_SIZE,
583 .cra_type = &crypto_ablkcipher_type, 595 .cra_ctxsize = sizeof(struct virtio_crypto_ablkcipher_ctx),
584 .cra_init = virtio_crypto_ablkcipher_init, 596 .cra_alignmask = 0,
585 .cra_exit = virtio_crypto_ablkcipher_exit, 597 .cra_module = THIS_MODULE,
586 .cra_u = { 598 .cra_type = &crypto_ablkcipher_type,
587 .ablkcipher = { 599 .cra_init = virtio_crypto_ablkcipher_init,
588 .setkey = virtio_crypto_ablkcipher_setkey, 600 .cra_exit = virtio_crypto_ablkcipher_exit,
589 .decrypt = virtio_crypto_ablkcipher_decrypt, 601 .cra_u = {
590 .encrypt = virtio_crypto_ablkcipher_encrypt, 602 .ablkcipher = {
591 .min_keysize = AES_MIN_KEY_SIZE, 603 .setkey = virtio_crypto_ablkcipher_setkey,
592 .max_keysize = AES_MAX_KEY_SIZE, 604 .decrypt = virtio_crypto_ablkcipher_decrypt,
593 .ivsize = AES_BLOCK_SIZE, 605 .encrypt = virtio_crypto_ablkcipher_encrypt,
606 .min_keysize = AES_MIN_KEY_SIZE,
607 .max_keysize = AES_MAX_KEY_SIZE,
608 .ivsize = AES_BLOCK_SIZE,
609 },
594 }, 610 },
595 }, 611 },
596} }; 612} };
597 613
598int virtio_crypto_algs_register(void) 614int virtio_crypto_algs_register(struct virtio_crypto *vcrypto)
599{ 615{
600 int ret = 0; 616 int ret = 0;
617 int i = 0;
601 618
602 mutex_lock(&algs_lock); 619 mutex_lock(&algs_lock);
603 if (++virtio_crypto_active_devs != 1)
604 goto unlock;
605 620
606 ret = crypto_register_algs(virtio_crypto_algs, 621 for (i = 0; i < ARRAY_SIZE(virtio_crypto_algs); i++) {
607 ARRAY_SIZE(virtio_crypto_algs)); 622
608 if (ret) 623 uint32_t service = virtio_crypto_algs[i].service;
609 virtio_crypto_active_devs--; 624 uint32_t algonum = virtio_crypto_algs[i].algonum;
625
626 if (!virtcrypto_algo_is_supported(vcrypto, service, algonum))
627 continue;
628
629 if (virtio_crypto_algs[i].active_devs == 0) {
630 ret = crypto_register_alg(&virtio_crypto_algs[i].algo);
631 if (ret)
632 goto unlock;
633 }
634
635 virtio_crypto_algs[i].active_devs++;
636 dev_info(&vcrypto->vdev->dev, "Registered algo %s\n",
637 virtio_crypto_algs[i].algo.cra_name);
638 }
610 639
611unlock: 640unlock:
612 mutex_unlock(&algs_lock); 641 mutex_unlock(&algs_lock);
613 return ret; 642 return ret;
614} 643}
615 644
616void virtio_crypto_algs_unregister(void) 645void virtio_crypto_algs_unregister(struct virtio_crypto *vcrypto)
617{ 646{
647 int i = 0;
648
618 mutex_lock(&algs_lock); 649 mutex_lock(&algs_lock);
619 if (--virtio_crypto_active_devs != 0)
620 goto unlock;
621 650
622 crypto_unregister_algs(virtio_crypto_algs, 651 for (i = 0; i < ARRAY_SIZE(virtio_crypto_algs); i++) {
623 ARRAY_SIZE(virtio_crypto_algs)); 652
653 uint32_t service = virtio_crypto_algs[i].service;
654 uint32_t algonum = virtio_crypto_algs[i].algonum;
655
656 if (virtio_crypto_algs[i].active_devs == 0 ||
657 !virtcrypto_algo_is_supported(vcrypto, service, algonum))
658 continue;
659
660 if (virtio_crypto_algs[i].active_devs == 1)
661 crypto_unregister_alg(&virtio_crypto_algs[i].algo);
662
663 virtio_crypto_algs[i].active_devs--;
664 }
624 665
625unlock:
626 mutex_unlock(&algs_lock); 666 mutex_unlock(&algs_lock);
627} 667}
diff --git a/drivers/crypto/virtio/virtio_crypto_common.h b/drivers/crypto/virtio/virtio_crypto_common.h
index 931a3bd5b51a..63ef7f7924ea 100644
--- a/drivers/crypto/virtio/virtio_crypto_common.h
+++ b/drivers/crypto/virtio/virtio_crypto_common.h
@@ -116,7 +116,12 @@ int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev);
116int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev); 116int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev);
117void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev); 117void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev);
118int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev); 118int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev);
119struct virtio_crypto *virtcrypto_get_dev_node(int node); 119bool virtcrypto_algo_is_supported(struct virtio_crypto *vcrypto_dev,
120 uint32_t service,
121 uint32_t algo);
122struct virtio_crypto *virtcrypto_get_dev_node(int node,
123 uint32_t service,
124 uint32_t algo);
120int virtcrypto_dev_start(struct virtio_crypto *vcrypto); 125int virtcrypto_dev_start(struct virtio_crypto *vcrypto);
121void virtcrypto_dev_stop(struct virtio_crypto *vcrypto); 126void virtcrypto_dev_stop(struct virtio_crypto *vcrypto);
122int virtio_crypto_ablkcipher_crypt_req( 127int virtio_crypto_ablkcipher_crypt_req(
@@ -136,7 +141,7 @@ static inline int virtio_crypto_get_current_node(void)
136 return node; 141 return node;
137} 142}
138 143
139int virtio_crypto_algs_register(void); 144int virtio_crypto_algs_register(struct virtio_crypto *vcrypto);
140void virtio_crypto_algs_unregister(void); 145void virtio_crypto_algs_unregister(struct virtio_crypto *vcrypto);
141 146
142#endif /* _VIRTIO_CRYPTO_COMMON_H */ 147#endif /* _VIRTIO_CRYPTO_COMMON_H */
diff --git a/drivers/crypto/virtio/virtio_crypto_mgr.c b/drivers/crypto/virtio/virtio_crypto_mgr.c
index a69ff71de2c4..d70de3a4f7d7 100644
--- a/drivers/crypto/virtio/virtio_crypto_mgr.c
+++ b/drivers/crypto/virtio/virtio_crypto_mgr.c
@@ -181,14 +181,20 @@ int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev)
181/* 181/*
182 * virtcrypto_get_dev_node() - Get vcrypto_dev on the node. 182 * virtcrypto_get_dev_node() - Get vcrypto_dev on the node.
183 * @node: Node id the driver works. 183 * @node: Node id the driver works.
184 * @service: Crypto service that needs to be supported by the
185 * dev
186 * @algo: The algorithm number that needs to be supported by the
187 * dev
184 * 188 *
185 * Function returns the virtio crypto device used fewest on the node. 189 * Function returns the virtio crypto device used fewest on the node,
190 * and supports the given crypto service and algorithm.
186 * 191 *
187 * To be used by virtio crypto device specific drivers. 192 * To be used by virtio crypto device specific drivers.
188 * 193 *
189 * Return: pointer to vcrypto_dev or NULL if not found. 194 * Return: pointer to vcrypto_dev or NULL if not found.
190 */ 195 */
191struct virtio_crypto *virtcrypto_get_dev_node(int node) 196struct virtio_crypto *virtcrypto_get_dev_node(int node, uint32_t service,
197 uint32_t algo)
192{ 198{
193 struct virtio_crypto *vcrypto_dev = NULL, *tmp_dev; 199 struct virtio_crypto *vcrypto_dev = NULL, *tmp_dev;
194 unsigned long best = ~0; 200 unsigned long best = ~0;
@@ -199,7 +205,8 @@ struct virtio_crypto *virtcrypto_get_dev_node(int node)
199 205
200 if ((node == dev_to_node(&tmp_dev->vdev->dev) || 206 if ((node == dev_to_node(&tmp_dev->vdev->dev) ||
201 dev_to_node(&tmp_dev->vdev->dev) < 0) && 207 dev_to_node(&tmp_dev->vdev->dev) < 0) &&
202 virtcrypto_dev_started(tmp_dev)) { 208 virtcrypto_dev_started(tmp_dev) &&
209 virtcrypto_algo_is_supported(tmp_dev, service, algo)) {
203 ctr = atomic_read(&tmp_dev->ref_count); 210 ctr = atomic_read(&tmp_dev->ref_count);
204 if (best > ctr) { 211 if (best > ctr) {
205 vcrypto_dev = tmp_dev; 212 vcrypto_dev = tmp_dev;
@@ -214,7 +221,9 @@ struct virtio_crypto *virtcrypto_get_dev_node(int node)
214 /* Get any started device */ 221 /* Get any started device */
215 list_for_each_entry(tmp_dev, 222 list_for_each_entry(tmp_dev,
216 virtcrypto_devmgr_get_head(), list) { 223 virtcrypto_devmgr_get_head(), list) {
217 if (virtcrypto_dev_started(tmp_dev)) { 224 if (virtcrypto_dev_started(tmp_dev) &&
225 virtcrypto_algo_is_supported(tmp_dev,
226 service, algo)) {
218 vcrypto_dev = tmp_dev; 227 vcrypto_dev = tmp_dev;
219 break; 228 break;
220 } 229 }
@@ -240,7 +249,7 @@ struct virtio_crypto *virtcrypto_get_dev_node(int node)
240 */ 249 */
241int virtcrypto_dev_start(struct virtio_crypto *vcrypto) 250int virtcrypto_dev_start(struct virtio_crypto *vcrypto)
242{ 251{
243 if (virtio_crypto_algs_register()) { 252 if (virtio_crypto_algs_register(vcrypto)) {
244 pr_err("virtio_crypto: Failed to register crypto algs\n"); 253 pr_err("virtio_crypto: Failed to register crypto algs\n");
245 return -EFAULT; 254 return -EFAULT;
246 } 255 }
@@ -260,5 +269,65 @@ int virtcrypto_dev_start(struct virtio_crypto *vcrypto)
260 */ 269 */
261void virtcrypto_dev_stop(struct virtio_crypto *vcrypto) 270void virtcrypto_dev_stop(struct virtio_crypto *vcrypto)
262{ 271{
263 virtio_crypto_algs_unregister(); 272 virtio_crypto_algs_unregister(vcrypto);
273}
274
275/*
276 * vcrypto_algo_is_supported()
277 * @vcrypto: Pointer to virtio crypto device.
278 * @service: The bit number for service validate.
279 * See VIRTIO_CRYPTO_SERVICE_*
280 * @algo : The bit number for the algorithm to validate.
281 *
282 *
283 * Validate if the virtio crypto device supports a service and
284 * algo.
285 *
286 * Return true if device supports a service and algo.
287 */
288
289bool virtcrypto_algo_is_supported(struct virtio_crypto *vcrypto,
290 uint32_t service,
291 uint32_t algo)
292{
293 uint32_t service_mask = 1u << service;
294 uint32_t algo_mask = 0;
295 bool low = true;
296
297 if (algo > 31) {
298 algo -= 32;
299 low = false;
300 }
301
302 if (!(vcrypto->crypto_services & service_mask))
303 return false;
304
305 switch (service) {
306 case VIRTIO_CRYPTO_SERVICE_CIPHER:
307 if (low)
308 algo_mask = vcrypto->cipher_algo_l;
309 else
310 algo_mask = vcrypto->cipher_algo_h;
311 break;
312
313 case VIRTIO_CRYPTO_SERVICE_HASH:
314 algo_mask = vcrypto->hash_algo;
315 break;
316
317 case VIRTIO_CRYPTO_SERVICE_MAC:
318 if (low)
319 algo_mask = vcrypto->mac_algo_l;
320 else
321 algo_mask = vcrypto->mac_algo_h;
322 break;
323
324 case VIRTIO_CRYPTO_SERVICE_AEAD:
325 algo_mask = vcrypto->aead_algo;
326 break;
327 }
328
329 if (!(algo_mask & (1u << algo)))
330 return false;
331
332 return true;
264} 333}