DivestOS/Patches/Linux_CVEs/CVE-2017-7366/ANY/1.patch
2017-10-29 22:14:37 -04:00

255 lines
8.2 KiB
Diff

From 7c4d5736d32f91f0cafe6cd86d00e26389970b00 Mon Sep 17 00:00:00 2001
From: Jordan Crouse <jcrouse@codeaurora.org>
Date: Tue, 31 May 2016 11:24:24 -0600
Subject: msm: kgsl: Make sure USE_CPU_MAP + MAP_USER_MEM work together
If one is mapping anonyomous user memory in the GPU with SVM enabled
we want to try to accommodate that request if possible. The memory
address was being set up correctly in the memory descriptor but
the GPU address was getting tripped up when getting mapped in the
process. This is because the memory should be treated like SVM
memory so it needs to be registered in the memory tree and the
rest of the path needs to accept the address.
Change-Id: Ic0dedbad661143977a226d50263c26b5af579ce3
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: Sudeep Yedalapure <sudeepy@codeaurora.org>
---
drivers/gpu/msm/kgsl.c | 134 +++++++++++++++++++++----------------------------
1 file changed, 57 insertions(+), 77 deletions(-)
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index bd022f1..db3ba02 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -166,9 +166,10 @@ int kgsl_memfree_find_entry(pid_t ptname, uint64_t *gpuaddr,
return 0;
}
-static void kgsl_memfree_purge(pid_t ptname, uint64_t gpuaddr,
- uint64_t size)
+static void kgsl_memfree_purge(struct kgsl_pagetable *pagetable,
+ uint64_t gpuaddr, uint64_t size)
{
+ pid_t ptname = pagetable ? pagetable->name : 0;
int i;
if (memfree.list == NULL)
@@ -332,40 +333,22 @@ kgsl_mem_entry_destroy(struct kref *kref)
}
EXPORT_SYMBOL(kgsl_mem_entry_destroy);
-/**
- * kgsl_mem_entry_track_gpuaddr - Insert a mem_entry in the address tree and
- * assign it with a gpu address space before insertion
- * @process: the process that owns the memory
- * @entry: the memory entry
- *
- * @returns - 0 on succcess else error code
- *
- * Insert the kgsl_mem_entry in to the rb_tree for searching by GPU address.
- * The assignment of gpu address and insertion into list needs to
- * happen with the memory lock held to avoid race conditions between
- * gpu address being selected and some other thread looking through the
- * rb list in search of memory based on gpuaddr
- * This function should be called with processes memory spinlock held
- */
-static int
-kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process,
- struct kgsl_mem_entry *entry)
+/* Allocate a IOVA for memory objects that don't use SVM */
+static int kgsl_mem_entry_track_gpuaddr(struct kgsl_device *device,
+ struct kgsl_process_private *process,
+ struct kgsl_mem_entry *entry)
{
- struct kgsl_pagetable *pagetable = process->pagetable;
+ struct kgsl_pagetable *pagetable;
/*
- * If cpu=gpu map is used then caller needs to set the
- * gpu address
+ * If SVM is enabled for this object then the address needs to be
+ * assigned elsewhere
*/
- if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
- if (!entry->memdesc.gpuaddr)
- return 0;
- } else if (entry->memdesc.gpuaddr) {
- WARN_ONCE(1, "gpuaddr assigned w/o holding memory lock\n");
- return -EINVAL;
- }
- if (kgsl_memdesc_is_secured(&entry->memdesc))
- pagetable = pagetable->mmu->securepagetable;
+ if (kgsl_memdesc_use_cpu_map(&entry->memdesc))
+ return 0;
+
+ pagetable = kgsl_memdesc_is_secured(&entry->memdesc) ?
+ device->mmu.securepagetable : process->pagetable;
return kgsl_mmu_get_gpuaddr(pagetable, &entry->memdesc);
}
@@ -381,33 +364,25 @@ static void kgsl_mem_entry_commit_process(struct kgsl_mem_entry *entry)
spin_unlock(&entry->priv->mem_lock);
}
-/**
- * kgsl_mem_entry_attach_process - Attach a mem_entry to its owner process
- * @entry: the memory entry
- * @process: the owner process
- *
- * Attach a newly created mem_entry to its owner process so that
- * it can be found later. The mem_entry will be added to mem_idr and have
- * its 'id' field assigned.
- *
- * @returns - 0 on success or error code on failure.
+/*
+ * Attach the memory object to a process by (possibly) getting a GPU address and
+ * (possibly) mapping it
*/
-int
-kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
- struct kgsl_device_private *dev_priv)
+static int kgsl_mem_entry_attach_process(struct kgsl_device *device,
+ struct kgsl_process_private *process,
+ struct kgsl_mem_entry *entry)
{
- int id;
- int ret;
- struct kgsl_process_private *process = dev_priv->process_priv;
- struct kgsl_pagetable *pagetable = NULL;
+ int id, ret;
ret = kgsl_process_private_get(process);
if (!ret)
return -EBADF;
- ret = kgsl_mem_entry_track_gpuaddr(process, entry);
- if (ret)
- goto err_put_proc_priv;
+ ret = kgsl_mem_entry_track_gpuaddr(device, process, entry);
+ if (ret) {
+ kgsl_process_private_put(process);
+ return ret;
+ }
idr_preload(GFP_KERNEL);
spin_lock(&process->mem_lock);
@@ -417,40 +392,33 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
idr_preload_end();
if (id < 0) {
- ret = id;
- kgsl_mmu_put_gpuaddr(&entry->memdesc);
- goto err_put_proc_priv;
+ if (!kgsl_memdesc_use_cpu_map(&entry->memdesc))
+ kgsl_mmu_put_gpuaddr(&entry->memdesc);
+ kgsl_process_private_put(process);
+ return id;
}
entry->id = id;
entry->priv = process;
- /* map the memory after unlocking if gpuaddr has been assigned */
+ /*
+ * Map the memory if a GPU address is already assigned, either through
+ * kgsl_mem_entry_track_gpuaddr() or via some other SVM process
+ */
if (entry->memdesc.gpuaddr) {
- /* if a secured buffer map it to secure global pagetable */
- if (kgsl_memdesc_is_secured(&entry->memdesc))
- pagetable = process->pagetable->mmu->securepagetable;
- else
- pagetable = process->pagetable;
+ ret = kgsl_mmu_map(entry->memdesc.pagetable, &entry->memdesc);
- entry->memdesc.pagetable = pagetable;
- ret = kgsl_mmu_map(pagetable, &entry->memdesc);
if (ret)
kgsl_mem_entry_detach_process(entry);
}
- kgsl_memfree_purge(pagetable ? pagetable->name : 0,
- entry->memdesc.gpuaddr, entry->memdesc.size);
-
- return ret;
+ kgsl_memfree_purge(entry->memdesc.pagetable, entry->memdesc.gpuaddr,
+ entry->memdesc.size);
-err_put_proc_priv:
- kgsl_process_private_put(process);
return ret;
}
/* Detach a memory entry from a process and unmap it from the MMU */
-
static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
{
unsigned int type;
@@ -2052,10 +2020,21 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = (uint64_t) size;
entry->memdesc.useraddr = hostptr;
- if (kgsl_memdesc_use_cpu_map(&entry->memdesc))
- entry->memdesc.gpuaddr = (uint64_t) entry->memdesc.useraddr;
entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ADDR;
+ if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
+ int ret;
+
+ /* Register the address in the database */
+ ret = kgsl_mmu_set_svm_region(pagetable,
+ (uint64_t) entry->memdesc.useraddr, (uint64_t) size);
+
+ if (ret)
+ return ret;
+
+ entry->memdesc.gpuaddr = (uint64_t) entry->memdesc.useraddr;
+ }
+
return memdesc_sg_virt(&entry->memdesc, NULL);
}
@@ -2305,7 +2284,7 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv,
param->flags = entry->memdesc.flags;
- ret = kgsl_mem_entry_attach_process(entry, dev_priv);
+ ret = kgsl_mem_entry_attach_process(dev_priv->device, private, entry);
if (ret)
goto unmap;
@@ -2609,7 +2588,8 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
/* echo back flags */
param->flags = (unsigned int) entry->memdesc.flags;
- result = kgsl_mem_entry_attach_process(entry, dev_priv);
+ result = kgsl_mem_entry_attach_process(dev_priv->device, private,
+ entry);
if (result)
goto error_attach;
@@ -3006,7 +2986,7 @@ static struct kgsl_mem_entry *gpumem_alloc_entry(
if (ret != 0)
goto err;
- ret = kgsl_mem_entry_attach_process(entry, dev_priv);
+ ret = kgsl_mem_entry_attach_process(dev_priv->device, private, entry);
if (ret != 0) {
kgsl_sharedmem_free(&entry->memdesc);
goto err;
@@ -3431,8 +3411,8 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private,
return ret;
}
- kgsl_memfree_purge(private->pagetable ? private->pagetable->name : 0,
- entry->memdesc.gpuaddr, entry->memdesc.size);
+ kgsl_memfree_purge(private->pagetable, entry->memdesc.gpuaddr,
+ entry->memdesc.size);
return addr;
}
--
cgit v1.1