Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60871bde authored by Vidyakumar Athota's avatar Vidyakumar Athota
Browse files

ipc: initialize glink link state



There is a chance that glink channel memory pointer is used
after free if WDSP_REG_PKT and WDSP_CMD_PKT are received at
the same time from different threads. Fix this issue by
initializing glink link state to GLINK_LINK_STATE_DOWN.
Also limit error logs to avoid watchdog timeout issues.

Change-Id: I07c4e6f12eb057405eb59f1c0d04b890fa964ce8
Signed-off-by: default avatarVidyakumar Athota <vathota@codeaurora.org>
parent 8f7ccc2e
Loading
Loading
Loading
Loading
+20 −18
Original line number Original line Diff line number Diff line
@@ -570,7 +570,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,


	mutex_lock(&wpriv->glink_mutex);
	mutex_lock(&wpriv->glink_mutex);
	if (wpriv->ch) {
	if (wpriv->ch) {
		dev_err(wpriv->dev, "%s: glink ch memory is already allocated\n",
		dev_err_ratelimited(wpriv->dev, "%s: glink ch memory is already allocated\n",
			 __func__);
			 __func__);
		ret = -EINVAL;
		ret = -EINVAL;
		goto done;
		goto done;
@@ -579,7 +579,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
	no_of_channels = pkt->no_of_channels;
	no_of_channels = pkt->no_of_channels;


	if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
	if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
		dev_err(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
		dev_err_ratelimited(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
			__func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
			__func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
		ret = -EINVAL;
		ret = -EINVAL;
		goto done;
		goto done;
@@ -598,20 +598,20 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,


		size += WDSP_CH_CFG_SIZE;
		size += WDSP_CH_CFG_SIZE;
		if (size > pkt_size) {
		if (size > pkt_size) {
			dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
			dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
				__func__, size, pkt_size);
				__func__, size, pkt_size);
			ret = -EINVAL;
			ret = -EINVAL;
			goto err_ch_mem;
			goto err_ch_mem;
		}
		}
		if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
		if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
			dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
			dev_err_ratelimited(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
				__func__, ch_cfg->no_of_intents);
				__func__, ch_cfg->no_of_intents);
			ret = -EINVAL;
			ret = -EINVAL;
			goto err_ch_mem;
			goto err_ch_mem;
		}
		}
		size += (sizeof(u32) * ch_cfg->no_of_intents);
		size += (sizeof(u32) * ch_cfg->no_of_intents);
		if (size > pkt_size) {
		if (size > pkt_size) {
			dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
			dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
				__func__, size, pkt_size);
				__func__, size, pkt_size);
			ret = -EINVAL;
			ret = -EINVAL;
			goto err_ch_mem;
			goto err_ch_mem;
@@ -746,7 +746,7 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf,
	}
	}


	if (count > WDSP_MAX_READ_SIZE) {
	if (count > WDSP_MAX_READ_SIZE) {
		dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n",
		dev_info_ratelimited(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n",
			__func__, count);
			__func__, count);
		count = WDSP_MAX_READ_SIZE;
		count = WDSP_MAX_READ_SIZE;
	}
	}
@@ -778,7 +778,7 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf,


		if (ret1) {
		if (ret1) {
			mutex_unlock(&wpriv->rsp_mutex);
			mutex_unlock(&wpriv->rsp_mutex);
			dev_err(wpriv->dev, "%s: copy_to_user failed %d\n",
			dev_err_ratelimited(wpriv->dev, "%s: copy_to_user failed %d\n",
				__func__, ret);
				__func__, ret);
			ret = -EFAULT;
			ret = -EFAULT;
			goto done;
			goto done;
@@ -824,7 +824,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,


	if ((count < WDSP_WRITE_PKT_SIZE) ||
	if ((count < WDSP_WRITE_PKT_SIZE) ||
	    (count > WDSP_MAX_WRITE_SIZE)) {
	    (count > WDSP_MAX_WRITE_SIZE)) {
		dev_err(wpriv->dev, "%s: Invalid count = %zd\n",
		dev_err_ratelimited(wpriv->dev, "%s: Invalid count = %zd\n",
			__func__, count);
			__func__, count);
		ret = -EINVAL;
		ret = -EINVAL;
		goto done;
		goto done;
@@ -841,7 +841,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,


	ret = copy_from_user(tx_buf->buf, buf, count);
	ret = copy_from_user(tx_buf->buf, buf, count);
	if (ret) {
	if (ret) {
		dev_err(wpriv->dev, "%s: copy_from_user failed %d\n",
		dev_err_ratelimited(wpriv->dev, "%s: copy_from_user failed %d\n",
			__func__, ret);
			__func__, ret);
		ret = -EFAULT;
		ret = -EFAULT;
		goto free_buf;
		goto free_buf;
@@ -852,7 +852,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
	case WDSP_REG_PKT:
	case WDSP_REG_PKT:
		if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE +
		if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE +
			     WDSP_CH_CFG_SIZE)) {
			     WDSP_CH_CFG_SIZE)) {
			dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
			dev_err_ratelimited(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
				__func__, count);
				__func__, count);
			ret = -EINVAL;
			ret = -EINVAL;
			goto free_buf;
			goto free_buf;
@@ -861,7 +861,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
					(struct wdsp_reg_pkt *)wpkt->payload,
					(struct wdsp_reg_pkt *)wpkt->payload,
					count);
					count);
		if (ret < 0)
		if (ret < 0)
			dev_err(wpriv->dev, "%s: glink register failed, ret = %d\n",
			dev_err_ratelimited(wpriv->dev, "%s: glink register failed, ret = %d\n",
				__func__, ret);
				__func__, ret);
		vfree(tx_buf);
		vfree(tx_buf);
		break;
		break;
@@ -871,7 +871,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
							GLINK_LINK_STATE_UP),
							GLINK_LINK_STATE_UP),
					 msecs_to_jiffies(TIMEOUT_MS));
					 msecs_to_jiffies(TIMEOUT_MS));
		if (!ret) {
		if (!ret) {
			dev_err(wpriv->dev, "%s: Link state wait timeout\n",
			dev_err_ratelimited(wpriv->dev, "%s: Link state wait timeout\n",
				__func__);
				__func__);
			ret = -ETIMEDOUT;
			ret = -ETIMEDOUT;
			goto free_buf;
			goto free_buf;
@@ -881,7 +881,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
		break;
		break;
	case WDSP_CMD_PKT:
	case WDSP_CMD_PKT:
		if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) {
		if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) {
			dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
			dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
				__func__, count);
				__func__, count);
			ret = -EINVAL;
			ret = -EINVAL;
			goto free_buf;
			goto free_buf;
@@ -889,7 +889,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
		mutex_lock(&wpriv->glink_mutex);
		mutex_lock(&wpriv->glink_mutex);
		if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
		if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
			mutex_unlock(&wpriv->glink_mutex);
			mutex_unlock(&wpriv->glink_mutex);
			dev_err(wpriv->dev, "%s: Link state is Down\n",
			dev_err_ratelimited(wpriv->dev, "%s: Link state is Down\n",
				__func__);
				__func__);


			ret = -ENETRESET;
			ret = -ENETRESET;
@@ -901,7 +901,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
					sizeof(struct wdsp_cmd_pkt) +
					sizeof(struct wdsp_cmd_pkt) +
					cpkt->payload_size;
					cpkt->payload_size;
		if (count < pkt_max_size) {
		if (count < pkt_max_size) {
			dev_err(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n",
			dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n",
				__func__, count, pkt_max_size);
				__func__, count, pkt_max_size);
			ret = -EINVAL;
			ret = -EINVAL;
			goto free_buf;
			goto free_buf;
@@ -917,7 +917,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
			}
			}
		}
		}
		if (!tx_buf->ch) {
		if (!tx_buf->ch) {
			dev_err(wpriv->dev, "%s: Failed to get glink channel\n",
			dev_err_ratelimited(wpriv->dev, "%s: Failed to get glink channel\n",
				__func__);
				__func__);
			ret = -EINVAL;
			ret = -EINVAL;
			goto free_buf;
			goto free_buf;
@@ -928,7 +928,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
							GLINK_CONNECTED),
							GLINK_CONNECTED),
					 msecs_to_jiffies(TIMEOUT_MS));
					 msecs_to_jiffies(TIMEOUT_MS));
		if (!ret) {
		if (!ret) {
			dev_err(wpriv->dev, "%s: glink channel %s is not in connected state %d\n",
			dev_err_ratelimited(wpriv->dev, "%s: glink channel %s is not in connected state %d\n",
				__func__, tx_buf->ch->ch_cfg.name,
				__func__, tx_buf->ch->ch_cfg.name,
				tx_buf->ch->channel_state);
				tx_buf->ch->channel_state);
			ret = -ETIMEDOUT;
			ret = -ETIMEDOUT;
@@ -940,7 +940,8 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
		queue_work(wpriv->work_queue, &tx_buf->tx_work);
		queue_work(wpriv->work_queue, &tx_buf->tx_work);
		break;
		break;
	default:
	default:
		dev_err(wpriv->dev, "%s: Invalid packet type\n", __func__);
		dev_err_ratelimited(wpriv->dev, "%s: Invalid packet type\n",
				    __func__);
		ret = -EINVAL;
		ret = -EINVAL;
		vfree(tx_buf);
		vfree(tx_buf);
		break;
		break;
@@ -986,6 +987,7 @@ static int wdsp_glink_open(struct inode *inode, struct file *file)
		goto err_wq;
		goto err_wq;
	}
	}


	wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN;
	init_completion(&wpriv->rsp_complete);
	init_completion(&wpriv->rsp_complete);
	init_waitqueue_head(&wpriv->link_state_wait);
	init_waitqueue_head(&wpriv->link_state_wait);
	mutex_init(&wpriv->rsp_mutex);
	mutex_init(&wpriv->rsp_mutex);