misc: tegra-cryptodev: fix resource leak
[linux-2.6.git] / drivers / misc / tegra-cryptodev.c
1 /*
2  * drivers/misc/tegra-cryptodev.c
3  *
4  * crypto dev node for NVIDIA tegra aes hardware
5  *
6  * Copyright (c) 2010, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  */
22
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/errno.h>
26 #include <linux/kernel.h>
27 #include <linux/slab.h>
28 #include <linux/fs.h>
29 #include <linux/miscdevice.h>
30 #include <linux/crypto.h>
31 #include <linux/scatterlist.h>
32 #include <linux/uaccess.h>
33 #include <crypto/rng.h>
34 #include <crypto/hash.h>
35 #include <mach/hardware.h>
36
37 #include "tegra-cryptodev.h"
38
39 #define NBUFS 2
40 #define XBUFSIZE 8
41 #define RNG_DRBG 1
42 #define RNG 0
43
44 struct tegra_crypto_ctx {
45         struct crypto_ablkcipher *ecb_tfm;
46         struct crypto_ablkcipher *cbc_tfm;
47         struct crypto_ablkcipher *ofb_tfm;
48         struct crypto_ablkcipher *ctr_tfm;
49         struct crypto_ablkcipher *cmac_tfm;
50         struct crypto_rng *rng;
51         struct crypto_rng *rng_drbg;
52         u8 seed[TEGRA_CRYPTO_RNG_SEED_SIZE];
53         int use_ssk;
54 };
55
56 struct tegra_crypto_completion {
57         struct completion restart;
58         int req_err;
59 };
60
61 static int alloc_bufs(unsigned long *buf[NBUFS])
62 {
63         int i;
64
65         for (i = 0; i < NBUFS; i++) {
66                 buf[i] = (void *)__get_free_page(GFP_KERNEL);
67                 if (!buf[i])
68                         goto err_free_buf;
69         }
70
71         return 0;
72
73 err_free_buf:
74         while (i-- > 0)
75                 free_page((unsigned long)buf[i]);
76
77         return -ENOMEM;
78 }
79
80 static void free_bufs(unsigned long *buf[NBUFS])
81 {
82         int i;
83
84         for (i = 0; i < NBUFS; i++)
85                 free_page((unsigned long)buf[i]);
86 }
87
88 static int tegra_crypto_dev_open(struct inode *inode, struct file *filp)
89 {
90         struct tegra_crypto_ctx *ctx;
91         int ret = 0;
92
93         ctx = kzalloc(sizeof(struct tegra_crypto_ctx), GFP_KERNEL);
94         if (!ctx) {
95                 pr_err("no memory for context\n");
96                 return -ENOMEM;
97         }
98
99         ctx->ecb_tfm = crypto_alloc_ablkcipher("ecb-aes-tegra",
100                 CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 0);
101         if (IS_ERR(ctx->ecb_tfm)) {
102                 pr_err("Failed to load transform for ecb-aes-tegra: %ld\n",
103                         PTR_ERR(ctx->ecb_tfm));
104                 ret = PTR_ERR(ctx->ecb_tfm);
105                 goto fail_ecb;
106         }
107
108         ctx->cbc_tfm = crypto_alloc_ablkcipher("cbc-aes-tegra",
109                 CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 0);
110         if (IS_ERR(ctx->cbc_tfm)) {
111                 pr_err("Failed to load transform for cbc-aes-tegra: %ld\n",
112                         PTR_ERR(ctx->cbc_tfm));
113                 ret = PTR_ERR(ctx->cbc_tfm);
114                 goto fail_cbc;
115         }
116
117         if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2) {
118                 ctx->ofb_tfm = crypto_alloc_ablkcipher("ofb-aes-tegra",
119                         CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 0);
120                 if (IS_ERR(ctx->ofb_tfm)) {
121                         pr_err("Failed to load transform for ofb-aes-tegra: %ld\n",
122                                 PTR_ERR(ctx->ofb_tfm));
123                         ret = PTR_ERR(ctx->ofb_tfm);
124                         goto fail_ofb;
125                 }
126
127                 ctx->ctr_tfm = crypto_alloc_ablkcipher("ctr-aes-tegra",
128                         CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 0);
129                 if (IS_ERR(ctx->ctr_tfm)) {
130                         pr_err("Failed to load transform for ctr-aes-tegra: %ld\n",
131                                 PTR_ERR(ctx->ctr_tfm));
132                         ret = PTR_ERR(ctx->ctr_tfm);
133                         goto fail_ctr;
134                 }
135         }
136         if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA11) {
137                 ctx->rng_drbg = crypto_alloc_rng("rng_drbg-aes-tegra",
138                         CRYPTO_ALG_TYPE_RNG, 0);
139                 if (IS_ERR(ctx->rng_drbg)) {
140                         pr_err("Failed to load transform for rng_drbg tegra: %ld\n",
141                                 PTR_ERR(ctx->rng_drbg));
142                         ret = PTR_ERR(ctx->rng_drbg);
143                         goto fail_rng;
144                 }
145         } else {
146                 ctx->rng = crypto_alloc_rng("rng-aes-tegra",
147                         CRYPTO_ALG_TYPE_RNG, 0);
148                 if (IS_ERR(ctx->rng)) {
149                         pr_err("Failed to load transform for tegra rng: %ld\n",
150                                 PTR_ERR(ctx->rng));
151                         ret = PTR_ERR(ctx->rng);
152                         goto fail_rng;
153                 }
154         }
155
156         filp->private_data = ctx;
157         return ret;
158
159 fail_rng:
160         if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2)
161                 crypto_free_ablkcipher(ctx->ctr_tfm);
162 fail_ctr:
163         if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2)
164                 crypto_free_ablkcipher(ctx->ofb_tfm);
165 fail_ofb:
166         crypto_free_ablkcipher(ctx->cbc_tfm);
167
168 fail_cbc:
169         crypto_free_ablkcipher(ctx->ecb_tfm);
170
171 fail_ecb:
172         kfree(ctx);
173         return ret;
174 }
175
176 static int tegra_crypto_dev_release(struct inode *inode, struct file *filp)
177 {
178         struct tegra_crypto_ctx *ctx = filp->private_data;
179
180         crypto_free_ablkcipher(ctx->ecb_tfm);
181         crypto_free_ablkcipher(ctx->cbc_tfm);
182
183         if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2) {
184                 crypto_free_ablkcipher(ctx->ofb_tfm);
185                 crypto_free_ablkcipher(ctx->ctr_tfm);
186         }
187
188         if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA11)
189                 crypto_free_rng(ctx->rng_drbg);
190         else
191                 crypto_free_rng(ctx->rng);
192         kfree(ctx);
193         filp->private_data = NULL;
194         return 0;
195 }
196
197 static void tegra_crypt_complete(struct crypto_async_request *req, int err)
198 {
199         struct tegra_crypto_completion *done = req->data;
200
201         if (err != -EINPROGRESS) {
202                 done->req_err = err;
203                 complete(&done->restart);
204         }
205 }
206
207 static int process_crypt_req(struct tegra_crypto_ctx *ctx, struct tegra_crypt_req *crypt_req)
208 {
209         struct crypto_ablkcipher *tfm;
210         struct ablkcipher_request *req = NULL;
211         struct scatterlist in_sg;
212         struct scatterlist out_sg;
213         unsigned long *xbuf[NBUFS];
214         int ret = 0, size = 0;
215         unsigned long total = 0;
216         const u8 *key = NULL;
217         struct tegra_crypto_completion tcrypt_complete;
218
219         if (crypt_req->op & TEGRA_CRYPTO_ECB) {
220                 req = ablkcipher_request_alloc(ctx->ecb_tfm, GFP_KERNEL);
221                 tfm = ctx->ecb_tfm;
222         } else if (crypt_req->op & TEGRA_CRYPTO_CBC) {
223                 req = ablkcipher_request_alloc(ctx->cbc_tfm, GFP_KERNEL);
224                 tfm = ctx->cbc_tfm;
225         } else if ((crypt_req->op & TEGRA_CRYPTO_OFB) &&
226                         (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2)) {
227
228                 req = ablkcipher_request_alloc(ctx->ofb_tfm, GFP_KERNEL);
229                 tfm = ctx->ofb_tfm;
230         } else if ((crypt_req->op & TEGRA_CRYPTO_CTR) &&
231                         (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2)) {
232
233                 req = ablkcipher_request_alloc(ctx->ctr_tfm, GFP_KERNEL);
234                 tfm = ctx->ctr_tfm;
235         }
236
237         if (!req) {
238                 pr_err("%s: Failed to allocate request\n", __func__);
239                 return -ENOMEM;
240         }
241
242         if ((crypt_req->keylen < 0) || (crypt_req->keylen > AES_MAX_KEY_SIZE)) {
243                 ret = -EINVAL;
244                 pr_err("crypt_req keylen invalid");
245                 goto process_req_out;
246         }
247
248         crypto_ablkcipher_clear_flags(tfm, ~0);
249
250         if (!ctx->use_ssk)
251                 key = crypt_req->key;
252
253         ret = crypto_ablkcipher_setkey(tfm, key, crypt_req->keylen);
254         if (ret < 0) {
255                 pr_err("setkey failed");
256                 goto process_req_out;
257         }
258
259         ret = alloc_bufs(xbuf);
260         if (ret < 0) {
261                 pr_err("alloc_bufs failed");
262                 goto process_req_out;
263         }
264
265         init_completion(&tcrypt_complete.restart);
266
267         ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
268                 tegra_crypt_complete, &tcrypt_complete);
269
270         total = crypt_req->plaintext_sz;
271         while (total > 0) {
272                 size = min(total, PAGE_SIZE);
273                 ret = copy_from_user((void *)xbuf[0],
274                         (void __user *)crypt_req->plaintext, size);
275                 if (ret < 0) {
276                         pr_debug("%s: copy_from_user failed (%d)\n", __func__, ret);
277                         goto process_req_buf_out;
278                 }
279                 sg_init_one(&in_sg, xbuf[0], size);
280                 sg_init_one(&out_sg, xbuf[1], size);
281
282                 ablkcipher_request_set_crypt(req, &in_sg,
283                         &out_sg, size, crypt_req->iv);
284
285                 INIT_COMPLETION(tcrypt_complete.restart);
286                 tcrypt_complete.req_err = 0;
287                 ret = crypt_req->encrypt ?
288                         crypto_ablkcipher_encrypt(req) :
289                         crypto_ablkcipher_decrypt(req);
290
291                 if ((ret == -EINPROGRESS) || (ret == -EBUSY)) {
292                         /* crypto driver is asynchronous */
293                         ret = wait_for_completion_interruptible(&tcrypt_complete.restart);
294
295                         if (ret < 0)
296                                 goto process_req_buf_out;
297
298                         if (tcrypt_complete.req_err < 0) {
299                                 ret = tcrypt_complete.req_err;
300                                 goto process_req_buf_out;
301                         }
302                 } else if (ret < 0) {
303                         pr_debug("%scrypt failed (%d)\n",
304                                 crypt_req->encrypt ? "en" : "de", ret);
305                         goto process_req_buf_out;
306                 }
307
308                 ret = copy_to_user((void __user *)crypt_req->result,
309                         (const void *)xbuf[1], size);
310                 if (ret < 0)
311                         goto process_req_buf_out;
312
313                 total -= size;
314                 crypt_req->result += size;
315                 crypt_req->plaintext += size;
316         }
317
318 process_req_buf_out:
319         free_bufs(xbuf);
320 process_req_out:
321         ablkcipher_request_free(req);
322
323         return ret;
324 }
325
326 static int sha_async_hash_op(struct ahash_request *req,
327                                 struct tegra_crypto_completion *tr,
328                                 int ret)
329 {
330         if (ret == -EINPROGRESS || ret == -EBUSY) {
331                 ret = wait_for_completion_interruptible(&tr->restart);
332                 if (!ret)
333                         ret = tr->req_err;
334                 INIT_COMPLETION(tr->restart);
335         }
336         return ret;
337 }
338
339 static int tegra_crypto_sha(struct tegra_sha_req *sha_req)
340 {
341
342         struct crypto_ahash *tfm;
343         struct scatterlist sg[1];
344         char result[64];
345         struct ahash_request *req;
346         struct tegra_crypto_completion sha_complete;
347         void *hash_buff;
348         unsigned long *xbuf[XBUFSIZE];
349         int ret = -ENOMEM;
350
351         tfm = crypto_alloc_ahash(sha_req->algo, 0, 0);
352         if (IS_ERR(tfm)) {
353                 printk(KERN_ERR "alg: hash: Failed to load transform for %s: "
354                        "%ld\n", sha_req->algo, PTR_ERR(tfm));
355                 goto out_alloc;
356         }
357
358         req = ahash_request_alloc(tfm, GFP_KERNEL);
359         if (!req) {
360                 printk(KERN_ERR "alg: hash: Failed to allocate request for "
361                        "%s\n", sha_req->algo);
362                 goto out_noreq;
363         }
364
365         ret = alloc_bufs(xbuf);
366         if (ret < 0) {
367                 pr_err("alloc_bufs failed");
368                 goto out_buf;
369         }
370
371         init_completion(&sha_complete.restart);
372
373         memset(result, 0, 64);
374
375         hash_buff = xbuf[0];
376
377         memcpy(hash_buff, sha_req->plaintext, sha_req->plaintext_sz);
378         sg_init_one(&sg[0], hash_buff, sha_req->plaintext_sz);
379
380         if (sha_req->keylen) {
381                 crypto_ahash_clear_flags(tfm, ~0);
382                 ret = crypto_ahash_setkey(tfm, sha_req->key,
383                                           sha_req->keylen);
384                 if (ret) {
385                         printk(KERN_ERR "alg: hash: setkey failed on "
386                                " %s: ret=%d\n", sha_req->algo,
387                                -ret);
388                         goto out;
389                 }
390         }
391
392         ahash_request_set_crypt(req, sg, result, sha_req->plaintext_sz);
393
394         ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_init(req));
395         if (ret) {
396                 pr_err("alg: hash: init failed on "
397                        "for %s: ret=%d\n", sha_req->algo, -ret);
398                 goto out;
399         }
400
401         ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_update(req));
402         if (ret) {
403                 pr_err("alg: hash: update failed on "
404                        "for %s: ret=%d\n", sha_req->algo, -ret);
405                 goto out;
406         }
407
408         ret = sha_async_hash_op(req, &sha_complete, crypto_ahash_final(req));
409         if (ret) {
410                 pr_err("alg: hash: final failed on "
411                        "for %s: ret=%d\n", sha_req->algo, -ret);
412                 goto out;
413         }
414
415         ret = copy_to_user((void __user *)sha_req->result,
416                 (const void *)result, crypto_ahash_digestsize(tfm));
417         if (ret < 0)
418                 goto out;
419
420 out:
421         free_bufs(xbuf);
422
423 out_buf:
424         ahash_request_free(req);
425
426 out_noreq:
427         crypto_free_ahash(tfm);
428
429 out_alloc:
430         return ret;
431
432 }
433
434 static long tegra_crypto_dev_ioctl(struct file *filp,
435         unsigned int ioctl_num, unsigned long arg)
436 {
437         struct tegra_crypto_ctx *ctx = filp->private_data;
438         struct tegra_crypt_req crypt_req;
439         struct tegra_rng_req rng_req;
440         struct tegra_sha_req sha_req;
441         char *rng;
442         int ret = 0;
443
444         switch (ioctl_num) {
445         case TEGRA_CRYPTO_IOCTL_NEED_SSK:
446                 ctx->use_ssk = (int)arg;
447                 break;
448
449         case TEGRA_CRYPTO_IOCTL_PROCESS_REQ:
450                 ret = copy_from_user(&crypt_req, (void __user *)arg,
451                         sizeof(crypt_req));
452                 if (ret < 0) {
453                         pr_err("%s: copy_from_user fail(%d)\n", __func__, ret);
454                         break;
455                 }
456
457                 ret = process_crypt_req(ctx, &crypt_req);
458                 break;
459
460         case TEGRA_CRYPTO_IOCTL_SET_SEED:
461                 if (copy_from_user(&rng_req, (void __user *)arg,
462                         sizeof(rng_req)))
463                         return -EFAULT;
464                 memcpy(ctx->seed, rng_req.seed, TEGRA_CRYPTO_RNG_SEED_SIZE);
465
466                 if (rng_req.type == RNG_DRBG)
467                         ret = crypto_rng_reset(ctx->rng_drbg, ctx->seed,
468                                 crypto_rng_seedsize(ctx->rng_drbg));
469                 else
470                         ret = crypto_rng_reset(ctx->rng, ctx->seed,
471                                 crypto_rng_seedsize(ctx->rng));
472                 break;
473
474         case TEGRA_CRYPTO_IOCTL_GET_RANDOM:
475                 if (copy_from_user(&rng_req, (void __user *)arg,
476                         sizeof(rng_req)))
477                         return -EFAULT;
478
479                 rng = kzalloc(rng_req.nbytes, GFP_KERNEL);
480                 if (!rng) {
481                         if (rng_req.type == RNG_DRBG)
482                                 pr_err("mem alloc for rng_drbg fail");
483                         else
484                                 pr_err("mem alloc for rng fail");
485                         ret = -ENODATA;
486                         goto rng_out;
487                 }
488
489                 if (rng_req.type == RNG_DRBG)
490                         ret = crypto_rng_get_bytes(ctx->rng_drbg, rng,
491                                 rng_req.nbytes);
492                 else
493                         ret = crypto_rng_get_bytes(ctx->rng, rng,
494                                 rng_req.nbytes);
495
496                 if (ret != rng_req.nbytes) {
497                         if (rng_req.type == RNG_DRBG)
498                                 pr_err("rng_drbg failed");
499                         else
500                                 pr_err("rng failed");
501                         ret = -ENODATA;
502                         goto rng_out;
503                 }
504
505                 ret = copy_to_user((void __user *)rng_req.rdata,
506                         (const void *)rng, rng_req.nbytes);
507                 ret = (ret < 0) ? -ENODATA : 0;
508 rng_out:
509                 if (rng)
510                         kfree(rng);
511                 break;
512
513         case TEGRA_CRYPTO_IOCTL_GET_SHA:
514                 if (tegra_get_chipid() != TEGRA_CHIPID_TEGRA2) {
515                         if (copy_from_user(&sha_req, (void __user *)arg,
516                                 sizeof(sha_req)))
517                                 return -EFAULT;
518                         ret = tegra_crypto_sha(&sha_req);
519                 } else {
520                         ret = -EINVAL;
521                 }
522                 break;
523
524         default:
525                 pr_debug("invalid ioctl code(%d)", ioctl_num);
526                 ret = -EINVAL;
527         }
528
529         return ret;
530 }
531
532 const struct file_operations tegra_crypto_fops = {
533         .owner = THIS_MODULE,
534         .open = tegra_crypto_dev_open,
535         .release = tegra_crypto_dev_release,
536         .unlocked_ioctl = tegra_crypto_dev_ioctl,
537 };
538
539 struct miscdevice tegra_crypto_device = {
540         .minor = MISC_DYNAMIC_MINOR,
541         .name = "tegra-crypto",
542         .fops = &tegra_crypto_fops,
543 };
544
545 static int __init tegra_crypto_dev_init(void)
546 {
547         return misc_register(&tegra_crypto_device);
548 }
549
550 late_initcall(tegra_crypto_dev_init);
551
552 MODULE_DESCRIPTION("Tegra AES hw device node.");
553 MODULE_AUTHOR("NVIDIA Corporation");
554 MODULE_LICENSE("GPLv2");