2023-05-30 07:38:34

by Trevor Wu (吳文良)

[permalink] [raw]
Subject: [PATCH 0/2] ASoC: mediatek: fix use-after-free in driver remove path

These patches concern modifications made in mt8186[1]. The clock
unregistration mechanism used in mt8188 and mt8195 is similar with
mt8186, resulting in the same problem existing within the driver.
Therefore, the solution has also been applied to these two platforms.

[1] https://lore.kernel.org/all/20230511092437.1.I31cceffc8c45bb1af16eb613e197b3df92cdc19e@changeid/

Trevor Wu (2):
ASoC: mediatek: mt8188: fix use-after-free in driver remove path
ASoC: mediatek: mt8195: fix use-after-free in driver remove path

sound/soc/mediatek/mt8188/mt8188-afe-clk.c | 7 ---
sound/soc/mediatek/mt8188/mt8188-afe-clk.h | 1 -
sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 4 --
sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 47 ++++++++++---------
sound/soc/mediatek/mt8188/mt8188-audsys-clk.h | 1 -
sound/soc/mediatek/mt8195/mt8195-afe-clk.c | 5 --
sound/soc/mediatek/mt8195/mt8195-afe-clk.h | 1 -
sound/soc/mediatek/mt8195/mt8195-afe-pcm.c | 4 --
sound/soc/mediatek/mt8195/mt8195-audsys-clk.c | 47 ++++++++++---------
sound/soc/mediatek/mt8195/mt8195-audsys-clk.h | 1 -
10 files changed, 48 insertions(+), 70 deletions(-)

--
2.18.0



2023-05-30 07:38:34

by Trevor Wu (吳文良)

[permalink] [raw]
Subject: [PATCH 2/2] ASoC: mediatek: mt8195: fix use-after-free in driver remove path

During mt8195_afe_init_clock(), mt8195_audsys_clk_register() was called
followed by several other devm functions. At mt8195_afe_deinit_clock()
located at mt8195_afe_pcm_dev_remove(), mt8195_audsys_clk_unregister()
was called.

However, there was an issue with the order in which these functions were
called. Specifically, the remove callback of platform_driver was called
before devres released the resource, resulting in a use-after-free issue
during remove time.

At probe time, the order of calls was:
1. mt8195_audsys_clk_register
2. afe_priv->clk = devm_kcalloc
3. afe_priv->clk[i] = devm_clk_get

At remove time, the order of calls was:
1. mt8195_audsys_clk_unregister
3. free afe_priv->clk[i]
2. free afe_priv->clk

To resolve the problem, we can utilize devm_add_action_or_reset() in
mt8195_audsys_clk_register() so that the remove order can be changed to
3->2->1.

Fixes: 6746cc858259 ("ASoC: mediatek: mt8195: add platform driver")
Signed-off-by: Trevor Wu <[email protected]>
---
sound/soc/mediatek/mt8195/mt8195-afe-clk.c | 5 --
sound/soc/mediatek/mt8195/mt8195-afe-clk.h | 1 -
sound/soc/mediatek/mt8195/mt8195-afe-pcm.c | 4 --
sound/soc/mediatek/mt8195/mt8195-audsys-clk.c | 47 ++++++++++---------
sound/soc/mediatek/mt8195/mt8195-audsys-clk.h | 1 -
5 files changed, 24 insertions(+), 34 deletions(-)

diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
index 9ca2cb8c8a9c..f35318ae0739 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.c
@@ -410,11 +410,6 @@ int mt8195_afe_init_clock(struct mtk_base_afe *afe)
return 0;
}

-void mt8195_afe_deinit_clock(struct mtk_base_afe *afe)
-{
- mt8195_audsys_clk_unregister(afe);
-}
-
int mt8195_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
{
int ret;
diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-clk.h b/sound/soc/mediatek/mt8195/mt8195-afe-clk.h
index 40663e31becd..a08c0ee6c860 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-clk.h
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-clk.h
@@ -101,7 +101,6 @@ int mt8195_afe_get_mclk_source_clk_id(int sel);
int mt8195_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll);
int mt8195_afe_get_default_mclk_source_by_rate(int rate);
int mt8195_afe_init_clock(struct mtk_base_afe *afe);
-void mt8195_afe_deinit_clock(struct mtk_base_afe *afe);
int mt8195_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
void mt8195_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
int mt8195_afe_prepare_clk(struct mtk_base_afe *afe, struct clk *clk);
diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
index d22cf1664d8a..a0f2012211fb 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
@@ -3224,15 +3224,11 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)

static void mt8195_afe_pcm_dev_remove(struct platform_device *pdev)
{
- struct mtk_base_afe *afe = platform_get_drvdata(pdev);
-
snd_soc_unregister_component(&pdev->dev);

pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
mt8195_afe_runtime_suspend(&pdev->dev);
-
- mt8195_afe_deinit_clock(afe);
}

static const struct of_device_id mt8195_afe_pcm_dt_match[] = {
diff --git a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
index e0670e0dbd5b..09bd1a020421 100644
--- a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
+++ b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
@@ -148,6 +148,29 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
GATE_AUD6(CLK_AUD_GASRC19, "aud_gasrc19", "top_asm_h", 19),
};

+static void mt8195_audsys_clk_unregister(void *data)
+{
+ struct mtk_base_afe *afe = (struct mtk_base_afe *)data;
+ struct mt8195_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ if (!afe_priv)
+ return;
+
+ for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+ cl = afe_priv->lookup[i];
+ if (!cl)
+ continue;
+
+ clk = cl->clk;
+ clk_unregister_gate(clk);
+
+ clkdev_drop(cl);
+ }
+}
+
int mt8195_audsys_clk_register(struct mtk_base_afe *afe)
{
struct mt8195_afe_private *afe_priv = afe->platform_priv;
@@ -188,27 +211,5 @@ int mt8195_audsys_clk_register(struct mtk_base_afe *afe)
afe_priv->lookup[i] = cl;
}

- return 0;
-}
-
-void mt8195_audsys_clk_unregister(struct mtk_base_afe *afe)
-{
- struct mt8195_afe_private *afe_priv = afe->platform_priv;
- struct clk *clk;
- struct clk_lookup *cl;
- int i;
-
- if (!afe_priv)
- return;
-
- for (i = 0; i < CLK_AUD_NR_CLK; i++) {
- cl = afe_priv->lookup[i];
- if (!cl)
- continue;
-
- clk = cl->clk;
- clk_unregister_gate(clk);
-
- clkdev_drop(cl);
- }
+ return devm_add_action_or_reset(afe->dev, mt8195_audsys_clk_unregister, afe);
}
diff --git a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.h b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.h
index 239d31016ba7..69db2dd1c9e0 100644
--- a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.h
+++ b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.h
@@ -10,6 +10,5 @@
#define _MT8195_AUDSYS_CLK_H_

int mt8195_audsys_clk_register(struct mtk_base_afe *afe);
-void mt8195_audsys_clk_unregister(struct mtk_base_afe *afe);

#endif
--
2.18.0


2023-05-30 07:40:33

by Trevor Wu (吳文良)

[permalink] [raw]
Subject: [PATCH 1/2] ASoC: mediatek: mt8188: fix use-after-free in driver remove path

During mt8188_afe_init_clock(), mt8188_audsys_clk_register() was called
followed by several other devm functions. The caller of
mt8188_afe_init_clock() utilized devm_add_action_or_reset() to call
mt8188_afe_deinit_clock(). However, the order was incorrect, causing a
use-after-free issue during remove time.

At probe time, the order of calls was:
1. mt8188_audsys_clk_register
2. afe_priv->clk = devm_kcalloc
3. afe_priv->clk[i] = devm_clk_get

At remove time, the order of calls was:
1. mt8188_audsys_clk_unregister
3. free afe_priv->clk[i]
2. free afe_priv->clk

To resolve the problem, it's necessary to move devm_add_action_or_reset()
to the appropriate position so that the remove order can be 3->2->1.

Fixes: f6b026479b13 ("ASoC: mediatek: mt8188: support audio clock control")
Signed-off-by: Trevor Wu <[email protected]>
---
sound/soc/mediatek/mt8188/mt8188-afe-clk.c | 7 ---
sound/soc/mediatek/mt8188/mt8188-afe-clk.h | 1 -
sound/soc/mediatek/mt8188/mt8188-afe-pcm.c | 4 --
sound/soc/mediatek/mt8188/mt8188-audsys-clk.c | 47 ++++++++++---------
sound/soc/mediatek/mt8188/mt8188-audsys-clk.h | 1 -
5 files changed, 24 insertions(+), 36 deletions(-)

diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
index 4c24d0b9e90d..e69c1bb2cb23 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
@@ -436,13 +436,6 @@ int mt8188_afe_init_clock(struct mtk_base_afe *afe)
return 0;
}

-void mt8188_afe_deinit_clock(void *priv)
-{
- struct mtk_base_afe *afe = priv;
-
- mt8188_audsys_clk_unregister(afe);
-}
-
int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
{
int ret;
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
index 904505d10841..ec53c171c170 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
@@ -111,7 +111,6 @@ int mt8188_afe_get_default_mclk_source_by_rate(int rate);
int mt8188_get_apll_by_rate(struct mtk_base_afe *afe, int rate);
int mt8188_get_apll_by_name(struct mtk_base_afe *afe, const char *name);
int mt8188_afe_init_clock(struct mtk_base_afe *afe);
-void mt8188_afe_deinit_clock(void *priv);
int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
void mt8188_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
index c3fd32764da0..6a24b339444b 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -3256,10 +3256,6 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(dev, ret, "init clock error");

- ret = devm_add_action_or_reset(dev, mt8188_afe_deinit_clock, (void *)afe);
- if (ret)
- return ret;
-
spin_lock_init(&afe_priv->afe_ctrl_lock);

mutex_init(&afe->irq_alloc_lock);
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
index be1c53bf4729..05d6f9d78e10 100644
--- a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
@@ -138,6 +138,29 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
GATE_AUD6(CLK_AUD_GASRC11, "aud_gasrc11", "top_asm_h", 11),
};

+static void mt8188_audsys_clk_unregister(void *data)
+{
+ struct mtk_base_afe *afe = (struct mtk_base_afe *)data;
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct clk *clk;
+ struct clk_lookup *cl;
+ int i;
+
+ if (!afe_priv)
+ return;
+
+ for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+ cl = afe_priv->lookup[i];
+ if (!cl)
+ continue;
+
+ clk = cl->clk;
+ clk_unregister_gate(clk);
+
+ clkdev_drop(cl);
+ }
+}
+
int mt8188_audsys_clk_register(struct mtk_base_afe *afe)
{
struct mt8188_afe_private *afe_priv = afe->platform_priv;
@@ -179,27 +202,5 @@ int mt8188_audsys_clk_register(struct mtk_base_afe *afe)
afe_priv->lookup[i] = cl;
}

- return 0;
-}
-
-void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe)
-{
- struct mt8188_afe_private *afe_priv = afe->platform_priv;
- struct clk *clk;
- struct clk_lookup *cl;
- int i;
-
- if (!afe_priv)
- return;
-
- for (i = 0; i < CLK_AUD_NR_CLK; i++) {
- cl = afe_priv->lookup[i];
- if (!cl)
- continue;
-
- clk = cl->clk;
- clk_unregister_gate(clk);
-
- clkdev_drop(cl);
- }
+ return devm_add_action_or_reset(afe->dev, mt8188_audsys_clk_unregister, afe);
}
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
index 6c5f463ad7e4..45b0948c4a06 100644
--- a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
@@ -10,6 +10,5 @@
#define _MT8188_AUDSYS_CLK_H_

int mt8188_audsys_clk_register(struct mtk_base_afe *afe);
-void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe);

#endif
--
2.18.0


2023-05-31 23:50:12

by Doug Anderson

[permalink] [raw]
Subject: Re: [PATCH 1/2] ASoC: mediatek: mt8188: fix use-after-free in driver remove path

Hi,

On Tue, May 30, 2023 at 12:25 AM Trevor Wu <[email protected]> wrote:
>
> diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> index be1c53bf4729..05d6f9d78e10 100644
> --- a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> @@ -138,6 +138,29 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
> GATE_AUD6(CLK_AUD_GASRC11, "aud_gasrc11", "top_asm_h", 11),
> };
>
> +static void mt8188_audsys_clk_unregister(void *data)
> +{
> + struct mtk_base_afe *afe = (struct mtk_base_afe *)data;

The above cast is unnecessary since the compiler lets you assign from
a "void *" to another pointer without a cast. Unnecessary casts are
considered harmful because they suspend the compiler's ability to do
type checking. Other than that, this looks good. Sorry for not
noticing that the same problem affected more than just the driver I
fixed previously.

Reviewed-by: Douglas Anderson <[email protected]>

2023-06-01 02:49:52

by Trevor Wu (吳文良)

[permalink] [raw]
Subject: Re: [PATCH 2/2] ASoC: mediatek: mt8195: fix use-after-free in driver remove path

On Wed, 2023-05-31 at 16:47 -0700, Doug Anderson wrote:
>
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> Hi,
>
> On Tue, May 30, 2023 at 12:25 AM Trevor Wu <[email protected]>
> wrote:
> >
> > diff --git a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
> b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
> > index e0670e0dbd5b..09bd1a020421 100644
> > --- a/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
> > +++ b/sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
> > @@ -148,6 +148,29 @@ static const struct afe_gate
> aud_clks[CLK_AUD_NR_CLK] = {
> > GATE_AUD6(CLK_AUD_GASRC19, "aud_gasrc19", "top_asm_h", 19),
> > };
> >
> > +static void mt8195_audsys_clk_unregister(void *data)
> > +{
> > + struct mtk_base_afe *afe = (struct mtk_base_afe *)data;
>
> Same as in patch #1, the above cast isn't necessary. Other than that:
>
> Reviewed-by: Douglas Anderson <[email protected]>

OK, I will remove the cast in V2.

Thanks,
Trevor

2023-06-01 03:04:06

by Trevor Wu (吳文良)

[permalink] [raw]
Subject: Re: [PATCH 1/2] ASoC: mediatek: mt8188: fix use-after-free in driver remove path

On Wed, 2023-05-31 at 16:47 -0700, Doug Anderson wrote:
>
> you have verified the sender or the content.
> Hi,
>
> On Tue, May 30, 2023 at 12:25 AM Trevor Wu <[email protected]>
> wrote:
> >
> > diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > index be1c53bf4729..05d6f9d78e10 100644
> > --- a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
> > @@ -138,6 +138,29 @@ static const struct afe_gate
> aud_clks[CLK_AUD_NR_CLK] = {
> > GATE_AUD6(CLK_AUD_GASRC11, "aud_gasrc11", "top_asm_h", 11),
> > };
> >
> > +static void mt8188_audsys_clk_unregister(void *data)
> > +{
> > + struct mtk_base_afe *afe = (struct mtk_base_afe *)data;
>
> The above cast is unnecessary since the compiler lets you assign from
> a "void *" to another pointer without a cast. Unnecessary casts are
> considered harmful because they suspend the compiler's ability to do
> type checking. Other than that, this looks good. Sorry for not
> noticing that the same problem affected more than just the driver I
> fixed previously.
>
> Reviewed-by: Douglas Anderson <[email protected]>


Got it. I will remove the unnecessary cast in V2. Most importantly,
thank you for bringing this issue to our attention.


Thanks,
Trevor