Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <tvrtko.ursulin@igalia.com>
Fixes: bae7cb5d6800 ("drm/v3d: Create a CPU job extension for the reset performance query job")
Cc: Maíra Canal <mcanal@igalia.com>
Cc: Iago Toral Quiroga <itoral@igalia.com>
Cc: stable@vger.kernel.org # v6.8+
Signed-off-by: Maíra Canal <mcanal@igalia.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240711135340.84617-4-tursulin@igalia.com

authored by

Tvrtko Ursulin and committed by
Maíra Canal
484de39f 753ce4fe

+50 -26
+2
drivers/gpu/drm/v3d/v3d_drv.h
··· 565 565 /* v3d_sched.c */ 566 566 void v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info, 567 567 unsigned int count); 568 + void v3d_performance_query_info_free(struct v3d_performance_query_info *query_info, 569 + unsigned int count); 568 570 void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue); 569 571 int v3d_sched_init(struct v3d_dev *v3d); 570 572 void v3d_sched_fini(struct v3d_dev *v3d);
+16 -6
drivers/gpu/drm/v3d/v3d_sched.c
··· 87 87 } 88 88 } 89 89 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 + 90 104 static void 91 105 v3d_cpu_job_free(struct drm_sched_job *sched_job) 92 106 { 93 107 struct v3d_cpu_job *job = to_cpu_job(sched_job); 94 - struct v3d_performance_query_info *performance_query = &job->performance_query; 95 108 96 109 v3d_timestamp_query_info_free(&job->timestamp_query, 97 110 job->timestamp_query.count); 98 111 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); 104 114 105 115 v3d_job_cleanup(&job->base); 106 116 }
+32 -20
drivers/gpu/drm/v3d/v3d_submit.c
··· 640 640 u32 __user *syncs; 641 641 u64 __user *kperfmon_ids; 642 642 struct drm_v3d_reset_performance_query reset; 643 + unsigned int i, j; 644 + int err; 643 645 644 646 if (!job) { 645 647 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 670 668 syncs = u64_to_user_ptr(reset.syncs); 671 669 kperfmon_ids = u64_to_user_ptr(reset.kperfmon_ids); 672 670 673 - for (int i = 0; i < reset.count; i++) { 671 + for (i = 0; i < reset.count; i++) { 674 672 u32 sync; 675 673 u64 ids; 676 674 u32 __user *ids_pointer; 677 675 u32 id; 678 676 679 677 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 680 - kvfree(job->performance_query.queries); 681 - return -EFAULT; 678 + err = -EFAULT; 679 + goto error; 682 680 } 683 681 684 - job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 685 - 686 682 if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) { 687 - kvfree(job->performance_query.queries); 688 - return -EFAULT; 683 + err = -EFAULT; 684 + goto error; 689 685 } 690 686 691 687 ids_pointer = u64_to_user_ptr(ids); 692 688 693 - for (int j = 0; j < reset.nperfmons; j++) { 689 + for (j = 0; j < reset.nperfmons; j++) { 694 690 if (copy_from_user(&id, ids_pointer++, sizeof(id))) { 695 - kvfree(job->performance_query.queries); 696 - return -EFAULT; 691 + err = -EFAULT; 692 + goto error; 697 693 } 698 694 699 695 job->performance_query.queries[i].kperfmon_ids[j] = id; 700 696 } 697 + 698 + job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 701 699 } 702 700 job->performance_query.count = reset.count; 703 701 job->performance_query.nperfmons = reset.nperfmons; 704 702 705 703 return 0; 704 + 705 + error: 706 + v3d_performance_query_info_free(&job->performance_query, i); 707 + return err; 706 708 } 707 709 708 710 static int ··· 717 711 u32 __user *syncs; 718 712 u64 __user *kperfmon_ids; 719 713 struct drm_v3d_copy_performance_query copy; 714 + unsigned int i, j; 715 + int err; 720 716 721 717 if (!job) { 722 718 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 750 742 syncs = u64_to_user_ptr(copy.syncs); 751 743 kperfmon_ids = u64_to_user_ptr(copy.kperfmon_ids); 752 744 753 - for (int i = 0; i < copy.count; i++) { 745 + for (i = 0; i < copy.count; i++) { 754 746 u32 sync; 755 747 u64 ids; 756 748 u32 __user *ids_pointer; 757 749 u32 id; 758 750 759 751 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 760 - kvfree(job->performance_query.queries); 761 - return -EFAULT; 752 + err = -EFAULT; 753 + goto error; 762 754 } 763 755 764 - job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 765 - 766 756 if (copy_from_user(&ids, kperfmon_ids++, sizeof(ids))) { 767 - kvfree(job->performance_query.queries); 768 - return -EFAULT; 757 + err = -EFAULT; 758 + goto error; 769 759 } 770 760 771 761 ids_pointer = u64_to_user_ptr(ids); 772 762 773 - for (int j = 0; j < copy.nperfmons; j++) { 763 + for (j = 0; j < copy.nperfmons; j++) { 774 764 if (copy_from_user(&id, ids_pointer++, sizeof(id))) { 775 - kvfree(job->performance_query.queries); 776 - return -EFAULT; 765 + err = -EFAULT; 766 + goto error; 777 767 } 778 768 779 769 job->performance_query.queries[i].kperfmon_ids[j] = id; 780 770 } 771 + 772 + job->performance_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); 781 773 } 782 774 job->performance_query.count = copy.count; 783 775 job->performance_query.nperfmons = copy.nperfmons; ··· 790 782 job->copy.stride = copy.stride; 791 783 792 784 return 0; 785 + 786 + error: 787 + v3d_performance_query_info_free(&job->performance_query, i); 788 + return err; 793 789 } 794 790 795 791 /* Whenever userspace sets ioctl extensions, v3d_get_extensions parses data