Commit 983e59d0 authored by xiongmengbiao's avatar xiongmengbiao
Browse files

crypto: ccp: fix the sev_do_cmd panic on non-Hygon platforms

hygon inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IAYIA8


CVE: NA

---------------------------

The Hygon platform indirectly accesses the `sev_cmd_mutex` variable
through `hygon_psp_hooks`.

However, on non-Hygon platforms (such as AMD), `hygon_psp_hooks` is
not initialized, so `sev_cmd_mutex` should be accessed directly.

Fixes: fe08767e ("drivers/crypto/ccp: concurrent psp access support between user and kernel space")
Signed-off-by: default avatarxiongmengbiao <xiongmengbiao@hygon.cn>
parent 7cefb1cd
Loading
Loading
Loading
Loading
+32 −11
Original line number Diff line number Diff line
@@ -211,7 +211,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (input.cmd > CSV_MAX)
		return -EINVAL;

	if (is_vendor_hygon() && mutex_enabled) {
	if (mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -239,7 +239,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
		 * Release the mutex before calling the native ioctl function
		 * because it will acquires the mutex.
		 */
		if (is_vendor_hygon() && mutex_enabled)
		if (mutex_enabled)
			psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
		else
			mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -249,7 +249,7 @@ static long csv_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (copy_to_user(argp, &input, sizeof(struct sev_issue_cmd)))
		ret = -EFAULT;

	if (is_vendor_hygon() && mutex_enabled)
	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -412,7 +412,7 @@ static int csv_do_ringbuf_cmds(int *psp_ret)
	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (is_vendor_hygon() && mutex_enabled) {
	if (mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -431,7 +431,7 @@ static int csv_do_ringbuf_cmds(int *psp_ret)
	csv_comm_mode = CSV_COMM_MAILBOX_ON;

cmd_unlock:
	if (is_vendor_hygon() && mutex_enabled)
	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -819,7 +819,10 @@ static int vpsp_psp_mutex_trylock(void)
{
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon() && mutex_enabled)
	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (mutex_enabled)
		return psp_mutex_trylock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		return mutex_trylock(hygon_psp_hooks.sev_cmd_mutex);
@@ -829,7 +832,10 @@ static int vpsp_psp_mutex_unlock(void)
{
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon() && mutex_enabled)
	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -845,6 +851,9 @@ static int __vpsp_ring_buffer_enter_locked(int *error)
	struct csv_ringbuffer_queue *hi_queue;
	struct sev_device *sev = psp_master->sev_data;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (csv_comm_mode == CSV_COMM_RINGBUFFER_ON)
		return -EEXIST;

@@ -881,7 +890,7 @@ static int __vpsp_do_ringbuf_cmds_locked(int *psp_ret, uint8_t prio, int index)
	unsigned int rb_ctl;
	struct sev_device *sev;

	if (!psp)
	if (!psp || !hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (*hygon_psp_hooks.psp_dead)
@@ -944,6 +953,9 @@ static int vpsp_do_ringbuf_cmds_locked(int *psp_ret, uint8_t prio, int index)
	struct sev_user_data_status data;
	int rc;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	rc = __vpsp_ring_buffer_enter_locked(psp_ret);
	if (rc)
		goto end;
@@ -1055,7 +1067,7 @@ static int __vpsp_do_cmd_locked(int cmd, phys_addr_t phy_addr, int *psp_ret)
	unsigned int phys_lsb, phys_msb;
	unsigned int reg, ret = 0;

	if (!psp || !psp->sev_data)
	if (!psp || !psp->sev_data || !hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (*hygon_psp_hooks.psp_dead)
@@ -1109,7 +1121,10 @@ int vpsp_do_cmd(int cmd, phys_addr_t phy_addr, int *psp_ret)
	int rc;
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (is_vendor_hygon() && mutex_enabled) {
	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					PSP_MUTEX_TIMEOUT) != 1) {
			return -EBUSY;
@@ -1120,7 +1135,7 @@ int vpsp_do_cmd(int cmd, phys_addr_t phy_addr, int *psp_ret)

	rc = __vpsp_do_cmd_locked(cmd, phy_addr, psp_ret);

	if (is_vendor_hygon() && mutex_enabled)
	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
@@ -1138,6 +1153,9 @@ int vpsp_try_get_result(uint8_t prio, uint32_t index, phys_addr_t phy_addr,
	int ret = 0;
	struct csv_cmdptr_entry cmd = {0};

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	/* Get the retult directly if the command has been executed */
	if (index >= 0 && vpsp_get_cmd_status(prio, index) !=
			VPSP_CMD_STATUS_RUNNING) {
@@ -1202,6 +1220,9 @@ int vpsp_try_do_cmd(int cmd, phys_addr_t phy_addr, struct vpsp_ret *psp_ret)
	int index = -1;
	uint8_t prio = CSV_COMMAND_PRIORITY_LOW;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	/* ringbuffer mode check and parse command prio*/
	rb_supported = vpsp_rb_check_and_cmd_prio_parse(&prio,
			(struct vpsp_cmd *)&cmd);
+13 −2
Original line number Diff line number Diff line
@@ -401,6 +401,9 @@ static long ioctl_psp(struct file *file, unsigned int ioctl, unsigned long arg)
	struct vpsp_dev_ctrl vpsp_ctrl_op;
	int ret = -EFAULT;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (_IOC_TYPE(ioctl) != HYGON_PSP_IOC_TYPE) {
		pr_info("%s: invalid ioctl type: 0x%x\n", __func__, _IOC_TYPE(ioctl));
		return -EINVAL;
@@ -469,6 +472,9 @@ int hygon_psp_additional_setup(struct sp_device *sp)
	struct device *dev = sp->dev;
	int ret = 0;

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (!psp_misc) {
		struct miscdevice *misc;

@@ -592,7 +598,12 @@ static int __psp_do_cmd_locked(int cmd, void *data, int *psp_ret)
int psp_do_cmd(int cmd, void *data, int *psp_ret)
{
	int rc;
	if (is_vendor_hygon()) {
	int mutex_enabled = READ_ONCE(hygon_psp_hooks.psp_mutex_enabled);

	if (!hygon_psp_hooks.sev_dev_hooks_installed)
		return -ENODEV;

	if (mutex_enabled) {
		if (psp_mutex_lock_timeout(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex,
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
@@ -601,7 +612,7 @@ int psp_do_cmd(int cmd, void *data, int *psp_ret)
	}

	rc = __psp_do_cmd_locked(cmd, data, psp_ret);
	if (is_vendor_hygon())
	if (mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
+12 −5
Original line number Diff line number Diff line
@@ -200,11 +200,6 @@ int psp_dev_init(struct sp_device *sp)

	/* Request an irq */
	if (is_vendor_hygon()) {
		ret = hygon_psp_additional_setup(sp);
		if (ret) {
			dev_err(dev, "psp: unable to do additional setup\n");
			goto e_err;
		}
		ret = sp_request_hygon_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
	} else {
		ret = sp_request_psp_irq(psp->sp, psp_irq_handler, psp->name, psp);
@@ -222,6 +217,18 @@ int psp_dev_init(struct sp_device *sp)
	if (ret)
		goto e_irq;

	/**
	 * hygon_psp_additional_setup() needs to wait for
	 * sev_dev_install_hooks() to complete before it can be called.
	 */
	if (is_vendor_hygon()) {
		ret = hygon_psp_additional_setup(sp);
		if (ret) {
			dev_err(dev, "psp: unable to do additional setup\n");
			goto e_irq;
		}
	}

	/* Enable interrupt */
	iowrite32(-1, psp->io_regs + psp->vdata->inten_reg);

+8 −8
Original line number Diff line number Diff line
@@ -415,13 +415,13 @@ static int sev_do_cmd(int cmd, void *data, int *psp_ret)
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
	} else {
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_lock(&sev_cmd_mutex);
	}
	rc = __sev_do_cmd_locked(cmd, data, psp_ret);
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_unlock(&sev_cmd_mutex);

	return rc;
}
@@ -546,13 +546,13 @@ int sev_platform_init(int *error)
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
	} else {
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_lock(&sev_cmd_mutex);
	}
	rc = __sev_platform_init_locked(error);
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_unlock(&sev_cmd_mutex);

	return rc;
}
@@ -596,13 +596,13 @@ static int sev_platform_shutdown(int *error)
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
	} else {
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_lock(&sev_cmd_mutex);
	}
	rc = __sev_platform_shutdown_locked(NULL);
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_unlock(&sev_cmd_mutex);

	return rc;
}
@@ -1168,7 +1168,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
					   PSP_MUTEX_TIMEOUT) != 1)
			return -EBUSY;
	} else {
		mutex_lock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_lock(&sev_cmd_mutex);
	}

	switch (input.cmd) {
@@ -1212,7 +1212,7 @@ static long sev_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
	if (is_vendor_hygon() && mutex_enabled)
		psp_mutex_unlock(&hygon_psp_hooks.psp_misc->data_pg_aligned->mb_mutex);
	else
		mutex_unlock(hygon_psp_hooks.sev_cmd_mutex);
		mutex_unlock(&sev_cmd_mutex);

	return ret;
}