During CRIU restore, restore_mqd() copies the MQD control stack using a size derived from the untrusted, user-supplied q_data->ctl_stack_size. On multi-XCC GFX9.4.3 parts the divisor used to size the MQD allocation can differ from the one used for the copy, so the memcpy at the fixed +AMDGPU_GPU_PAGE_SIZE offset can write attacker-controlled bytes past the TTM/BO-backed MQD buffer into adjacent kernel memory, allowing local privilege escalation (requires CAP_CHECKPOINT_RESTORE and /dev/kfd).
Clamp the control stack copy in restore_mqd() to qp->ctl_stack_size, the page-aligned region allocate_mqd() actually reserves, and reject oversized q_data->ctl_stack_size early in kfd_criu_restore_queue() by bounding the per-XCC size to the node's advertised control stack size. Signed-off-by: Yongqiang Sun <[email protected]> --- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c | 16 +++++++++++- .../amd/amdkfd/kfd_process_queue_manager.c | 26 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index ce379ab17916..9117fbae0a1a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -453,8 +453,22 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, if (gart_addr) *gart_addr = addr; - /* Control stack is located one page after MQD. */ + /* + * Control stack is located one page after the MQD. allocate_mqd() + * sized this region from qp->ctl_stack_size (page aligned). On the + * CRIU restore path ctl_stack_size is derived from the untrusted, + * user-supplied q_data->ctl_stack_size and, on multi-XCC parts, from + * a divisor that may not match the one used to size the allocation. + * Bound the copy to the allocated region so a malicious checkpoint + * cannot write past the MQD buffer object into adjacent kernel + * (TTM/GTT) memory. + */ ctl_stack = (void *)((uintptr_t)*mqd + AMDGPU_GPU_PAGE_SIZE); + if (ctl_stack_size > qp->ctl_stack_size) { + pr_err_ratelimited("ctl_stack_size 0x%x exceeds allocated 0x%x, clamping\n", + ctl_stack_size, qp->ctl_stack_size); + ctl_stack_size = qp->ctl_stack_size; + } memcpy(ctl_stack, ctl_stack_src, ctl_stack_size); m->cp_hqd_pq_doorbell_control = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 071f956f183c..7c4f89cf283c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -27,6 +27,7 @@ #include "kfd_device_queue_manager.h" #include "kfd_priv.h" #include "kfd_kernel_queue.h" +#include "kfd_topology.h" #include "amdgpu_amdkfd.h" #include "amdgpu_reset.h" @@ -984,7 +985,9 @@ int kfd_criu_restore_queue(struct kfd_process *p, { uint8_t *mqd, *ctl_stack, *q_extra_data = NULL; struct kfd_criu_queue_priv_data *q_data; + struct kfd_topology_device *topo_dev; struct kfd_process_device *pdd; + uint32_t max_ctl_stack_size, num_xcc; uint64_t q_extra_data_size; struct queue_properties qp; unsigned int queue_id; @@ -1032,6 +1035,29 @@ int kfd_criu_restore_queue(struct kfd_process *p, goto exit; } + /* + * q_data->ctl_stack_size is user-supplied and is consumed across all + * XCCs of the node when restoring the MQD control stack. Reject sizes + * that could not have come from a valid checkpoint before sizing any + * allocation or copy, so a bogus value can never drive an + * out-of-bounds control stack write during MQD restore. + */ + num_xcc = NUM_XCC(pdd->dev->xcc_mask); + topo_dev = kfd_topology_device_by_id(pdd->dev->id); + if (!num_xcc || !topo_dev) { + ret = -EINVAL; + goto exit; + } + max_ctl_stack_size = ALIGN(topo_dev->node_props.ctl_stack_size, PAGE_SIZE); + if (q_data->type == KFD_QUEUE_TYPE_COMPUTE && + q_data->ctl_stack_size > (uint64_t)max_ctl_stack_size * num_xcc) { + pr_err("CRIU restore ctl_stack_size 0x%x exceeds max 0x%llx\n", + q_data->ctl_stack_size, + (uint64_t)max_ctl_stack_size * num_xcc); + ret = -EINVAL; + goto exit; + } + /* * data stored in this order: * mqd[xcc0], mqd[xcc1],..., ctl_stack[xcc0], ctl_stack[xcc1]... -- 2.43.0
