diff options
Diffstat (limited to 'drivers/staging/android/ashmem.c')
-rw-r--r-- | drivers/staging/android/ashmem.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 74d497d39c5a..8044510d8ec6 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -351,8 +351,23 @@ static inline vm_flags_t calc_vm_may_flags(unsigned long prot) _calc_vm_trans(prot, PROT_EXEC, VM_MAYEXEC); } +static int ashmem_vmfile_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* do not allow to mmap ashmem backing shmem file directly */ + return -EPERM; +} + +static unsigned long +ashmem_vmfile_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); +} + static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) { + static struct file_operations vmfile_fops; struct ashmem_area *asma = file->private_data; int ret = 0; @@ -393,6 +408,19 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) } vmfile->f_mode |= FMODE_LSEEK; asma->file = vmfile; + /* + * override mmap operation of the vmfile so that it can't be + * remapped which would lead to creation of a new vma with no + * asma permission checks. Have to override get_unmapped_area + * as well to prevent VM_BUG_ON check for f_ops modification. + */ + if (!vmfile_fops.mmap) { + vmfile_fops = *vmfile->f_op; + vmfile_fops.mmap = ashmem_vmfile_mmap; + vmfile_fops.get_unmapped_area = + ashmem_vmfile_get_unmapped_area; + } + vmfile->f_op = &vmfile_fops; } get_file(asma->file); @@ -537,14 +565,14 @@ static int set_name(struct ashmem_area *asma, void __user *name) len = strncpy_from_user(local_name, name, ASHMEM_NAME_LEN); if (len < 0) return len; - if (len == ASHMEM_NAME_LEN) - local_name[ASHMEM_NAME_LEN - 1] = '\0'; + mutex_lock(&ashmem_mutex); /* cannot change an existing mapping's name */ if (asma->file) ret = -EINVAL; else - strcpy(asma->name + ASHMEM_NAME_PREFIX_LEN, local_name); + strscpy(asma->name + ASHMEM_NAME_PREFIX_LEN, local_name, + ASHMEM_NAME_LEN); mutex_unlock(&ashmem_mutex); return ret; |