From 3fc710f5fb932b381799a372488d0bd3b40c9e8d Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil.sutter@viprinet.com>
Date: Thu, 21 Oct 2010 18:26:02 +0200
Subject: [PATCH 097/291] cryptodev: introduce

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.

Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
---
 drivers/staging/crypto/cryptodev/cryptodev_int.h  |  5 ++
 drivers/staging/crypto/cryptodev/cryptodev_main.c | 79 +++++++++++++++++------
 2 files changed, 64 insertions(+), 20 deletions(-)

diff --git a/drivers/staging/crypto/cryptodev/cryptodev_int.h b/drivers/staging/crypto/cryptodev/cryptodev_int.h
index 15eb5bf7e566..6b0b90910abf 100644
--- a/drivers/staging/crypto/cryptodev/cryptodev_int.h
+++ b/drivers/staging/crypto/cryptodev/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/drivers/staging/crypto/cryptodev/cryptodev_main.c b/drivers/staging/crypto/cryptodev/cryptodev_main.c
index f3ccc069a80a..fb5172375b79 100644
--- a/drivers/staging/crypto/cryptodev/cryptodev_main.c
+++ b/drivers/staging/crypto/cryptodev/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;
-- 
2.1.0

