struct queue embeds a struct kobject (q->kobj) for procfs entries, but
procfs_queue_type had no .release callback and uninit_queue() freed q
immediately after kfd_procfs_del_queue() called kobject_put(&q->kobj).
With CONFIG_DEBUG_KOBJECT_RELEASE=y, this causes a use-after-free.
Add kfd_procfs_queue_release() to free struct queue from the kobject
release callback, change kfd_procfs_del_queue() to only remove the
kobject from sysfs via kobject_del(), and drop the final reference in
uninit_queue() via kobject_put(). Check q->kobj.state_in_sysfs before
calling kobject_del() in kfd_procfs_del_queue() to avoid warnings if
sysfs creation previously failed.
Fixes: 6d220a7e7971 ("drm/amdkfd: Add queue information to sysfs")
Signed-off-by: Ian Rogers <[email protected]>
---
drivers/gpu/drm/amd/amdkfd/kfd_process.c | 12 +++++++++---
drivers/gpu/drm/amd/amdkfd/kfd_queue.c | 5 ++++-
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 226f52626e84..8e6136d52a50 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -512,7 +512,15 @@ static const struct sysfs_ops procfs_queue_ops = {
.show = kfd_procfs_queue_show,
};
+static void kfd_procfs_queue_release(struct kobject *kobj)
+{
+ struct queue *q = container_of(kobj, struct queue, kobj);
+
+ kfree(q);
+}
+
static const struct kobj_type procfs_queue_type = {
+ .release = kfd_procfs_queue_release,
.sysfs_ops = &procfs_queue_ops,
.default_groups = procfs_queue_groups,
};
@@ -552,7 +560,6 @@ int kfd_procfs_add_queue(struct queue *q)
if (ret < 0) {
pr_warn("Creating proc/<pid>/queues/%u failed",
q->properties.queue_id);
- kobject_put(&q->kobj);
return ret;
}
@@ -697,11 +704,10 @@ static void kfd_procfs_add_sysfs_files(struct kfd_process
*p)
void kfd_procfs_del_queue(struct queue *q)
{
- if (!q || !q->process->kobj)
+ if (!q || !q->process || !q->process->kobj || !q->kobj.state_in_sysfs)
return;
kobject_del(&q->kobj);
- kobject_put(&q->kobj);
}
int kfd_process_create_wq(void)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
index ae3e7c54014a..4666110aebe0 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c
@@ -83,7 +83,10 @@ int init_queue(struct queue **q, const struct
queue_properties *properties)
void uninit_queue(struct queue *q)
{
- kfree(q);
+ if (q && q->kobj.state_initialized)
+ kobject_put(&q->kobj);
+ else
+ kfree(q);
}
#if IS_ENABLED(CONFIG_HSA_AMD_SVM)
--
2.56.0.313.g2479322e68-goog