diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index e3e0b0973410..ecbdd412d378 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1962,6 +1962,20 @@ static inline int _check_region(unsigned long start, unsigned long size, return (end > len); } +static int check_vma_flags(struct vm_area_struct *vma, + unsigned int flags) +{ + unsigned long flags_requested = (VM_READ | VM_WRITE); + + if (flags & KGSL_MEMFLAGS_GPUREADONLY) + flags_requested &= ~VM_WRITE; + + if ((vma->vm_flags & flags_requested) == flags_requested) + return 0; + + return -EFAULT; +} + static int check_vma(struct vm_area_struct *vma, struct file *vmfile, struct kgsl_memdesc *memdesc) { @@ -1975,7 +1989,7 @@ static int check_vma(struct vm_area_struct *vma, struct file *vmfile, if (vma->vm_start != memdesc->useraddr || (memdesc->useraddr + memdesc->size) != vma->vm_end) return -EINVAL; - return 0; + return check_vma_flags(vma, memdesc->flags); } static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, struct file *vmfile) @@ -1984,7 +1998,7 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, struct file *vmfile) long npages = 0, i; size_t sglen = (size_t) (memdesc->size / PAGE_SIZE); struct page **pages = NULL; - int write = (memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY) != 0; + int write = ((memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY) ? 0 : 1); if (sglen == 0 || sglen >= LONG_MAX) return -EINVAL; @@ -2103,6 +2117,12 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device, if (vma && vma->vm_file) { int fd; + ret = check_vma_flags(vma, entry->memdesc.flags); + if (ret) { + up_read(¤t->mm->mmap_sem); + return ret; + } + /* * Check to see that this isn't our own memory that we have * already mapped