msm: kgsl: Don't make assumptions about VMA regions
We cannot assume that a VMA region created as a result of an mmap
belongs exclusively to us. Allow the user to pass the size of
the vmalloc region through the 'gpuaddr' member of the ioctl
struct and do strict checking on the returned vma to make sure
it is valid.
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 3f0885a..acdd1b7 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1053,25 +1053,13 @@
static struct vm_area_struct *kgsl_get_vma_from_start_addr(unsigned int addr)
{
struct vm_area_struct *vma;
- int len;
down_read(¤t->mm->mmap_sem);
vma = find_vma(current->mm, addr);
up_read(¤t->mm->mmap_sem);
- if (!vma) {
+ if (!vma)
KGSL_CORE_ERR("find_vma(%x) failed\n", addr);
- return NULL;
- }
- len = vma->vm_end - vma->vm_start;
- if (vma->vm_pgoff || !KGSL_IS_PAGE_ALIGNED(len) ||
- !KGSL_IS_PAGE_ALIGNED(vma->vm_start)) {
- KGSL_CORE_ERR("address %x is not aligned\n", addr);
- return NULL;
- }
- if (vma->vm_start != addr) {
- KGSL_CORE_ERR("vma address does not match mmap address\n");
- return NULL;
- }
+
return vma;
}
@@ -1102,9 +1090,30 @@
result = -EINVAL;
goto error;
}
- len = vma->vm_end - vma->vm_start;
- if (len == 0) {
- KGSL_CORE_ERR("Invalid vma region length %d\n", len);
+
+ /*
+ * If the user specified a length, use it, otherwise try to
+ * infer the length if the vma region
+ */
+ if (param->gpuaddr != 0) {
+ len = param->gpuaddr;
+ } else {
+ /*
+ * For this to work, we have to assume the VMA region is only
+ * for this single allocation. If it isn't, then bail out
+ */
+ if (vma->vm_pgoff || (param->hostptr != vma->vm_start)) {
+ KGSL_CORE_ERR("VMA region does not match hostaddr\n");
+ result = -EINVAL;
+ goto error;
+ }
+
+ len = vma->vm_end - vma->vm_start;
+ }
+
+ /* Make sure it fits */
+ if (len == 0 || param->hostptr + len > vma->vm_end) {
+ KGSL_CORE_ERR("Invalid memory allocation length %d\n", len);
result = -EINVAL;
goto error;
}
@@ -1323,11 +1332,17 @@
struct vm_area_struct *vma;
struct file *filep, *vmfile;
unsigned long len;
+ unsigned int hostaddr = (unsigned int) hostptr;
- vma = kgsl_get_vma_from_start_addr((unsigned long) hostptr);
+ vma = kgsl_get_vma_from_start_addr(hostaddr);
if (vma == NULL)
return -EINVAL;
+ if (vma->vm_pgoff || vma->vm_start != hostaddr) {
+ KGSL_CORE_ERR("Invalid vma region\n");
+ return -EINVAL;
+ }
+
len = vma->vm_end - vma->vm_start;
if (size == 0)