This struct is meant as an internal wrapper around struct crypt_op, so
additional information can be passed around within the kernel module
without giving userspace access to it.
---
 cryptodev_int.h  |    5 +++
 cryptodev_main.c |   79 ++++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 64 insertions(+), 20 deletions(-)

diff --git a/cryptodev_int.h b/cryptodev_int.h
index 15eb5bf..6b0b909 100644
--- a/cryptodev_int.h
+++ b/cryptodev_int.h
@@ -117,4 +117,9 @@ struct compat_session_op {
 
 #endif /* CONFIG_COMPAT */
 
+/* kernel-internal extension to struct crypt_op */
+struct kernel_crypt_op {
+       struct crypt_op cop;
+};
+
 #endif /* CRYPTODEV_INT_H */
diff --git a/cryptodev_main.c b/cryptodev_main.c
index f3ccc06..fb51723 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -549,11 +549,12 @@ int __get_userbuf(uint8_t __user *addr, uint32_t len, int 
write,
 }
 
 /* make cop->src and cop->dst available in scatterlists */
-static int get_userbuf(struct csession *ses,
-               struct crypt_op *cop, struct scatterlist **src_sg,
-               struct scatterlist **dst_sg, int *tot_pages)
+static int get_userbuf(struct csession *ses, struct kernel_crypt_op *kcop,
+                       struct scatterlist **src_sg, struct scatterlist 
**dst_sg,
+                       int *tot_pages)
 {
        int src_pagecount, dst_pagecount = 0, pagecount, write_src = 1;
+       struct crypt_op *cop = &kcop->cop;
 
        if (cop->src == NULL)
                return -EINVAL;
@@ -618,12 +619,13 @@ static int get_userbuf(struct csession *ses,
 
 /* This is the main crypto function - zero-copy edition */
 static int
-__crypto_run_zc(struct csession *ses_ptr, struct crypt_op *cop)
+__crypto_run_zc(struct csession *ses_ptr, struct kernel_crypt_op *kcop)
 {
        struct scatterlist *src_sg, *dst_sg;
+       struct crypt_op *cop = &kcop->cop;
        int ret = 0, pagecount;
 
-       ret = get_userbuf(ses_ptr, cop, &src_sg, &dst_sg, &pagecount);
+       ret = get_userbuf(ses_ptr, kcop, &src_sg, &dst_sg, &pagecount);
        if (unlikely(ret)) {
                dprintk(1, KERN_ERR, "Error getting user pages. \
                                        Falling back to non zero copy.\n");
@@ -636,10 +638,11 @@ __crypto_run_zc(struct csession *ses_ptr, struct crypt_op 
*cop)
        return ret;
 }
 
-static int crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
+static int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop)
 {
        struct csession *ses_ptr;
        uint8_t hash_output[AALG_MAX_RESULT_LEN];
+       struct crypt_op *cop = &kcop->cop;
        int ret;
 
        if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
@@ -696,7 +699,7 @@ static int crypto_run(struct fcrypt *fcr, struct crypt_op 
*cop)
        }
 
        if (cop->len != 0) {
-               ret = __crypto_run_zc(ses_ptr, cop);
+               ret = __crypto_run_zc(ses_ptr, kcop);
                if (unlikely(ret))
                        goto out_unlock;
        }
@@ -778,13 +781,39 @@ clonefd(struct file *filp)
        return ret;
 }
 
+/* this function has to be called from process context */
+static int fill_kcop_from_cop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
+{
+       struct crypt_op *cop = &kcop->cop;
+       struct csession *ses_ptr;
+
+       /* this also enters ses_ptr->sem */
+       ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
+       if (unlikely(!ses_ptr)) {
+               dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
+               return -EINVAL;
+       }
+       mutex_unlock(&ses_ptr->sem);
+
+       return 0;
+}
+
+static int kcop_from_user(struct kernel_crypt_op *kcop,
+                          struct fcrypt *fcr, void __user *arg)
+{
+       if (unlikely(copy_from_user(&kcop->cop, arg, sizeof(kcop->cop))))
+               return -EFAULT;
+
+       return fill_kcop_from_cop(kcop, fcr);
+}
+
 static long
 cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
 {
        void __user *arg = (void __user *)arg_;
        int __user *p = arg;
        struct session_op sop;
-       struct crypt_op cop;
+       struct kernel_crypt_op kcop;
        struct crypt_priv *pcr = filp->private_data;
        struct fcrypt *fcr;
        uint32_t ses;
@@ -826,13 +855,13 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, 
unsigned long arg_)
                ret = crypto_finish_session(fcr, ses);
                return ret;
        case CIOCCRYPT:
-               if (unlikely(copy_from_user(&cop, arg, sizeof(cop))))
-                       return -EFAULT;
+               if (unlikely(ret = kcop_from_user(&kcop, fcr, arg)))
+                       return ret;
 
-               ret = crypto_run(fcr, &cop);
+               ret = crypto_run(fcr, &kcop);
                if (unlikely(ret))
                        return ret;
-               if (unlikely(copy_to_user(arg, &cop, sizeof(cop))))
+               if (unlikely(copy_to_user(arg, &kcop.cop, sizeof(kcop.cop))))
                        return -EFAULT;
                return 0;
 
@@ -898,6 +927,18 @@ crypt_op_to_compat(struct crypt_op *cop, struct 
compat_crypt_op *compat)
        compat->iv  = ptr_to_compat(cop->iv);
 }
 
+static int compat_kcop_from_user(struct kernel_crypt_op *kcop,
+                                 struct fcrypt *fcr, void __user *arg)
+{
+       struct compat_crypt_op compat_cop;
+
+       if (unlikely(copy_from_user(&compat_cop, arg, sizeof(compat_cop))))
+               return -EFAULT;
+       compat_to_crypt_op(&compat_cop, &kcop->cop);
+
+       return fill_kcop_from_cop(kcop, fcr);
+}
+
 static long
 cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
 {
@@ -905,7 +946,7 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, 
unsigned long arg_)
        struct fcrypt *fcr = file->private_data;
        struct session_op sop;
        struct compat_session_op compat_sop;
-       struct crypt_op cop;
+       struct kernel_crypt_op kcop;
        struct compat_crypt_op compat_cop;
        int ret;
 
@@ -937,17 +978,15 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg_)
                return ret;
 
        case COMPAT_CIOCCRYPT:
-               if (unlikely(copy_from_user(&compat_cop, arg,
-                                           sizeof(compat_cop))))
-                       return -EFAULT;
-
-               compat_to_crypt_op(&compat_cop, &cop);
+               ret = compat_kcop_from_user(&kcop, fcr, arg);
+               if (unlikely(ret))
+                       return ret;
 
-               ret = crypto_run(fcr, &cop);
+               ret = crypto_run(fcr, &kcop);
                if (unlikely(ret))
                        return ret;
 
-               crypt_op_to_compat(&cop, &compat_cop);
+               crypt_op_to_compat(&kcop.cop, &compat_cop);
                if (unlikely(copy_to_user(arg, &compat_cop,
                                          sizeof(compat_cop))))
                        return -EFAULT;
-- 
1.7.2.2



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

Reply via email to