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

Commit 9eea7955 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "From bbfaa7d36c1eb465f120f2a3dfe25c1fe022195d Mon Sep 17 00:00:00 2001...

Merge "From bbfaa7d36c1eb465f120f2a3dfe25c1fe022195d Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang <kaichieh.chuang@mediatek.com> Date: Thu, 7 Mar 2019 07:51:09 +0800 Subject: [PATCH] ASoC: dpcm: prevent snd_soc_dpcm use after free"
parents 9c978aa8 cae336fb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1070,6 +1070,8 @@ struct snd_soc_card {
	struct mutex dapm_mutex;
	struct mutex dapm_power_mutex;

	spinlock_t dpcm_lock;

	bool instantiated;
	bool topology_shortname_created;

+1 −0
Original line number Diff line number Diff line
@@ -2792,6 +2792,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
	mutex_init(&card->mutex);
	mutex_init(&card->dapm_mutex);
	mutex_init(&card->dapm_power_mutex);
	spin_lock_init(&card->dpcm_lock);

	ret = snd_soc_instantiate_card(card);
	if (ret != 0)
+26 −7
Original line number Diff line number Diff line
@@ -1340,8 +1340,10 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
	dpcm->fe = fe;
	be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
	dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
	spin_lock(&fe->card->dpcm_lock);
	list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
	list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
	spin_unlock(&fe->card->dpcm_lock);

	dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
			stream ? "capture" : "playback",  fe->dai_link->name,
@@ -1406,8 +1408,10 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
#ifdef CONFIG_DEBUG_FS
		debugfs_remove(dpcm->debugfs_state);
#endif
		spin_lock(&fe->card->dpcm_lock);
		list_del(&dpcm->list_be);
		list_del(&dpcm->list_fe);
		spin_unlock(&fe->card->dpcm_lock);
		kfree(dpcm);
	}
}
@@ -1672,9 +1676,11 @@ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
{
	struct snd_soc_dpcm *dpcm;

	spin_lock(&fe->card->dpcm_lock);
	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
		dpcm->be->dpcm[stream].runtime_update =
						SND_SOC_DPCM_UPDATE_NO;
	spin_unlock(&fe->card->dpcm_lock);
}

static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
@@ -3044,11 +3050,13 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
	dpcm_be_dai_shutdown(fe, stream);
disconnect:
	/* disconnect any non started BEs */
	spin_lock(&fe->card->dpcm_lock);
	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
		struct snd_soc_pcm_runtime *be = dpcm->be;
		if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
				dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
	}
	spin_unlock(&fe->card->dpcm_lock);

	return ret;
}
@@ -3662,7 +3670,9 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
{
	struct snd_soc_dpcm *dpcm;
	int state;
	int ret = 1;

	spin_lock(&fe->card->dpcm_lock);
	list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {

		if (dpcm->fe == fe)
@@ -3671,12 +3681,15 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
		state = dpcm->fe->dpcm[stream].state;
		if (state == SND_SOC_DPCM_STATE_START ||
			state == SND_SOC_DPCM_STATE_PAUSED ||
			state == SND_SOC_DPCM_STATE_SUSPEND)
			return 0;
			state == SND_SOC_DPCM_STATE_SUSPEND) {
			ret = 0;
			break;
		}
	}
	spin_unlock(&fe->card->dpcm_lock);

	/* it's safe to free/stop this BE DAI */
	return 1;
	return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);

@@ -3689,7 +3702,9 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
{
	struct snd_soc_dpcm *dpcm;
	int state;
	int ret = 1;

	spin_lock(&fe->card->dpcm_lock);
	list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {

		if (dpcm->fe == fe)
@@ -3699,12 +3714,15 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
		if (state == SND_SOC_DPCM_STATE_START ||
			state == SND_SOC_DPCM_STATE_PAUSED ||
			state == SND_SOC_DPCM_STATE_SUSPEND ||
			state == SND_SOC_DPCM_STATE_PREPARE)
			return 0;
			state == SND_SOC_DPCM_STATE_PREPARE) {
			ret = 0;
			break;
		}
	}
	spin_unlock(&fe->card->dpcm_lock);

	/* it's safe to change hw_params */
	return 1;
	return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);

@@ -3770,6 +3788,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
		goto out;
	}

	spin_lock(&fe->card->dpcm_lock);
	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
		struct snd_soc_pcm_runtime *be = dpcm->be;
		params = &dpcm->hw_params;
@@ -3790,7 +3809,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
				params_channels(params),
				params_rate(params));
	}

	spin_unlock(&fe->card->dpcm_lock);
out:
	return offset;
}