[PATCH v2 6/6] misc: fastrpc: Add support for compat ioctls

From: Srinivas Kandagatla
Date: Fri Dec 07 2018 - 11:35:41 EST


This patch adds support for compat ioctl from 32 bits userland to
Qualcomm fastrpc driver.

Supported ioctls in this change are INIT, INVOKE, and ALLOC/FREE_DMA.

Most of the work is derived from various downstream Qualcomm kernels.
Credits to various Qualcomm authors who have contributed to this code.
Specially Tharun Kumar Merugu <mtharu@xxxxxxxxxxxxxx>

Co-developed-by: Thierry Escande <thierry.escande@xxxxxxxxxx>
Signed-off-by: Thierry Escande <thierry.escande@xxxxxxxxxx>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx>
---
drivers/misc/fastrpc.c | 71 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 5ea2bba1e4bd..f36657263183 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -2,6 +2,7 @@
// Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited

+#include <linux/compat.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/dma-buf.h>
@@ -194,6 +195,22 @@ struct fastrpc_user {
struct mutex mutex;
};

+#ifdef CONFIG_COMPAT
+
+#define FASTRPC_IOCTL_INVOKE32 _IOWR('R', 3, struct fastrpc_invoke32)
+struct fastrpc_invoke_args32 {
+ __s32 fd;
+ compat_size_t length;
+ compat_caddr_t ptr;
+};
+
+struct fastrpc_invoke32 {
+ __u32 handle;
+ __u32 sc;
+ compat_uptr_t args;
+};
+#endif
+
static void fastrpc_free_map(struct kref *ref)
{
struct fastrpc_map *map;
@@ -1092,6 +1109,52 @@ static long fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
return err;
}

+#ifdef CONFIG_COMPAT
+static long fastrpc_invoke32(struct fastrpc_user *fl, compat_uptr_t arg)
+{
+ struct fastrpc_invoke_args32 *args32 = NULL;
+ struct fastrpc_invoke_args *args = NULL;
+ struct fastrpc_invoke32 inv32;
+ struct fastrpc_invoke inv;
+ int i, ret, nscalars;
+
+ if (copy_from_user(&inv32, compat_ptr(arg), sizeof(inv32)))
+ return -EFAULT;
+
+ inv.handle = inv32.handle;
+ inv.sc = inv32.sc;
+ inv.args = NULL;
+ nscalars = REMOTE_SCALARS_LENGTH(inv.sc);
+
+ if (nscalars) {
+ args32 = kcalloc(nscalars, sizeof(*args32), GFP_KERNEL);
+ if (!args32)
+ return -ENOMEM;
+
+ if (copy_from_user(args32, compat_ptr(inv32.args),
+ nscalars * sizeof(*args32)))
+ return -EFAULT;
+
+ args = kcalloc(nscalars, sizeof(*args), GFP_KERNEL);
+ if (!args)
+ return -ENOMEM;
+
+ for (i = 0; i < nscalars; i++) {
+ args[i].length = args32[i].length;
+ args[i].ptr = (void *)(unsigned long)args32[i].ptr;
+ args[i].fd = args32[i].fd;
+ }
+ inv.args = &args[0];
+ }
+
+ ret = fastrpc_internal_invoke(fl, 0, &inv);
+ kfree(args32);
+ kfree(args);
+
+ return ret;
+}
+#endif
+
static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
@@ -1103,6 +1166,11 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
case FASTRPC_IOCTL_INVOKE:
err = fastrpc_invoke(fl, argp);
break;
+#ifdef CONFIG_COMPAT
+ case FASTRPC_IOCTL_INVOKE32:
+ err = fastrpc_invoke32(fl, ptr_to_compat(argp));
+ break;
+#endif
case FASTRPC_IOCTL_INIT_ATTACH:
err = fastrpc_init_attach(fl);
break;
@@ -1131,6 +1199,9 @@ static const struct file_operations fastrpc_fops = {
.open = fastrpc_device_open,
.release = fastrpc_device_release,
.unlocked_ioctl = fastrpc_device_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = fastrpc_device_ioctl,
+#endif
};

static int fastrpc_cb_probe(struct platform_device *pdev)
--
2.19.2