From f54224a6ac85c7bd7dbd7e98a8c395b4f9ca53a2 Mon Sep 17 00:00:00 2001 From: Tarun Karra <tkarra@codeaurora.org> Date: Mon, 28 Mar 2016 12:30:58 -0700 Subject: [PATCH] msm: kgsl: verify user memory permissions before mapping to GPU driver For user memory of type KGSL_USER_MEM_TYPE_ADDR mapped to GPU driver verify permissions and map GPU permissions same as CPU permissions. If elevated permissions are requested return an error to prevent privilege escalation. Without this check user could map readonly memory into GPU driver as readwrite and gain elevated privilege. Write permissions check is currently inverted causing readonly user pages to be mapped as readwrite in GPU driver. Fix this check to map readonly pages as readonly. Bug: 28305757 CRs-Fixed: 988993 Change-Id: I0e097d7e4e4c414c0849e33bcc61a26fb94291ad Signed-off-by: Tarun Karra <tkarra@codeaurora.org> --- drivers/gpu/msm/kgsl.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index d7c5026c32fa..863782a430bc 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2549,6 +2549,20 @@ static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry, } #endif +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) { @@ -2562,7 +2576,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) @@ -2571,7 +2585,7 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, struct file *vmfile) long npages = 0; unsigned long sglen = 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); pages = kgsl_malloc(sglen * sizeof(struct page *)); if (pages == NULL) @@ -2654,6 +2668,7 @@ static int kgsl_setup_useraddr(struct kgsl_mem_entry *entry, struct kgsl_map_user_mem *param = data; struct dma_buf *dmabuf = NULL; struct vm_area_struct *vma = NULL; + int ret; if (param->offset != 0 || param->hostptr == 0 || !KGSL_IS_PAGE_ALIGNED(param->hostptr) @@ -2670,6 +2685,12 @@ static int kgsl_setup_useraddr(struct kgsl_mem_entry *entry, 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 @@ -2688,7 +2709,7 @@ static int kgsl_setup_useraddr(struct kgsl_mem_entry *entry, up_read(¤t->mm->mmap_sem); if (!IS_ERR_OR_NULL(dmabuf)) { - int ret = kgsl_setup_dma_buf(entry, pagetable, device, dmabuf); + ret = kgsl_setup_dma_buf(entry, pagetable, device, dmabuf); if (ret) dma_buf_put(dmabuf); else { -- GitLab