aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerban Constantinescu <serban.constantinescu@arm.com>2012-09-25 16:58:13 +0100
committerZach Pfeffer <zach.pfeffer@linaro.org>2012-10-04 21:03:16 -0500
commit57952f2f3c171519877d0f37785cb8554577d4e5 (patch)
tree6443539b94dd504ed530000b8f2db46f6cefb4d2
parent1819da661a46fd3c7f5919df64ff31f0c597236c (diff)
downloadlinux-aarch64-57952f2f3c171519877d0f37785cb8554577d4e5.tar.gz
Android32: Add support for 32-bit Ashmem calls in a 64-bit kernel
Android's shared memory subsystem, Ashmem, does not support calls from a 32-bit userspace in a 64 bit kernel. This patch adds support for syscalls from a 32-bit userspace in a 64-bit kernel. Most of the changes are applied to types that change sizes between 32 and 64 bit world. The patch has been tested successfully on ARMv8 AEM. NOTE: The patch should be considered development quality. Signed-off-by: Serban Constantinescu <serban.constantinescu@arm.com>
-rw-r--r--drivers/staging/android/ashmem.c68
-rw-r--r--drivers/staging/android/ashmem.h4
2 files changed, 51 insertions, 21 deletions
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 69cf2db1d69..77234bbef8e 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -586,6 +586,22 @@ static int ashmem_get_pin_status(struct ashmem_area *asma, size_t pgstart,
return ret;
}
+/* checks pointers when casting back to 32-bit user-space usage
+ * it will check that the high 4bytes are 0; thus a 32-bit userspace pointer
+ */
+static unsigned int revert_ptr(unsigned long ptr)
+{
+ unsigned int ptr_compat = (unsigned int) ptr;
+ unsigned int ptr_assert = (unsigned int) (ptr >> 32);
+
+ if(unlikely(ptr_assert != 0))
+ {
+ printk("ERROR: compat_ptr failed in ashmem!\n");
+ return 0;
+ }
+ return ptr_compat;
+}
+
static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
void __user *p)
{
@@ -595,13 +611,12 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
if (unlikely(!asma->file))
return -EINVAL;
-
if (unlikely(copy_from_user(&pin, p, sizeof(pin))))
return -EFAULT;
/* per custom, you can pass zero for len to mean "everything onward" */
if (!pin.len)
- pin.len = PAGE_ALIGN(asma->size) - pin.offset;
+ pin.len = revert_ptr(PAGE_ALIGN(asma->size) - pin.offset);
if (unlikely((pin.offset | pin.len) & ~PAGE_MASK))
return -EINVAL;
@@ -639,37 +654,49 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct ashmem_area *asma = file->private_data;
long ret = -ENOTTY;
- switch (cmd) {
- case ASHMEM_SET_NAME:
- ret = set_name(asma, (void __user *) arg);
+ switch (_IOC_NR(cmd)) {
+
+ case _IOC_NR(ASHMEM_SET_NAME):
+ if(_IOC_SIZE(ASHMEM_SET_NAME) != sizeof(char[ASHMEM_NAME_LEN]))
+ printk(KERN_ERR "ashmem: ERROR: ioctl: SET_NAME: sizeof U/K structure differ\n");
+ ret = set_name(asma, (void __user *) compat_ptr(arg));
break;
- case ASHMEM_GET_NAME:
- ret = get_name(asma, (void __user *) arg);
+ case _IOC_NR(ASHMEM_GET_NAME):
+ if(_IOC_SIZE(ASHMEM_GET_NAME) != sizeof(char[ASHMEM_NAME_LEN]))
+ printk(KERN_ERR "ashmem: ERROR: ioctl: GET_NAME: sizeof U/K structure differ\n");
+ ret = get_name(asma, (void __user *) compat_ptr(arg));
break;
- case ASHMEM_SET_SIZE:
+ case _IOC_NR(ASHMEM_SET_SIZE):
+ if(_IOC_SIZE(ASHMEM_SET_SIZE) != sizeof(uint32_t))
+ printk(KERN_ERR "ashmem: ERROR: ioctl: SET_SIZE: sizeof U/K structure differ\n");
ret = -EINVAL;
if (!asma->file) {
ret = 0;
asma->size = (size_t) arg;
}
break;
- case ASHMEM_GET_SIZE:
+ case _IOC_NR(ASHMEM_GET_SIZE):
ret = asma->size;
- break;
- case ASHMEM_SET_PROT_MASK:
+ break;
+ case _IOC_NR(ASHMEM_SET_PROT_MASK):
+ if(_IOC_SIZE(ASHMEM_SET_PROT_MASK) != sizeof(uint32_t))
+ printk(KERN_ERR "ashmem: ERROR: ioctl: ASHMEM_SET_PROT_MASK: sizeof U/K structure differ\n");
ret = set_prot_mask(asma, arg);
break;
- case ASHMEM_GET_PROT_MASK:
- ret = asma->prot_mask;
- break;
- case ASHMEM_PIN:
- case ASHMEM_UNPIN:
- case ASHMEM_GET_PIN_STATUS:
- ret = ashmem_pin_unpin(asma, cmd, (void __user *) arg);
+ case _IOC_NR(ASHMEM_GET_PROT_MASK):
+ ret = asma->prot_mask;
+ break;
+ case _IOC_NR(ASHMEM_PIN):
+ case _IOC_NR(ASHMEM_UNPIN):
+ case _IOC_NR(ASHMEM_GET_PIN_STATUS):
+ if(_IOC_SIZE(ASHMEM_PIN) != sizeof(struct ashmem_pin))
+ printk(KERN_ERR "ashmem: ERROR: ioctl: ASHMEM_PIN: sizeof U/K structure differ\n");
+ ret = ashmem_pin_unpin(asma, cmd, (void __user *) compat_ptr(arg));
break;
- case ASHMEM_PURGE_ALL_CACHES:
+ case _IOC_NR(ASHMEM_PURGE_ALL_CACHES):
ret = -EPERM;
if (capable(CAP_SYS_ADMIN)) {
+ printk(KERN_ERR "ashmem: ioctl: ASHMEM_PURGE: user: sys-administrator\n");
struct shrink_control sc = {
.gfp_mask = GFP_KERNEL,
.nr_to_scan = 0,
@@ -679,6 +706,9 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ashmem_shrink(&ashmem_shrinker, &sc);
}
break;
+ default:
+ printk(KERN_ERR "ashmem: ERROR: ioctl: IOCTL No. does not match\n");
+ break;
}
return ret;
diff --git a/drivers/staging/android/ashmem.h b/drivers/staging/android/ashmem.h
index 1976b10ef93..f19d8908eac 100644
--- a/drivers/staging/android/ashmem.h
+++ b/drivers/staging/android/ashmem.h
@@ -36,9 +36,9 @@ struct ashmem_pin {
#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
-#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
+#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, uint32_t)
#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
-#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
+#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, uint32_t)
#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
#define ASHMEM_PIN _IOW(__ASHMEMIOC, 7, struct ashmem_pin)
#define ASHMEM_UNPIN _IOW(__ASHMEMIOC, 8, struct ashmem_pin)