CHROMIUM: virtwl: use compat_ptr in compat_ioctl implementations

BUG=None
TEST=virtio_wl.c compiles

Change-Id: I5e00d8d98d48996bc1c7a61babe4ea291ed61cc7
Signed-off-by: Zach Reizner <zachr@google.com>
Reviewed-on: https://chromium-review.googlesource.com/865494
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dmitry Torokhov <dtor@chromium.org>
(cherry picked from commit efa89ecc24b75cc89384f715135ec25e1caa226d)
Reviewed-on: https://chromium-review.googlesource.com/957809
diff --git a/drivers/virtio/virtio_wl.c b/drivers/virtio/virtio_wl.c
index e7d0d3d..f5f1e1d 100644
--- a/drivers/virtio/virtio_wl.c
+++ b/drivers/virtio/virtio_wl.c
@@ -41,6 +41,7 @@
 
 #include <linux/anon_inodes.h>
 #include <linux/cdev.h>
+#include <linux/compat.h>
 #include <linux/completion.h>
 #include <linux/err.h>
 #include <linux/fdtable.h>
@@ -879,16 +880,14 @@
 	return ERR_PTR(ret);
 }
 
-static long virtwl_ioctl_send(struct file *filp, unsigned long arg)
+static long virtwl_ioctl_send(struct file *filp, void __user *ptr)
 {
 	struct virtwl_vfd *vfd = filp->private_data;
 	struct virtwl_ioctl_txn ioctl_send;
-	void __user *user_data = (void __user *)arg +
-				 sizeof(struct virtwl_ioctl_txn);
+	void __user *user_data = ptr + sizeof(struct virtwl_ioctl_txn);
 	int ret;
 
-	ret = copy_from_user(&ioctl_send, (void __user *)arg,
-			     sizeof(struct virtwl_ioctl_txn));
+	ret = copy_from_user(&ioctl_send, ptr, sizeof(struct virtwl_ioctl_txn));
 	if (ret)
 		return -EFAULT;
 
@@ -901,12 +900,11 @@
 		       filp->f_flags & O_NONBLOCK);
 }
 
-static long virtwl_ioctl_recv(struct file *filp, unsigned long arg)
+static long virtwl_ioctl_recv(struct file *filp, void __user *ptr)
 {
 	struct virtwl_ioctl_txn ioctl_recv;
-	void __user *user_data = (void __user *)arg +
-				 sizeof(struct virtwl_ioctl_txn);
-	int __user *user_fds = (int __user *)arg;
+	void __user *user_data = ptr + sizeof(struct virtwl_ioctl_txn);
+	int __user *user_fds = (int __user *)ptr;
 	size_t vfd_count = VIRTWL_SEND_MAX_ALLOCS;
 	struct virtwl_vfd *vfds[VIRTWL_SEND_MAX_ALLOCS] = { 0 };
 	int fds[VIRTWL_SEND_MAX_ALLOCS];
@@ -917,8 +915,7 @@
 	for (i = 0; i < VIRTWL_SEND_MAX_ALLOCS; i++)
 		fds[i] = -1;
 
-	ret = copy_from_user(&ioctl_recv, (void __user *)arg,
-			     sizeof(struct virtwl_ioctl_txn));
+	ret = copy_from_user(&ioctl_recv, ptr, sizeof(struct virtwl_ioctl_txn));
 	if (ret)
 		return -EFAULT;
 
@@ -932,7 +929,7 @@
 	if (ret < 0)
 		return ret;
 
-	ret = copy_to_user(&((struct virtwl_ioctl_txn __user *)arg)->len, &ret,
+	ret = copy_to_user(&((struct virtwl_ioctl_txn __user *)ptr)->len, &ret,
 			   sizeof(ioctl_recv.len));
 	if (ret) {
 		ret = -EFAULT;
@@ -969,27 +966,26 @@
 }
 
 static long virtwl_vfd_ioctl(struct file *filp, unsigned int cmd,
-			     unsigned long arg)
+			     void __user *ptr)
 {
 	switch (cmd) {
 	case VIRTWL_IOCTL_SEND:
-		return virtwl_ioctl_send(filp, arg);
+		return virtwl_ioctl_send(filp, ptr);
 	case VIRTWL_IOCTL_RECV:
-		return virtwl_ioctl_recv(filp, arg);
+		return virtwl_ioctl_recv(filp, ptr);
 	default:
 		return -ENOTTY;
 	}
 }
 
-static long virtwl_ioctl_new(struct file *filp, unsigned long arg)
+static long virtwl_ioctl_new(struct file *filp, void __user *ptr)
 {
 	struct virtwl_info *vi = filp->private_data;
 	struct virtwl_vfd *vfd;
 	struct virtwl_ioctl_new ioctl_new;
 	int ret;
 
-	ret = copy_from_user(&ioctl_new, (void __user *)arg,
-			     sizeof(struct virtwl_ioctl_new));
+	ret = copy_from_user(&ioctl_new, ptr, sizeof(struct virtwl_ioctl_new));
 	if (ret)
 		return -EFAULT;
 
@@ -1008,8 +1004,7 @@
 	}
 
 	ioctl_new.fd = ret;
-	ret = copy_to_user((void __user *)arg, &ioctl_new,
-			   sizeof(struct virtwl_ioctl_new));
+	ret = copy_to_user(ptr, &ioctl_new, sizeof(struct virtwl_ioctl_new));
 	if (ret) {
 		/* The release operation will handle freeing this alloc */
 		sys_close(ioctl_new.fd);
@@ -1019,8 +1014,8 @@
 	return 0;
 }
 
-static long virtwl_ioctl(struct file *filp, unsigned int cmd,
-			 unsigned long arg)
+static long virtwl_ioctl_ptr(struct file *filp, unsigned int cmd,
+			     void *__user ptr)
 {
 	int err = 0;
 
@@ -1030,27 +1025,36 @@
 		return -ENOTTY;
 
 	if (_IOC_DIR(cmd) & _IOC_READ) {
-		err = !access_ok(VERIFY_WRITE, (void __user *)arg,
-				 _IOC_SIZE(cmd));
+		err = !access_ok(VERIFY_WRITE, ptr, _IOC_SIZE(cmd));
 	} else if (_IOC_DIR(cmd) & _IOC_WRITE) {
-		err = !access_ok(VERIFY_READ, (void __user *)arg,
-				 _IOC_SIZE(cmd));
+		err = !access_ok(VERIFY_READ, ptr, _IOC_SIZE(cmd));
 	}
 
 	if (err)
 		return -EFAULT;
 
 	if (filp->f_op == &virtwl_vfd_fops)
-		return virtwl_vfd_ioctl(filp, cmd, arg);
+		return virtwl_vfd_ioctl(filp, cmd, ptr);
 
 	switch (cmd) {
 	case VIRTWL_IOCTL_NEW:
-		return virtwl_ioctl_new(filp, arg);
+		return virtwl_ioctl_new(filp, ptr);
 	default:
 		return -ENOTTY;
 	}
 }
 
+static long virtwl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	return virtwl_ioctl_ptr(filp, cmd, (void *__user)arg);
+}
+
+static long virtwl_ioctl_compat(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	return virtwl_ioctl_ptr(filp, cmd, compat_ptr(arg));
+}
+
 static int virtwl_release(struct inode *inodep, struct file *filp)
 {
 	return 0;
@@ -1059,7 +1063,7 @@
 static const struct file_operations virtwl_fops = {
 	.open = virtwl_open,
 	.unlocked_ioctl = virtwl_ioctl,
-	.compat_ioctl = virtwl_ioctl,
+	.compat_ioctl = virtwl_ioctl_compat,
 	.release = virtwl_release,
 };
 
@@ -1067,7 +1071,7 @@
 	.mmap = virtwl_vfd_mmap,
 	.poll = virtwl_vfd_poll,
 	.unlocked_ioctl = virtwl_ioctl,
-	.compat_ioctl = virtwl_ioctl,
+	.compat_ioctl = virtwl_ioctl_compat,
 	.release = virtwl_vfd_release,
 };