Skip to content

Commit 32df4ab

Browse files
Tvrtko Ursulintdz
authored andcommitted
drm/v3d: Fix potential memory leak in the performance extension
If fetching of userspace memory fails during the main loop, all drm sync objs looked up until that point will be leaked because of the missing drm_syncobj_put. Fix it by exporting and using a common cleanup helper. Signed-off-by: Tvrtko Ursulin <[email protected]> Fixes: bae7cb5 ("drm/v3d: Create a CPU job extension for the reset performance query job") Cc: Maíra Canal <[email protected]> Cc: Iago Toral Quiroga <[email protected]> Cc: [email protected] # v6.8+ Signed-off-by: Maíra Canal <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] (cherry picked from commit 484de39) Signed-off-by: Thomas Zimmermann <[email protected]>
1 parent 0e50fcc commit 32df4ab

File tree

3 files changed

+50
-26
lines changed

3 files changed

+50
-26
lines changed

drivers/gpu/drm/v3d/v3d_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ void v3d_mmu_remove_ptes(struct v3d_bo *bo);
558558
/* v3d_sched.c */
559559
void v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info,
560560
unsigned int count);
561+
void v3d_performance_query_info_free(struct v3d_performance_query_info *query_info,
562+
unsigned int count);
561563
void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue);
562564
int v3d_sched_init(struct v3d_dev *v3d);
563565
void v3d_sched_fini(struct v3d_dev *v3d);

drivers/gpu/drm/v3d/v3d_sched.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,20 +87,30 @@ v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info,
8787
}
8888
}
8989

90+
void
91+
v3d_performance_query_info_free(struct v3d_performance_query_info *query_info,
92+
unsigned int count)
93+
{
94+
if (query_info->queries) {
95+
unsigned int i;
96+
97+
for (i = 0; i < count; i++)
98+
drm_syncobj_put(query_info->queries[i].syncobj);
99+
100+
kvfree(query_info->queries);
101+
}
102+
}
103+
90104
static void
91105
v3d_cpu_job_free(struct drm_sched_job *sched_job)
92106
{
93107
struct v3d_cpu_job *job = to_cpu_job(sched_job);
94-
struct v3d_performance_query_info *performance_query = &job->performance_query;
95108

96109
v3d_timestamp_query_info_free(&job->timestamp_query,
97110
job->timestamp_query.count);
98111

99-
if (performance_query->queries) {
100-
for (int i = 0; i < performance_query->count; i++)
101-
drm_syncobj_put(performance_query->queries[i].syncobj);
102-
kvfree(performance_query->queries);
103-
}
112+
v3d_performance_query_info_free(&job->performance_query,
113+
job->performance_query.count);
104114

105115
v3d_job_cleanup(&job->base);
106116
}

drivers/gpu/drm/v3d/v3d_submit.c

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,8 @@ v3d_get_cpu_reset_performance_params(struct drm_file *file_priv,
640640
u32 __user *syncs;
641641
u64 __user *kperfmon_ids;
642642
struct drm_v3d_reset_performance_query reset;
643+
unsigned int i, j;
644+
int err;
643645

644646
if (!job) {
645647
DRM_DEBUG("CPU job extension was attached to a GPU job.\n");
@@ -668,39 +670,43 @@ v3d_get_cpu_reset_performance_params(struct drm_file *file_priv,
668670
syncs = u64_to_user_ptr(reset.syncs);
669671
kperfmon_ids = u64_to_user_ptr(reset.kperfmon_ids);
670672

671-
for (int i = 0; i < reset.count; i++) {
673+
for (i = 0; i < reset.count; i++) {
672674
u32 sync;
673675
u64 ids;
674676
u32 __user *ids_pointer;
675677
u32 id;
676678

677679
if (copy_from_user(&sync, syncs++, sizeof(sync))) {
678-
kvfree(job->performance_query.queries);
679-
return -EFAULT;
680+
err = -EFAULT;
681+
goto error;
680682
}
681683

682-
job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
683-
684684
if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) {
685-
kvfree(job->performance_query.queries);
686-
return -EFAULT;
685+
err = -EFAULT;
686+
goto error;
687687
}
688688

689689
ids_pointer = u64_to_user_ptr(ids);
690690

691-
for (int j = 0; j < reset.nperfmons; j++) {
691+
for (j = 0; j < reset.nperfmons; j++) {
692692
if (copy_from_user(&id, ids_pointer++, sizeof(id))) {
693-
kvfree(job->performance_query.queries);
694-
return -EFAULT;
693+
err = -EFAULT;
694+
goto error;
695695
}
696696

697697
job->performance_query.queries[i].kperfmon_ids[j] = id;
698698
}
699+
700+
job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
699701
}
700702
job->performance_query.count = reset.count;
701703
job->performance_query.nperfmons = reset.nperfmons;
702704

703705
return 0;
706+
707+
error:
708+
v3d_performance_query_info_free(&job->performance_query, i);
709+
return err;
704710
}
705711

706712
static int
@@ -711,6 +717,8 @@ v3d_get_cpu_copy_performance_query_params(struct drm_file *file_priv,
711717
u32 __user *syncs;
712718
u64 __user *kperfmon_ids;
713719
struct drm_v3d_copy_performance_query copy;
720+
unsigned int i, j;
721+
int err;
714722

715723
if (!job) {
716724
DRM_DEBUG("CPU job extension was attached to a GPU job.\n");
@@ -742,34 +750,34 @@ v3d_get_cpu_copy_performance_query_params(struct drm_file *file_priv,
742750
syncs = u64_to_user_ptr(copy.syncs);
743751
kperfmon_ids = u64_to_user_ptr(copy.kperfmon_ids);
744752

745-
for (int i = 0; i < copy.count; i++) {
753+
for (i = 0; i < copy.count; i++) {
746754
u32 sync;
747755
u64 ids;
748756
u32 __user *ids_pointer;
749757
u32 id;
750758

751759
if (copy_from_user(&sync, syncs++, sizeof(sync))) {
752-
kvfree(job->performance_query.queries);
753-
return -EFAULT;
760+
err = -EFAULT;
761+
goto error;
754762
}
755763

756-
job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
757-
758764
if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) {
759-
kvfree(job->performance_query.queries);
760-
return -EFAULT;
765+
err = -EFAULT;
766+
goto error;
761767
}
762768

763769
ids_pointer = u64_to_user_ptr(ids);
764770

765-
for (int j = 0; j < copy.nperfmons; j++) {
771+
for (j = 0; j < copy.nperfmons; j++) {
766772
if (copy_from_user(&id, ids_pointer++, sizeof(id))) {
767-
kvfree(job->performance_query.queries);
768-
return -EFAULT;
773+
err = -EFAULT;
774+
goto error;
769775
}
770776

771777
job->performance_query.queries[i].kperfmon_ids[j] = id;
772778
}
779+
780+
job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync);
773781
}
774782
job->performance_query.count = copy.count;
775783
job->performance_query.nperfmons = copy.nperfmons;
@@ -782,6 +790,10 @@ v3d_get_cpu_copy_performance_query_params(struct drm_file *file_priv,
782790
job->copy.stride = copy.stride;
783791

784792
return 0;
793+
794+
error:
795+
v3d_performance_query_info_free(&job->performance_query, i);
796+
return err;
785797
}
786798

787799
/* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data

0 commit comments

Comments
 (0)