Commit 421c0f19 authored by David Francis's avatar David Francis Committed by Alex Deucher
Browse files

drm/amdgpu: Check for multiplication overflow in checkpoint stack size



get_checkpoint_info() in kfd_mqd_manager_v9.c finds 32-bit value
ctl_stack_size by multiplying two 32-bit values. This can overflow to a
lower value, which could result in copying outside the bounds of
a buffer in checkpoint_mqd() in the same file.

Put in a check for the overflow, and fail with -EINVAL if detected.

v2: use check_mul_overflow()

Signed-off-by: default avatarDavid Francis <David.Francis@amd.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 8c78845b
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -2720,7 +2720,7 @@ static int get_wave_state(struct device_queue_manager *dqm,
			ctl_stack, ctl_stack_used_size, save_area_used_size);
}

static void get_queue_checkpoint_info(struct device_queue_manager *dqm,
static int get_queue_checkpoint_info(struct device_queue_manager *dqm,
			const struct queue *q,
			u32 *mqd_size,
			u32 *ctl_stack_size)
@@ -2728,6 +2728,7 @@ static void get_queue_checkpoint_info(struct device_queue_manager *dqm,
	struct mqd_manager *mqd_mgr;
	enum KFD_MQD_TYPE mqd_type =
			get_mqd_type_from_queue_type(q->properties.type);
	int ret = 0;

	dqm_lock(dqm);
	mqd_mgr = dqm->mqd_mgrs[mqd_type];
@@ -2735,9 +2736,11 @@ static void get_queue_checkpoint_info(struct device_queue_manager *dqm,
	*ctl_stack_size = 0;

	if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE && mqd_mgr->get_checkpoint_info)
		mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size);
		ret = mqd_mgr->get_checkpoint_info(mqd_mgr, q->mqd, ctl_stack_size);

	dqm_unlock(dqm);

	return ret;
}

static int checkpoint_mqd(struct device_queue_manager *dqm,
+1 −1
Original line number Diff line number Diff line
@@ -192,7 +192,7 @@ struct device_queue_manager_ops {

	int (*reset_queues)(struct device_queue_manager *dqm,
					uint16_t pasid);
	void	(*get_queue_checkpoint_info)(struct device_queue_manager *dqm,
	int	(*get_queue_checkpoint_info)(struct device_queue_manager *dqm,
				  const struct queue *q, u32 *mqd_size,
				  u32 *ctl_stack_size);

+2 −1
Original line number Diff line number Diff line
@@ -102,7 +102,8 @@ struct mqd_manager {
				  u32 *ctl_stack_used_size,
				  u32 *save_area_used_size);

	void	(*get_checkpoint_info)(struct mqd_manager *mm, void *mqd, uint32_t *ctl_stack_size);
	int	(*get_checkpoint_info)(struct mqd_manager *mm, void *mqd,
				       uint32_t *ctl_stack_size);

	void	(*checkpoint_mqd)(struct mqd_manager *mm,
				  void *mqd,
+5 −2
Original line number Diff line number Diff line
@@ -385,11 +385,14 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
	return 0;
}

static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
{
	struct v9_mqd *m = get_mqd(mqd);

	*ctl_stack_size = m->cp_hqd_cntl_stack_size * NUM_XCC(mm->dev->xcc_mask);
	if (check_mul_overflow(m->cp_hqd_cntl_stack_size, NUM_XCC(mm->dev->xcc_mask), ctl_stack_size))
		return -EINVAL;

	return 0;
}

static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst)
+2 −1
Original line number Diff line number Diff line
@@ -274,10 +274,11 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd,
	return 0;
}

static void get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size)
{
	/* Control stack is stored in user mode */
	*ctl_stack_size = 0;
	return 0;
}

static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst)
Loading