summaryrefslogtreecommitdiff
path: root/drivers/gpu/msm/kgsl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/msm/kgsl.c')
-rw-r--r--drivers/gpu/msm/kgsl.c39
1 files changed, 27 insertions, 12 deletions
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index a9b6e24728c7..43ec8d8ff88b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -541,7 +541,7 @@ int kgsl_context_init(struct kgsl_device_private *dev_priv,
if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) {
KGSL_DRV_ERR_RATELIMIT(device,
"Per process context limit reached for pid %u",
- dev_priv->process_priv->pid);
+ pid_nr(dev_priv->process_priv->pid));
spin_unlock(&proc_priv->ctxt_count_lock);
return -ENOSPC;
}
@@ -866,6 +866,7 @@ static void kgsl_destroy_process_private(struct kref *kref)
struct kgsl_process_private *private = container_of(kref,
struct kgsl_process_private, refcount);
+ put_pid(private->pid);
idr_destroy(&private->mem_idr);
idr_destroy(&private->syncsource_idr);
@@ -896,7 +897,7 @@ struct kgsl_process_private *kgsl_process_private_find(pid_t pid)
mutex_lock(&kgsl_driver.process_mutex);
list_for_each_entry(p, &kgsl_driver.process_list, list) {
- if (p->pid == pid) {
+ if (pid_nr(p->pid) == pid) {
if (kgsl_process_private_get(p))
private = p;
break;
@@ -910,25 +911,34 @@ static struct kgsl_process_private *kgsl_process_private_new(
struct kgsl_device *device)
{
struct kgsl_process_private *private;
- pid_t tgid = task_tgid_nr(current);
+ struct pid *cur_pid = get_task_pid(current->group_leader, PIDTYPE_PID);
/* Search in the process list */
list_for_each_entry(private, &kgsl_driver.process_list, list) {
- if (private->pid == tgid) {
- if (!kgsl_process_private_get(private))
+ if (private->pid == cur_pid) {
+ if (!kgsl_process_private_get(private)) {
private = ERR_PTR(-EINVAL);
+ }
+ /*
+ * We need to hold only one reference to the PID for
+ * each process struct to avoid overflowing the
+ * reference counter which can lead to use-after-free.
+ */
+ put_pid(cur_pid);
return private;
}
}
/* Create a new object */
private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
- if (private == NULL)
+ if (private == NULL) {
+ put_pid(cur_pid);
return ERR_PTR(-ENOMEM);
+ }
kref_init(&private->refcount);
- private->pid = tgid;
+ private->pid = cur_pid;
get_task_comm(private->comm, current->group_leader);
spin_lock_init(&private->mem_lock);
@@ -939,12 +949,14 @@ static struct kgsl_process_private *kgsl_process_private_new(
idr_init(&private->syncsource_idr);
/* Allocate a pagetable for the new process object */
- private->pagetable = kgsl_mmu_getpagetable(&device->mmu, tgid);
+ private->pagetable = kgsl_mmu_getpagetable(&device->mmu,
+ pid_nr(cur_pid));
if (IS_ERR(private->pagetable)) {
int err = PTR_ERR(private->pagetable);
idr_destroy(&private->mem_idr);
idr_destroy(&private->syncsource_idr);
+ put_pid(private->pid);
kfree(private);
private = ERR_PTR(err);
@@ -1878,8 +1890,9 @@ static long gpumem_free_entry(struct kgsl_mem_entry *entry)
if (entry->memdesc.pagetable != NULL)
ptname = entry->memdesc.pagetable->name;
- kgsl_memfree_add(entry->priv->pid, ptname, entry->memdesc.gpuaddr,
- entry->memdesc.size, entry->memdesc.flags);
+ kgsl_memfree_add(pid_nr(entry->priv->pid), ptname,
+ entry->memdesc.gpuaddr, entry->memdesc.size,
+ entry->memdesc.flags);
kgsl_mem_entry_put(entry);
@@ -4569,13 +4582,15 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr,
if (IS_ERR_VALUE(val))
KGSL_DRV_ERR_RATELIMIT(device,
"get_unmapped_area: pid %d addr %lx pgoff %lx len %ld failed error %d\n",
- private->pid, addr, pgoff, len, (int) val);
+ pid_nr(private->pid), addr,
+ pgoff, len, (int) val);
} else {
val = _get_svm_area(private, entry, addr, len, flags);
if (IS_ERR_VALUE(val))
KGSL_DRV_ERR_RATELIMIT(device,
"_get_svm_area: pid %d mmap_base %lx addr %lx pgoff %lx len %ld failed error %d\n",
- private->pid, current->mm->mmap_base, addr,
+ pid_nr(private->pid),
+ current->mm->mmap_base, addr,
pgoff, len, (int) val);
}