diff options
author | Farhan Ali <alifm@linux.vnet.ibm.com> | 2018-06-19 11:41:34 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-07-01 09:00:46 -0400 |
commit | d0d859bb87ac3b4df1cb6692531fc95d093357c5 (patch) | |
tree | 98479955d47077a57822c4a3472fce79477c8808 | |
parent | b551bac14acab9c601269e2007a6b6cad2250a4c (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.c | 112 | ||||
-rw-r--r-- | drivers/crypto/virtio/virtio_crypto_common.h | 11 | ||||
-rw-r--r-- | drivers/crypto/virtio/virtio_crypto_mgr.c | 81 |
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 | ||
52 | struct 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 | */ |
56 | static DEFINE_MUTEX(algs_lock); | 63 | static DEFINE_MUTEX(algs_lock); |
57 | static unsigned int virtio_crypto_active_devs; | ||
58 | static void virtio_crypto_ablkcipher_finalize_req( | 64 | static 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 | ||
574 | static struct crypto_alg virtio_crypto_algs[] = { { | 586 | static 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 | ||
598 | int virtio_crypto_algs_register(void) | 614 | int 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 | ||
611 | unlock: | 640 | unlock: |
612 | mutex_unlock(&algs_lock); | 641 | mutex_unlock(&algs_lock); |
613 | return ret; | 642 | return ret; |
614 | } | 643 | } |
615 | 644 | ||
616 | void virtio_crypto_algs_unregister(void) | 645 | void 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 | ||
625 | unlock: | ||
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); | |||
116 | int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev); | 116 | int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev); |
117 | void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev); | 117 | void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev); |
118 | int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev); | 118 | int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev); |
119 | struct virtio_crypto *virtcrypto_get_dev_node(int node); | 119 | bool virtcrypto_algo_is_supported(struct virtio_crypto *vcrypto_dev, |
120 | uint32_t service, | ||
121 | uint32_t algo); | ||
122 | struct virtio_crypto *virtcrypto_get_dev_node(int node, | ||
123 | uint32_t service, | ||
124 | uint32_t algo); | ||
120 | int virtcrypto_dev_start(struct virtio_crypto *vcrypto); | 125 | int virtcrypto_dev_start(struct virtio_crypto *vcrypto); |
121 | void virtcrypto_dev_stop(struct virtio_crypto *vcrypto); | 126 | void virtcrypto_dev_stop(struct virtio_crypto *vcrypto); |
122 | int virtio_crypto_ablkcipher_crypt_req( | 127 | int 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 | ||
139 | int virtio_crypto_algs_register(void); | 144 | int virtio_crypto_algs_register(struct virtio_crypto *vcrypto); |
140 | void virtio_crypto_algs_unregister(void); | 145 | void 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 | */ |
191 | struct virtio_crypto *virtcrypto_get_dev_node(int node) | 196 | struct 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 | */ |
241 | int virtcrypto_dev_start(struct virtio_crypto *vcrypto) | 250 | int 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 | */ |
261 | void virtcrypto_dev_stop(struct virtio_crypto *vcrypto) | 270 | void 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 | |||
289 | bool 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 | } |