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

authored by

Tvrtko Ursulin and committed by
Maíra Canal
753ce4fe f32b5128

+48 -19
+2
drivers/gpu/drm/v3d/v3d_drv.h
··· 563 563 void v3d_mmu_remove_ptes(struct v3d_bo *bo); 564 564 565 565 /* v3d_sched.c */ 566 + void v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info, 567 + unsigned int count); 566 568 void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue); 567 569 int v3d_sched_init(struct v3d_dev *v3d); 568 570 void v3d_sched_fini(struct v3d_dev *v3d);
+16 -6
drivers/gpu/drm/v3d/v3d_sched.c
··· 73 73 v3d_job_cleanup(job); 74 74 } 75 75 76 + void 77 + v3d_timestamp_query_info_free(struct v3d_timestamp_query_info *query_info, 78 + unsigned int count) 79 + { 80 + if (query_info->queries) { 81 + unsigned int i; 82 + 83 + for (i = 0; i < count; i++) 84 + drm_syncobj_put(query_info->queries[i].syncobj); 85 + 86 + kvfree(query_info->queries); 87 + } 88 + } 89 + 76 90 static void 77 91 v3d_cpu_job_free(struct drm_sched_job *sched_job) 78 92 { 79 93 struct v3d_cpu_job *job = to_cpu_job(sched_job); 80 - struct v3d_timestamp_query_info *timestamp_query = &job->timestamp_query; 81 94 struct v3d_performance_query_info *performance_query = &job->performance_query; 82 95 83 - if (timestamp_query->queries) { 84 - for (int i = 0; i < timestamp_query->count; i++) 85 - drm_syncobj_put(timestamp_query->queries[i].syncobj); 86 - kvfree(timestamp_query->queries); 87 - } 96 + v3d_timestamp_query_info_free(&job->timestamp_query, 97 + job->timestamp_query.count); 88 98 89 99 if (performance_query->queries) { 90 100 for (int i = 0; i < performance_query->count; i++)
+30 -13
drivers/gpu/drm/v3d/v3d_submit.c
··· 452 452 { 453 453 u32 __user *offsets, *syncs; 454 454 struct drm_v3d_timestamp_query timestamp; 455 + unsigned int i; 456 + int err; 455 457 456 458 if (!job) { 457 459 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 482 480 offsets = u64_to_user_ptr(timestamp.offsets); 483 481 syncs = u64_to_user_ptr(timestamp.syncs); 484 482 485 - for (int i = 0; i < timestamp.count; i++) { 483 + for (i = 0; i < timestamp.count; i++) { 486 484 u32 offset, sync; 487 485 488 486 if (copy_from_user(&offset, offsets++, sizeof(offset))) { 489 - kvfree(job->timestamp_query.queries); 490 - return -EFAULT; 487 + err = -EFAULT; 488 + goto error; 491 489 } 492 490 493 491 job->timestamp_query.queries[i].offset = offset; 494 492 495 493 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 496 - kvfree(job->timestamp_query.queries); 497 - return -EFAULT; 494 + err = -EFAULT; 495 + goto error; 498 496 } 499 497 500 498 job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); ··· 502 500 job->timestamp_query.count = timestamp.count; 503 501 504 502 return 0; 503 + 504 + error: 505 + v3d_timestamp_query_info_free(&job->timestamp_query, i); 506 + return err; 505 507 } 506 508 507 509 static int ··· 515 509 { 516 510 u32 __user *syncs; 517 511 struct drm_v3d_reset_timestamp_query reset; 512 + unsigned int i; 513 + int err; 518 514 519 515 if (!job) { 520 516 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 541 533 542 534 syncs = u64_to_user_ptr(reset.syncs); 543 535 544 - for (int i = 0; i < reset.count; i++) { 536 + for (i = 0; i < reset.count; i++) { 545 537 u32 sync; 546 538 547 539 job->timestamp_query.queries[i].offset = reset.offset + 8 * i; 548 540 549 541 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 550 - kvfree(job->timestamp_query.queries); 551 - return -EFAULT; 542 + err = -EFAULT; 543 + goto error; 552 544 } 553 545 554 546 job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); ··· 556 548 job->timestamp_query.count = reset.count; 557 549 558 550 return 0; 551 + 552 + error: 553 + v3d_timestamp_query_info_free(&job->timestamp_query, i); 554 + return err; 559 555 } 560 556 561 557 /* Get data for the copy timestamp query results job submission. */ ··· 570 558 { 571 559 u32 __user *offsets, *syncs; 572 560 struct drm_v3d_copy_timestamp_query copy; 573 - int i; 561 + unsigned int i; 562 + int err; 574 563 575 564 if (!job) { 576 565 DRM_DEBUG("CPU job extension was attached to a GPU job.\n"); ··· 604 591 u32 offset, sync; 605 592 606 593 if (copy_from_user(&offset, offsets++, sizeof(offset))) { 607 - kvfree(job->timestamp_query.queries); 608 - return -EFAULT; 594 + err = -EFAULT; 595 + goto error; 609 596 } 610 597 611 598 job->timestamp_query.queries[i].offset = offset; 612 599 613 600 if (copy_from_user(&sync, syncs++, sizeof(sync))) { 614 - kvfree(job->timestamp_query.queries); 615 - return -EFAULT; 601 + err = -EFAULT; 602 + goto error; 616 603 } 617 604 618 605 job->timestamp_query.queries[i].syncobj = drm_syncobj_find(file_priv, sync); ··· 626 613 job->copy.stride = copy.stride; 627 614 628 615 return 0; 616 + 617 + error: 618 + v3d_timestamp_query_info_free(&job->timestamp_query, i); 619 + return err; 629 620 } 630 621 631 622 static int