---
 cryptodev.h        |   53 ++++++------
 cryptodev_cipher.c |   67 +++++++++-----
 cryptodev_int.h    |   21 ++++-
 cryptodev_main.c   |  244 +++++++++++++++++++++++++++++-----------------------
 4 files changed, 225 insertions(+), 160 deletions(-)

diff --git a/cryptodev.h b/cryptodev.h
index 7c25431..34537d0 100644
--- a/cryptodev.h
+++ b/cryptodev.h
@@ -5,8 +5,9 @@
 #ifndef L_CRYPTODEV_H
 #define L_CRYPTODEV_H
 
+#include <linux/types.h>
 #ifndef __KERNEL__
-#include <inttypes.h>
+#define __user
 #endif
 
 /* API extensions for linux */
@@ -69,15 +70,15 @@ typedef enum {
 struct session_op {
        /* Specify either cipher or mac
         */
-       uint32_t        cipher;         /* cryptodev_crypto_op_t */
-       uint32_t        mac;            /* cryptodev_crypto_op_t */
+       __u32   cipher;         /* cryptodev_crypto_op_t */
+       __u32   mac;            /* cryptodev_crypto_op_t */
 
-       uint32_t        keylen;
-       uint8_t *       key;
-       uint32_t        mackeylen;
-       uint8_t *       mackey;
+       __u32   keylen;
+       __u8    __user *key;
+       __u32   mackeylen;
+       __u8    __user *mackey;
 
-       uint32_t        ses;            /* session identifier */
+       __u32   ses;            /* session identifier */
 };
 
 #define        COP_ENCRYPT     0
@@ -85,14 +86,14 @@ struct session_op {
 
 /* input of CIOCCRYPT */
  struct crypt_op {
-       uint32_t        ses;            /* session identifier */
-       uint16_t        op;             /* COP_ENCRYPT or COP_DECRYPT */
-       uint16_t        flags;          /* operational switches, use 0 in doubt 
*/
-       uint32_t        len;            /* length of source data */
-       uint8_t *       src;            /* source data */
-       uint8_t *       dst;            /* pointer to output data */
-       uint8_t *       mac;            /* pointer to output data for hash/MAC 
operations */
-       uint8_t *       iv;             /* initialization vector for encryption 
operations */
+       __u32   ses;            /* session identifier */
+       __u16   op;             /* COP_ENCRYPT or COP_DECRYPT */
+       __u16   flags;          /* no usage so far, use 0 */
+       __u32   len;            /* length of source data */
+       __u8    __user *src;            /* source data */
+       __u8    __user *dst;            /* pointer to output data */
+       __u8    __user *mac;            /* pointer to output data for hash/MAC 
operations */
+       __u8    __user *iv;             /* initialization vector for encryption 
operations */
 };
 
 /* struct crypt_op flags */
@@ -109,19 +110,19 @@ struct session_op {
 #define        CRYPTO_ALG_FLAG_DSA_SHA         4
 
 struct crparam {
-       uint8_t*        crp_p;
-       uint32_t        crp_nbits;
+       __u8*   crp_p;
+       __u32   crp_nbits;
 };
 
 #define CRK_MAXPARAM   8
 
 /* input of CIOCKEY */
 struct crypt_kop {
-       uint32_t        crk_op;         /* cryptodev_crk_ot_t */
-       uint32_t        crk_status;
-       uint16_t        crk_iparams;
-       uint16_t        crk_oparams;
-       uint32_t        crk_pad1;
+       __u32   crk_op;         /* cryptodev_crk_ot_t */
+       __u32   crk_status;
+       __u16   crk_iparams;
+       __u16   crk_oparams;
+       __u32   crk_pad1;
        struct crparam  crk_param[CRK_MAXPARAM];
 };
 
@@ -147,11 +148,11 @@ typedef enum {
 
 /* ioctl's. Compatible with old linux cryptodev.h
  */
-#define CRIOGET         _IOWR('c', 101, uint32_t)
+#define CRIOGET         _IOWR('c', 101, __u32)
 #define CIOCGSESSION    _IOWR('c', 102, struct session_op)
-#define CIOCFSESSION    _IOW('c', 103, uint32_t)
+#define CIOCFSESSION    _IOW('c', 103, __u32)
 #define CIOCCRYPT       _IOWR('c', 104, struct crypt_op)
 #define CIOCKEY         _IOWR('c', 105, struct crypt_kop)
-#define CIOCASYMFEAT    _IOR('c', 106, uint32_t)
+#define CIOCASYMFEAT    _IOR('c', 106, __u32)
 
 #endif /* L_CRYPTODEV_H */
diff --git a/cryptodev_cipher.c b/cryptodev_cipher.c
index 15e9d9f..5377ba3 100644
--- a/cryptodev_cipher.c
+++ b/cryptodev_cipher.c
@@ -2,6 +2,8 @@
  * Driver for /dev/crypto device (aka CryptoDev)
  *
  * Copyright (c) 2010 Nikos Mavrogiannopoulos <n...@gnutls.org>
+ * Portions Copyright (c) 2010 Michael Weiser
+ * Portions Copyright (c) 2010 Phil Sutter
  *
  * This file is part of linux cryptodev.
  *
@@ -23,10 +25,10 @@
 #include <linux/crypto.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
+#include <linux/ioctl.h>
 #include <linux/random.h>
-#include <asm/uaccess.h>
-#include <asm/ioctl.h>
 #include <linux/scatterlist.h>
+#include <linux/uaccess.h>
 #include <crypto/algapi.h>
 #include <crypto/hash.h>
 #include "cryptodev.h"
@@ -51,14 +53,11 @@ static void cryptodev_complete(struct crypto_async_request 
*req, int err)
 
 int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, 
uint8_t * keyp, size_t keylen)
 {
-
        struct ablkcipher_alg* alg;
        int ret;
 
        memset(out, 0, sizeof(*out));
 
-       out->init = 1;
-
        out->async.s = crypto_alloc_ablkcipher(alg_name, 0, 0);
        if (unlikely(IS_ERR(out->async.s))) {
                dprintk(1,KERN_DEBUG,"%s: Failed to load cipher %s\n", __func__,
@@ -110,27 +109,34 @@ int cryptodev_cipher_init(struct cipher_data* out, const 
char* alg_name, uint8_t
        ablkcipher_request_set_callback(out->async.request, 
CRYPTO_TFM_REQ_MAY_BACKLOG,
                                        cryptodev_complete, out->async.result);
 
+       out->init = 1;
        return 0;
 error:
-       crypto_free_ablkcipher(out->async.s);
+       if (out->async.request)
+               ablkcipher_request_free(out->async.request);
        kfree(out->async.result);
-       ablkcipher_request_free(out->async.request);
+       if (out->async.s)
+               crypto_free_ablkcipher(out->async.s);
 
        return ret;
 }
 
 void cryptodev_cipher_deinit(struct cipher_data* cdata)
 {
-       crypto_free_ablkcipher(cdata->async.s);
-       kfree(cdata->async.result);
-       ablkcipher_request_free(cdata->async.request);
-
-       cdata->init = 0;
+       if (cdata->init) {
+               if (cdata->async.request)
+                       ablkcipher_request_free(cdata->async.request);
+               kfree(cdata->async.result);
+               if (cdata->async.s)
+                       crypto_free_ablkcipher(cdata->async.s);
+
+               cdata->init = 0;
+       }
 }
 
-void cryptodev_cipher_set_iv(struct cipher_data* cdata, void __user* iv, 
size_t iv_size)
+void cryptodev_cipher_set_iv(struct cipher_data* cdata, void *iv, size_t 
iv_size)
 {
-       memcpy(cdata->async.iv, iv, min(iv_size,sizeof(cdata->async.iv)) );
+       memcpy(cdata->async.iv, iv, min(iv_size,sizeof(cdata->async.iv)));
 }
 
 static inline int waitfor (struct cryptodev_result* cr, ssize_t ret)
@@ -148,7 +154,7 @@ static inline int waitfor (struct cryptodev_result* cr, 
ssize_t ret)
                 * another request. */
 
                if (unlikely(cr->err)) {
-                       dprintk(0,KERN_ERR,"error from async request: %zd \n", 
ret);
+                       dprintk(0,KERN_ERR,"error from async request: %d \n", 
cr->err);
                         return cr->err; 
                }
 
@@ -160,24 +166,24 @@ static inline int waitfor (struct cryptodev_result* cr, 
ssize_t ret)
        return 0;
 }
 
-ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, struct 
scatterlist *sg1, struct scatterlist *sg2, size_t len)
+ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, const struct 
scatterlist *sg1, struct scatterlist *sg2, size_t len)
 {
        int ret;
 
        INIT_COMPLETION(cdata->async.result->completion);
-       ablkcipher_request_set_crypt(cdata->async.request, sg1, sg2,
+       ablkcipher_request_set_crypt(cdata->async.request, (struct 
scatterlist*)sg1, sg2,
                        len, cdata->async.iv);
        ret = crypto_ablkcipher_encrypt(cdata->async.request);
 
        return waitfor(cdata->async.result,ret);
 }
 
-ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, struct 
scatterlist *sg1, struct scatterlist *sg2, size_t len)
+ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, const struct 
scatterlist *sg1, struct scatterlist *sg2, size_t len)
 {
        int ret;
 
        INIT_COMPLETION(cdata->async.result->completion);
-       ablkcipher_request_set_crypt(cdata->async.request, sg1, sg2,
+       ablkcipher_request_set_crypt(cdata->async.request, (struct 
scatterlist*)sg1, sg2,
                        len, cdata->async.iv);
        ret = crypto_ablkcipher_decrypt(cdata->async.request);
 
@@ -190,8 +196,6 @@ int cryptodev_hash_init( struct hash_data* hdata, const 
char* alg_name, int hmac
 {
 int ret;
 
-       hdata->init = 1;
-
        hdata->async.s = crypto_alloc_ahash(alg_name, 0, 0);
        if (unlikely(IS_ERR(hdata->async.s))) {
                dprintk(1,KERN_DEBUG,"%s: Failed to load transform for %s\n", 
__func__,
@@ -231,18 +235,34 @@ int ret;
        ahash_request_set_callback(hdata->async.request, 
CRYPTO_TFM_REQ_MAY_BACKLOG,
                                        cryptodev_complete, 
hdata->async.result);
 
+       ret = crypto_ahash_init(hdata->async.request);
+       if (unlikely(ret)) {
+               dprintk(0,KERN_ERR,
+                       "error in crypto_hash_init()\n");
+               goto error_request;
+       }
 
+       hdata->init = 1;
        return 0;
 
+error_request:
+       ahash_request_free(hdata->async.request);
 error:
+       kfree(hdata->async.result);
        crypto_free_ahash(hdata->async.s);
        return ret;
 }
 
 void cryptodev_hash_deinit(struct hash_data* hdata)
 {
-       crypto_free_ahash(hdata->async.s);
-       hdata->init = 0;
+       if (hdata->init) {
+               if (hdata->async.request)
+                       ahash_request_free(hdata->async.request);
+               kfree(hdata->async.result);
+               if (hdata->async.s)
+                       crypto_free_ahash(hdata->async.s);
+               hdata->init = 0;
+       }
 }
 
 int cryptodev_hash_reset( struct hash_data* hdata)
@@ -272,7 +292,6 @@ ssize_t cryptodev_hash_update( struct hash_data* hdata, 
struct scatterlist *sg,
        return waitfor(hdata->async.result,ret);
 }
 
-
 int cryptodev_hash_final( struct hash_data* hdata, void* output)
 {
        int ret;
diff --git a/cryptodev_int.h b/cryptodev_int.h
index bc3b586..1bf309c 100644
--- a/cryptodev_int.h
+++ b/cryptodev_int.h
@@ -10,8 +10,8 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-
-#undef DISABLE_ZCOPY
+#include <linux/scatterlist.h>
+#include "cryptodev.h"
 
 #define PFX "cryptodev: "
 #define dprintk(level,severity,format,a...)                    \
@@ -24,6 +24,18 @@
 
 extern int cryptodev_verbosity;
 
+/* For zero copy */
+int __get_userbuf(uint8_t __user *addr, uint32_t len, int write,
+               int pgcount, struct page **pg, struct scatterlist *sg);
+void release_user_pages(struct page **pg, int pagecount);
+
+/* last page - first page + 1 */
+#define PAGECOUNT(buf, buflen) \
+        ((((unsigned long)(buf + buflen - 1) & PAGE_MASK) >> PAGE_SHIFT) - \
+         (((unsigned long) buf               & PAGE_MASK) >> PAGE_SHIFT) + 1)
+
+#define DEFAULT_PREALLOC_PAGES 32
+
 struct cipher_data
 {
        int init; /* 0 uninitialized */
@@ -39,8 +51,9 @@ struct cipher_data
 
 int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, 
uint8_t * key, size_t keylen);
 void cryptodev_cipher_deinit(struct cipher_data* cdata);
-ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, struct 
scatterlist *sg1, struct scatterlist *sg2, size_t len);
-ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, struct 
scatterlist *sg1, struct scatterlist *sg2, size_t len);
+ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, const struct 
scatterlist *sg1, struct scatterlist *sg2, size_t len);
+ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, const struct 
scatterlist *sg1, struct scatterlist *sg2, size_t len);
+
 void cryptodev_cipher_set_iv(struct cipher_data* cdata, void* iv, size_t 
iv_size);
 
 /* hash stuff */
diff --git a/cryptodev_main.c b/cryptodev_main.c
index b1b05d6..35b90cc 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -34,11 +34,12 @@
 #include <linux/crypto.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
-#include <linux/pagemap.h>
+#include <linux/ioctl.h>
 #include <linux/random.h>
+#include <linux/syscalls.h>
+#include <linux/pagemap.h>
+#include <linux/uaccess.h>
 #include "cryptodev.h"
-#include <asm/uaccess.h>
-#include <asm/ioctl.h>
 #include <linux/scatterlist.h>
 #include "cryptodev_int.h"
 #include "version.h"
@@ -64,6 +65,15 @@ MODULE_PARM_DESC(enable_stats, "collect statictics about 
cryptodev usage");
 #endif
 
 /* ====== CryptoAPI ====== */
+struct fcrypt {
+       struct list_head list;
+       struct semaphore sem;
+};
+
+struct crypt_priv {
+       void * ncr;
+       struct fcrypt fcrypt;
+};
 
 #define FILL_SG(sg,ptr,len)                                    \
        do {                                                    \
@@ -91,11 +101,6 @@ struct csession {
        struct scatterlist *sg;
 };
 
-struct fcrypt {
-       struct list_head list;
-       struct semaphore sem;
-};
-
 /* Prepare session for future use. */
 static int
 crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
@@ -211,13 +216,12 @@ crypto_create_session(struct fcrypt *fcr, struct 
session_op *sop)
                        goto error_cipher;
                }
 
-               ret = copy_from_user(keyp, sop->key, sop->keylen);
-               if (unlikely(ret)) {
+               if (unlikely(copy_from_user(keyp, sop->key, sop->keylen))) {
+                       ret = -EFAULT;
                        goto error_cipher;
                }
 
                ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keyp, 
sop->keylen);
-
                if (ret < 0) {
                        dprintk(1,KERN_DEBUG,"%s: Failed to load cipher for 
%s\n", __func__,
                                   alg_name);
@@ -235,9 +239,10 @@ crypto_create_session(struct fcrypt *fcr, struct 
session_op *sop)
                        ret = -EINVAL;
                        goto error_hash;
                }
-
-               ret = copy_from_user(keyp, sop->mackey, sop->mackeylen);
-               if (unlikely(ret)) {
+               
+               if (unlikely(copy_from_user(keyp, sop->mackey,
+                                           sop->mackeylen))) {
+                       ret = -EFAULT;
                        goto error_hash;
                }
 
@@ -250,13 +255,18 @@ crypto_create_session(struct fcrypt *fcr, struct 
session_op *sop)
                }
        }
 
-       ses_new->array_size = 16;
+       ses_new->array_size = DEFAULT_PREALLOC_PAGES;
        dprintk(2, KERN_DEBUG, "%s: preallocating for %d user pages\n",
                        __func__, ses_new->array_size);
        ses_new->pages = kzalloc(ses_new->array_size *
                        sizeof(struct page *), GFP_KERNEL);
        ses_new->sg = kzalloc(ses_new->array_size *
                        sizeof(struct scatterlist), GFP_KERNEL);
+       if (ses_new->sg == NULL || ses_new->pages == NULL) {
+               dprintk(0,KERN_DEBUG,"Memory error\n");
+               ret = -ENOMEM;
+               goto error_hash;
+       }
 
        /* put the new session to the list */
        get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
@@ -284,6 +294,8 @@ restart:
 
 error_hash:
        cryptodev_cipher_deinit( &ses_new->cdata);
+       kfree(ses_new->sg);
+       kfree(ses_new->pages);
 error_cipher:
        if (ses_new) kfree(ses_new);
 
@@ -434,7 +446,7 @@ static int
 __crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop)
 {
        char *data;
-       char __user *src, __user *dst;
+       char __user *src, *dst;
        struct scatterlist sg;
        size_t nbytes, bufsize;
        int ret = 0;
@@ -453,9 +465,10 @@ __crypto_run_std(struct csession *ses_ptr, struct crypt_op 
*cop)
        while(nbytes > 0) {
                size_t current_len = nbytes > bufsize ? bufsize : nbytes;
 
-               ret = copy_from_user(data, src, current_len);
-               if (unlikely(ret))
+               if (unlikely(copy_from_user(data, src, current_len))) {
+                       ret = -EFAULT;
                        break;
+               }
 
                sg_init_one(&sg, data, current_len);
 
@@ -465,9 +478,10 @@ __crypto_run_std(struct csession *ses_ptr, struct crypt_op 
*cop)
                        break;
 
                if (ses_ptr->cdata.init != 0) {
-                       ret = copy_to_user(dst, data, current_len);
-                       if (unlikely(ret))
+                       if (unlikely(copy_to_user(dst, data, current_len))) {
+                               ret = -EFAULT;
                                break;
+                       }
                }
 
                dst += current_len;
@@ -481,7 +495,7 @@ __crypto_run_std(struct csession *ses_ptr, struct crypt_op 
*cop)
 
 #ifndef DISABLE_ZCOPY
 
-static void release_user_pages(struct page **pg, int pagecount)
+void release_user_pages(struct page **pg, int pagecount)
 {
        while (pagecount--) {
                if (!PageReserved(pg[pagecount]))
@@ -490,18 +504,11 @@ static void release_user_pages(struct page **pg, int 
pagecount)
        }
 }
 
-/* last page - first page + 1 */
-#define PAGECOUNT(buf, buflen) \
-        ((((unsigned long)(buf + buflen - 1) & PAGE_MASK) >> PAGE_SHIFT) - \
-         (((unsigned long) buf               & PAGE_MASK) >> PAGE_SHIFT) + 1)
-
 /* offset of buf in it's first page */
 #define PAGEOFFSET(buf) ((unsigned long)buf & ~PAGE_MASK)
 
-#define MIN(a, b)      ((a > b) ? b : a)
-
 /* fetch the pages addr resides in into pg and initialise sg with them */
-static int __get_userbuf(uint8_t *addr, uint32_t len, int write,
+int __get_userbuf(uint8_t __user *addr, uint32_t len, int write,
                int pgcount, struct page **pg, struct scatterlist *sg)
 {
        int ret, pglen, i = 0;
@@ -516,12 +523,12 @@ static int __get_userbuf(uint8_t *addr, uint32_t len, int 
write,
 
        sg_init_table(sg, pgcount);
 
-       pglen = MIN(PAGE_SIZE - PAGEOFFSET(addr), len);
+       pglen = min((ptrdiff_t)(PAGE_SIZE - PAGEOFFSET(addr)), (ptrdiff_t)len);
        sg_set_page(sg, pg[i++], pglen, PAGEOFFSET(addr));
 
        len -= pglen;
        for (sgp = sg_next(sg); len; sgp = sg_next(sgp)) {
-               pglen = MIN(PAGE_SIZE, len);
+               pglen = min((uint32_t)PAGE_SIZE, len);
                sg_set_page(sgp, pg[i++], pglen, 0);
                len -= pglen;
        }
@@ -536,31 +543,44 @@ static int get_userbuf(struct csession *ses,
 {
        int src_pagecount, dst_pagecount = 0, pagecount, write_src = 1;
 
-       BUG_ON(!cop->src);
+       if (cop->src == NULL) {
+               return -EINVAL;
+       }
+
        src_pagecount = PAGECOUNT(cop->src, cop->len);
        if (!ses->cdata.init) {         /* hashing only */
                write_src = 0;
        } else if (cop->src != cop->dst) {      /* non-in-situ transformation */
-               BUG_ON(!cop->dst);
+               if (cop->dst == NULL) {
+                       return -EINVAL;
+               }
                dst_pagecount = PAGECOUNT(cop->dst, cop->len);
                write_src = 0;
        }
        (*tot_pages) = pagecount = src_pagecount + dst_pagecount;
 
        if (pagecount > ses->array_size) {
-               while (ses->array_size < pagecount)
-                       ses->array_size *= 2;
+               struct scatterlist *sg;
+               struct page **pages;
+               int array_size;
 
-               dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n",
-                               __func__, ses->array_size);
-               ses->pages = krealloc(ses->pages, ses->array_size *
-                               sizeof(struct page *), GFP_KERNEL);
-               ses->sg = krealloc(ses->sg, ses->array_size *
-                               sizeof(struct scatterlist), GFP_KERNEL);
+               for (array_size = ses->array_size; array_size < pagecount;
+                    array_size *= 2)
+                       ;
 
-               if (ses->sg == NULL || ses->pages == NULL) {
+               dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n",
+                               __func__, array_size);
+               pages = krealloc(ses->pages, array_size * sizeof(struct page *),
+                                GFP_KERNEL);
+               if (pages == NULL)
                        return -ENOMEM;
-               }
+               ses->pages = pages;
+               sg = krealloc(ses->sg, array_size * sizeof(struct scatterlist),
+                             GFP_KERNEL);
+               if (sg == NULL)
+                       return -ENOMEM;
+               ses->sg = sg;
+               ses->array_size = array_size;
        }
 
        if (__get_userbuf(cop->src, cop->len, write_src,
@@ -648,6 +668,7 @@ static int crypto_run(struct fcrypt *fcr, struct crypt_op 
*cop)
                        ret = copy_from_user(iv, cop->iv, min( (int)sizeof(iv), 
(ses_ptr->cdata.ivsize)));
                        if (unlikely(ret)) {
                                dprintk(1, KERN_ERR, "error copying IV (%d 
bytes)\n", min( (int)sizeof(iv), (ses_ptr->cdata.ivsize)));
+                               ret = -EFAULT;
                                goto out_unlock;
                        }
 
@@ -670,8 +691,10 @@ static int crypto_run(struct fcrypt *fcr, struct crypt_op 
*cop)
                        goto out_unlock;
                }
 
-               if (unlikely(copy_to_user(cop->mac, hash_output, 
ses_ptr->hdata.digestsize)))
+               if (unlikely(copy_to_user(cop->mac, hash_output, 
ses_ptr->hdata.digestsize))) {
+                       ret = -EFAULT;
                        goto out_unlock;
+               }
        }
 
 #if defined(CRYPTODEV_STATS)
@@ -694,28 +717,28 @@ out_unlock:
 static int
 cryptodev_open(struct inode *inode, struct file *filp)
 {
-       struct fcrypt *fcr;
+       struct crypt_priv *pcr;
 
-       fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
-       if(!fcr)
+       pcr = kmalloc(sizeof(*pcr), GFP_KERNEL);
+       if(!pcr)
                return -ENOMEM;
 
-       memset(fcr, 0, sizeof(*fcr));
-       init_MUTEX(&fcr->sem);
-       INIT_LIST_HEAD(&fcr->list);
-       filp->private_data = fcr;
-
+       memset(pcr, 0, sizeof(*pcr));
+       init_MUTEX(&pcr->fcrypt.sem);
+       INIT_LIST_HEAD(&pcr->fcrypt.list);
+       
+       filp->private_data = pcr;
        return 0;
 }
 
 static int
 cryptodev_release(struct inode *inode, struct file *filp)
 {
-       struct fcrypt *fcr = filp->private_data;
+       struct crypt_priv *pcr = filp->private_data;
 
-       if(fcr) {
-               crypto_finish_all_sessions(fcr);
-               kfree(fcr);
+       if(pcr) {
+               crypto_finish_all_sessions(&pcr->fcrypt);
+               kfree(pcr);
                filp->private_data = NULL;
        }
 
@@ -725,67 +748,73 @@ cryptodev_release(struct inode *inode, struct file *filp)
 static int
 clonefd(struct file *filp)
 {
-       struct fdtable *fdt = files_fdtable(current->files);
        int ret;
        ret = get_unused_fd();
        if (ret >= 0) {
                        get_file(filp);
-                       FD_SET(ret, fdt->open_fds);
                        fd_install(ret, filp);
        }
 
        return ret;
 }
 
-static int
-cryptodev_ioctl(struct inode *inode, struct file *filp,
-               unsigned int cmd, unsigned long arg)
+static long
+cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
 {
-       int __user *p = (void __user *)arg;
+       void __user *arg = (void __user *)arg_;
+       int __user *p = arg;
        struct session_op sop;
        struct crypt_op cop;
-       struct fcrypt *fcr = filp->private_data;
+       struct crypt_priv *pcr = filp->private_data;
+       struct fcrypt * fcr;
        uint32_t ses;
        int ret, fd;
 
-       if (unlikely(!fcr))
+       if (unlikely(!pcr))
                BUG();
 
+       fcr = &pcr->fcrypt;
+
        switch (cmd) {
                case CIOCASYMFEAT:
-                       put_user(0, p);
-                       return 0;
+                       return put_user(0, p);
                case CRIOGET:
                        fd = clonefd(filp);
-                       put_user(fd, p);
-                       return 0;
-
-               case CIOCGSESSION:
-                       ret = copy_from_user(&sop, (void*)arg, sizeof(sop));
-                       if (unlikely(ret))
+                       ret = put_user(fd, p);
+                       if (unlikely(ret)) {
+                               sys_close(fd);
                                return ret;
+                       }
+                       return ret;
+               case CIOCGSESSION:
+                       if (unlikely(copy_from_user(&sop, arg, sizeof(sop))))
+                               return -EFAULT;
 
                        ret = crypto_create_session(fcr, &sop);
                        if (unlikely(ret))
                                return ret;
-                       return copy_to_user((void*)arg, &sop, sizeof(sop));
-
+                       ret = copy_to_user(arg, &sop, sizeof(sop));
+                       if (unlikely(ret)) {
+                               crypto_finish_session(fcr, sop.ses);
+                               return -EFAULT;
+                       }
+                       return ret;
                case CIOCFSESSION:
-                       ret = get_user(ses, (uint32_t*)arg);
+                       ret = get_user(ses, (uint32_t __user *)arg);
                        if (unlikely(ret))
                                return ret;
-
-                       return crypto_finish_session(fcr, ses);
-
+                       ret = crypto_finish_session(fcr, ses);
+                       return ret;
                case CIOCCRYPT:
-                       ret = copy_from_user(&cop, (void*)arg, sizeof(cop));
-                       if (unlikely(ret))
-                               return ret;
+                       if (unlikely(copy_from_user(&cop, arg, sizeof(cop))))
+                               return -EFAULT;
 
                        ret = crypto_run(fcr, &cop);
                        if (unlikely(ret))
                                return ret;
-                       return copy_to_user((void*)arg, &cop, sizeof(cop));
+                       if (unlikely(copy_to_user(arg, &cop, sizeof(cop))))
+                               return -EFAULT;
+                       return 0;
 
                default:
                        return -EINVAL;
@@ -850,8 +879,9 @@ crypt_op_to_compat(struct crypt_op *cop, struct 
compat_crypt_op *compat)
 }
 
 static long
-cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
 {
+       void __user *arg = (void __user *)arg_;
        struct fcrypt *fcr = file->private_data;
        struct session_op sop;
        struct compat_session_op compat_sop;
@@ -866,14 +896,12 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
        case CIOCASYMFEAT:
        case CRIOGET:
        case CIOCFSESSION:
-               return cryptodev_ioctl(NULL, file, cmd, arg);
+               return cryptodev_ioctl(file, cmd, arg_);
 
        case COMPAT_CIOCGSESSION:
-               ret = copy_from_user(&compat_sop,
-                               (void *)arg, sizeof(compat_sop));
-               if (unlikely(ret))
-                       return ret;
-
+               if (unlikely(copy_from_user(&compat_sop, arg,
+                                           sizeof(compat_sop))))
+                       return -EFAULT;
                compat_to_session_op(&compat_sop, &sop);
 
                ret = crypto_create_session(fcr, &sop);
@@ -881,14 +909,17 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
                        return ret;
 
                session_op_to_compat(&sop, &compat_sop);
-               return copy_to_user((void*)arg,
-                               &compat_sop, sizeof(compat_sop));
+               ret = copy_to_user(arg, &compat_sop, sizeof(compat_sop));
+               if (unlikely(ret)) {
+                       crypto_finish_session(fcr, sop.ses);
+                       return -EFAULT;
+               }
+               return ret;
 
        case COMPAT_CIOCCRYPT:
-               ret = copy_from_user(&compat_cop,
-                               (void*)arg, sizeof(compat_cop));
-               if (unlikely(ret))
-                       return ret;
+               if (unlikely(copy_from_user(&compat_cop, arg,
+                                           sizeof(compat_cop))))
+                       return -EFAULT;
 
                compat_to_crypt_op(&compat_cop, &cop);
 
@@ -897,8 +928,10 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
                        return ret;
 
                crypt_op_to_compat(&cop, &compat_cop);
-               return copy_to_user((void*)arg,
-                               &compat_cop, sizeof(compat_cop));
+               if (unlikely(copy_to_user(arg, &compat_cop,
+                                         sizeof(compat_cop))))
+                       return -EFAULT;
+               return 0;
 
        default:
                return -EINVAL;
@@ -907,45 +940,44 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg)
 
 #endif /* CONFIG_COMPAT */
 
-struct file_operations cryptodev_fops = {
+static const struct file_operations cryptodev_fops = {
        .owner = THIS_MODULE,
        .open = cryptodev_open,
        .release = cryptodev_release,
-       .ioctl = cryptodev_ioctl,
+       .unlocked_ioctl = cryptodev_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = cryptodev_compat_ioctl,
 #endif /* CONFIG_COMPAT */
 };
 
-struct miscdevice cryptodev = {
+static struct miscdevice cryptodev = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = "crypto",
        .fops = &cryptodev_fops,
 };
 
-static int
+static int __init
 cryptodev_register(void)
 {
        int rc;
 
        rc = misc_register (&cryptodev);
        if (unlikely(rc)) {
-               printk(KERN_ERR PFX "registeration of /dev/crypto failed\n");
+               printk(KERN_ERR PFX "registration of /dev/crypto failed\n");
                return rc;
        }
 
        return 0;
 }
 
-static void
+static void __exit
 cryptodev_deregister(void)
 {
        misc_deregister(&cryptodev);
 }
 
 /* ====== Module init/exit ====== */
-
-int __init init_cryptodev(void)
+static int __init init_cryptodev(void)
 {
        int rc;
 
@@ -958,7 +990,7 @@ int __init init_cryptodev(void)
        return 0;
 }
 
-void __exit exit_cryptodev(void)
+static void __exit exit_cryptodev(void)
 {
        cryptodev_deregister();
        printk(KERN_INFO PFX "driver unloaded.\n");
-- 
1.7.0.4


_______________________________________________
Cryptodev-linux-devel mailing list
Cryptodev-linux-devel@gna.org
https://mail.gna.org/listinfo/cryptodev-linux-devel

Reply via email to