]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amdkfd: fix 32-bit overflow in CWSR total size calculation
authorYongqiang Sun <Yongqiang.Sun@amd.com>
Mon, 6 Jul 2026 19:15:07 +0000 (15:15 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 17 Jul 2026 21:37:12 +0000 (17:37 -0400)
total_cwsr_size was computed in 32-bit before being used as a BO/SVM
allocation size.
With large ctx_save_restore_area_size and debug_memory_size
multiplied by the XCC count, the product can wrap,
yielding an undersized CWSR save area that firmware later overruns.

Promote total_cwsr_size to u64 and use check_add_overflow()/
check_mul_overflow() in both kfd_queue_acquire_buffers() and
kfd_queue_release_buffers().

Signed-off-by: Yongqiang Sun <Yongqiang.Sun@amd.com>
Reviewed-by: Philip Yang <philip.yang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 319f7e13423ae3f486b9aea82f9ad2d6af0ee608)
Cc: stable@vger.kernel.org
drivers/gpu/drm/amd/amdkfd/kfd_queue.c

index 28354a4e5dd5d153d49bcb3a3c2b0125b0ddea28..98a5512b701b12f7f9706be221711206413e8eb4 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/overflow.h>
 #include "kfd_priv.h"
 #include "kfd_topology.h"
 #include "kfd_svm.h"
@@ -235,7 +236,7 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope
        struct kfd_topology_device *topo_dev;
        u64 expected_queue_size;
        struct amdgpu_vm *vm;
-       u32 total_cwsr_size;
+       u64 total_cwsr_size;
        int err;
 
        topo_dev = kfd_topology_device_by_id(pdd->dev->id);
@@ -308,8 +309,14 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope
                goto out_err_unreserve;
        }
 
-       total_cwsr_size = (properties->ctx_save_restore_area_size +
-                          topo_dev->node_props.debug_memory_size) * NUM_XCC(pdd->dev->xcc_mask);
+       total_cwsr_size = (u64)properties->ctx_save_restore_area_size +
+                         topo_dev->node_props.debug_memory_size;
+       if (check_mul_overflow(total_cwsr_size,
+                              NUM_XCC(pdd->dev->xcc_mask),
+                              &total_cwsr_size)) {
+               err = -EINVAL;
+               goto out_err_unreserve;
+       }
        total_cwsr_size = ALIGN(total_cwsr_size, PAGE_SIZE);
 
        err = kfd_queue_buffer_get(vm, (void *)properties->ctx_save_restore_area_address,
@@ -344,7 +351,7 @@ out_err_release:
 int kfd_queue_release_buffers(struct kfd_process_device *pdd, struct queue_properties *properties)
 {
        struct kfd_topology_device *topo_dev;
-       u32 total_cwsr_size;
+       u64 total_cwsr_size;
 
        kfd_queue_buffer_put(&properties->wptr_bo);
        kfd_queue_buffer_put(&properties->rptr_bo);
@@ -355,8 +362,12 @@ int kfd_queue_release_buffers(struct kfd_process_device *pdd, struct queue_prope
        topo_dev = kfd_topology_device_by_id(pdd->dev->id);
        if (!topo_dev)
                return -EINVAL;
-       total_cwsr_size = (properties->ctx_save_restore_area_size +
-                          topo_dev->node_props.debug_memory_size) * NUM_XCC(pdd->dev->xcc_mask);
+       total_cwsr_size = (u64)properties->ctx_save_restore_area_size +
+                         topo_dev->node_props.debug_memory_size;
+       if (check_mul_overflow(total_cwsr_size,
+                              NUM_XCC(pdd->dev->xcc_mask),
+                              &total_cwsr_size))
+               return -EINVAL;
        total_cwsr_size = ALIGN(total_cwsr_size, PAGE_SIZE);
 
        kfd_queue_buffer_svm_put(pdd, properties->ctx_save_restore_area_address, total_cwsr_size);