]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amdkfd: clamp v9 CRIU control stack checkpoint copy to BO size
authorYongqiang Sun <Yongqiang.Sun@amd.com>
Tue, 2 Jun 2026 13:47:19 +0000 (09:47 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 1 Jul 2026 16:59:39 +0000 (12:59 -0400)
CRIU checkpoint copies the MQD control stack using cp_hqd_cntl_stack_size
from hardware without bounding it to the allocated BO region. If the HW
field is larger than the queue's control stack allocation, memcpy reads
past the BO into adjacent GTT memory and can leak kernel data to userspace.

Store the page-aligned control stack BO size in mqd_manager and clamp
checkpoint copies and reported checkpoint sizes to
min(cp_hqd_cntl_stack_size, mm->ctl_stack_size). Apply the same bound
for multi-XCC v9.4.3 checkpoint layout.

Signed-off-by: Yongqiang Sun <Yongqiang.Sun@amd.com>
Reviewed-by: David Francis <David.Francis@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 6c2abd0ec09e86c6323010673766f76050e28aa3)
Cc: stable@vger.kernel.org
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c

index 06ca6235ff1b7642446efd1837864de15f6e449d..63ea70e5c0e656807788f89950c34b705c06ce66 100644 (file)
@@ -127,6 +127,7 @@ struct mqd_manager {
        struct mutex    mqd_mutex;
        struct kfd_node *dev;
        uint32_t mqd_size;
+       uint32_t ctl_stack_size;
 };
 
 struct mqd_user_context_save_area_header {
index 17bfb419b2020a8f86099f6d8e2fbf8167d4d0c6..be99f0d53b188867b40a32bec42375533268bbff 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/uaccess.h>
 #include "kfd_priv.h"
 #include "kfd_mqd_manager.h"
+#include "kfd_topology.h"
 #include "v9_structs.h"
 #include "gc/gc_9_0_offset.h"
 #include "gc/gc_9_0_sh_mask.h"
@@ -411,8 +412,11 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
 static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
 {
        struct v9_mqd *m = get_mqd(mqd);
+       u32 per_xcc_size;
 
-       if (check_mul_overflow(m->cp_hqd_cntl_stack_size, NUM_XCC(mm->dev->xcc_mask), ctl_stack_size))
+       per_xcc_size = min_t(u32, m->cp_hqd_cntl_stack_size, mm->ctl_stack_size);
+
+       if (check_mul_overflow(per_xcc_size, NUM_XCC(mm->dev->xcc_mask), ctl_stack_size))
                return -EINVAL;
 
        return 0;
@@ -421,13 +425,15 @@ static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack
 static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst)
 {
        struct v9_mqd *m;
+       u32 ctl_stack_copy_size;
        /* Control stack is located one page after MQD. */
        void *ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE);
 
        m = get_mqd(mqd);
+       ctl_stack_copy_size = min_t(u32, m->cp_hqd_cntl_stack_size, mm->ctl_stack_size);
 
        memcpy(mqd_dst, m, sizeof(struct v9_mqd));
-       memcpy(ctl_stack_dst, ctl_stack, m->cp_hqd_cntl_stack_size);
+       memcpy(ctl_stack_dst, ctl_stack, ctl_stack_copy_size);
 }
 
 static void checkpoint_mqd_v9_4_3(struct mqd_manager *mm,
@@ -436,15 +442,19 @@ static void checkpoint_mqd_v9_4_3(struct mqd_manager *mm,
                                                                  void *ctl_stack_dst)
 {
        struct v9_mqd *m;
+       u32 ctl_stack_stride;
        int xcc;
        uint64_t size = get_mqd(mqd)->cp_mqd_stride_size;
 
+       ctl_stack_stride = min_t(u32, get_mqd(mqd)->cp_hqd_cntl_stack_size,
+                                mm->ctl_stack_size);
+
        for (xcc = 0; xcc < NUM_XCC(mm->dev->xcc_mask); xcc++) {
                m = get_mqd(mqd + size * xcc);
 
                checkpoint_mqd(mm, m,
                                (uint8_t *)mqd_dst + sizeof(*m) * xcc,
-                               (uint8_t *)ctl_stack_dst + m->cp_hqd_cntl_stack_size * xcc);
+                               (uint8_t *)ctl_stack_dst + ctl_stack_stride * xcc);
        }
 }
 
@@ -998,6 +1008,15 @@ struct mqd_manager *mqd_manager_init_v9(enum KFD_MQD_TYPE type,
                mqd->is_occupied = kfd_is_occupied_cp;
                mqd->get_checkpoint_info = get_checkpoint_info;
                mqd->mqd_size = sizeof(struct v9_mqd);
+               if (dev->kfd->cwsr_enabled) {
+                       struct kfd_topology_device *topo_dev;
+
+                       topo_dev = kfd_topology_device_by_id(dev->id);
+                       if (topo_dev)
+                               mqd->ctl_stack_size =
+                                       ALIGN(topo_dev->node_props.ctl_stack_size,
+                                             AMDGPU_GPU_PAGE_SIZE);
+               }
                mqd->mqd_stride = mqd_stride_v9;
 #if defined(CONFIG_DEBUG_FS)
                mqd->debugfs_show_mqd = debugfs_show_mqd;