[v2,1/3] ASoC: sunxi: sun4i-spdif: Use guard() for spin locks
Commit Message
From: bui duc phuc <phucduc.bui@gmail.com>
Clean up the code using guard() for spin locks.
Merely code refactoring, and no behavior change.
Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
---
Change in v2:
- Switched from using guard() to scoped_guard()
sound/soc/sunxi/sun4i-spdif.c | 62 ++++++++++++++++-------------------
1 file changed, 28 insertions(+), 34 deletions(-)
Comments
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [Critical] If `regmap_read()` fails in `sun4i_spdif_get_status()`, the local variable `reg` is left uninitialized, leading to a kernel stack information leak.
--
commit b943afeae6523774115b9e6d838ae64e650c95c5
Author: bui duc phuc <phucduc.bui@gmail.com>
ASoC: sunxi: sun4i-spdif: Use guard() for spin locks
This commit refactors the sun4i-spdif driver to use the scoped_guard() macro
for managing spin locks. The changes are intended as refactoring only, with
no functional changes to the driver's behavior.
> diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
> index c2ec19437cd7a..89eccc83a1301 100644
> --- a/sound/soc/sunxi/sun4i-spdif.c
> +++ b/sound/soc/sunxi/sun4i-spdif.c
> @@ -427,24 +427,21 @@ static int sun4i_spdif_get_status(struct snd_kcontrol *kcontrol,
> struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
> struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
> u8 *status = ucontrol->value.iec958.status;
> - unsigned long flags;
> unsigned int reg;
>
> - spin_lock_irqsave(&host->lock, flags);
> + scoped_guard(spinlock_irqsave, &host->lock) {
> + regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, ®);
[Severity: Critical]
This is a pre-existing issue, but does this leak uninitialized kernel stack
memory to userspace?
The regmap_read() function can fail and return an error code without modifying
the reg variable. Since the return value isn't checked, the uninitialized
contents of reg are unpacked into the status array:
status[0] = reg & 0xff;
status[1] = (reg >> 8) & 0xff;
status[2] = (reg >> 16) & 0xff;
status[3] = (reg >> 24) & 0xff;
This array is subsequently copied back to userspace by the ALSA control
subsystem.
Should the return value of regmap_read() be checked, and an error returned
if it fails?
[ ... ]
@@ -427,24 +427,21 @@ static int sun4i_spdif_get_status(struct snd_kcontrol *kcontrol,
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
u8 *status = ucontrol->value.iec958.status;
- unsigned long flags;
unsigned int reg;
- spin_lock_irqsave(&host->lock, flags);
+ scoped_guard(spinlock_irqsave, &host->lock) {
+ regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, ®);
- regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA0, ®);
+ status[0] = reg & 0xff;
+ status[1] = (reg >> 8) & 0xff;
+ status[2] = (reg >> 16) & 0xff;
+ status[3] = (reg >> 24) & 0xff;
- status[0] = reg & 0xff;
- status[1] = (reg >> 8) & 0xff;
- status[2] = (reg >> 16) & 0xff;
- status[3] = (reg >> 24) & 0xff;
+ regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA1, ®);
- regmap_read(host->regmap, SUN4I_SPDIF_TXCHSTA1, ®);
-
- status[4] = reg & 0xff;
- status[5] = (reg >> 8) & 0x3;
-
- spin_unlock_irqrestore(&host->lock, flags);
+ status[4] = reg & 0xff;
+ status[5] = (reg >> 8) & 0x3;
+ }
return 0;
}
@@ -455,35 +452,32 @@ static int sun4i_spdif_set_status(struct snd_kcontrol *kcontrol,
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct sun4i_spdif_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
u8 *status = ucontrol->value.iec958.status;
- unsigned long flags;
unsigned int reg;
bool chg0, chg1;
- spin_lock_irqsave(&host->lock, flags);
-
- reg = (u32)status[3] << 24;
- reg |= (u32)status[2] << 16;
- reg |= (u32)status[1] << 8;
- reg |= (u32)status[0];
+ scoped_guard(spinlock_irqsave, &host->lock) {
+ reg = (u32)status[3] << 24;
+ reg |= (u32)status[2] << 16;
+ reg |= (u32)status[1] << 8;
+ reg |= (u32)status[0];
- regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA0,
- GENMASK(31,0), reg, &chg0);
+ regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA0,
+ GENMASK(31, 0), reg, &chg0);
- reg = (u32)status[5] << 8;
- reg |= (u32)status[4];
+ reg = (u32)status[5] << 8;
+ reg |= (u32)status[4];
- regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA1,
- GENMASK(9,0), reg, &chg1);
+ regmap_update_bits_check(host->regmap, SUN4I_SPDIF_TXCHSTA1,
+ GENMASK(9, 0), reg, &chg1);
- reg = SUN4I_SPDIF_TXCFG_CHSTMODE;
- if (status[0] & IEC958_AES0_NONAUDIO)
- reg |= SUN4I_SPDIF_TXCFG_NONAUDIO;
+ reg = SUN4I_SPDIF_TXCFG_CHSTMODE;
+ if (status[0] & IEC958_AES0_NONAUDIO)
+ reg |= SUN4I_SPDIF_TXCFG_NONAUDIO;
- regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
- SUN4I_SPDIF_TXCFG_CHSTMODE |
- SUN4I_SPDIF_TXCFG_NONAUDIO, reg);
-
- spin_unlock_irqrestore(&host->lock, flags);
+ regmap_update_bits(host->regmap, SUN4I_SPDIF_TXCFG,
+ SUN4I_SPDIF_TXCFG_CHSTMODE |
+ SUN4I_SPDIF_TXCFG_NONAUDIO, reg);
+ }
return chg0 || chg1;
}