From: sashiko-bot@kernel.org
To: "James Calligeros" <jcalligeros99@gmail.com>
Cc: robh@kernel.org, devicetree@vger.kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v2 09/21] ASoC: apple: Add macaudio machine driver
Date: Sun, 04 Oct 2026 06:24:25 +0000 [thread overview]
Message-ID: <20261004062425.A460A1F000FF@smtp.kernel.org> (raw)
In-Reply-To: <20261004-macaudio-v2-9-7b47ed6335a8@gmail.com>
Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:
- [High] ALSA: macaudio: UAF in workqueues due to devres and remove cleanup ordering
- [High] ALSA: macaudio: OOB memory read in macaudio_vlimit_unlock due to pointer underflow
- [High] ALSA: macaudio: ABBA deadlock between controls_rwsem and volume_lock_mutex
- [High] ALSA: macaudio: sleeping in atomic context in macaudio_be_trigger
- [High] ALSA: macaudio: invalid hardware state from mutating params in macaudio_dpcm_hw_params
- [Medium] ALSA: macaudio: spurious speaker volume lock due to race condition in macaudio_slk_put
- [Medium] ALSA: macaudio: OF node reference leak in probe error paths and driver unbind
- [Medium] ALSA: macaudio: NULL pointer dereference of DAI widget streams on malformed DT
- [Low] ALSA: macaudio: missing NULL check before pointer dereference in macaudio_vlimit_unlock
- [Low] ALSA: macaudio: data race on ma->bes_active read
--
commit 5727989ecaf382b9e8427180fda0eb828623fffb
Author: Martin Povišer <povik+lin@cutebit.org>
ASoC: apple: Add macaudio machine driver
Apple Silicon Macs have a complex audio subsystem consisting
of an I2S peripheral (MCA) and multiple codecs of various
models and capabilities. Some machines have a basic mono
speaker with hardware downmix, while others have a very
intricate stereo system consisting of multiple codecs and
drivers per L/R channel. Some machines report voice coil
voltage and current information back to the SoC, and others
do not. All machines have a headset jack.
> diff --git a/sound/soc/apple/macaudio.c b/sound/soc/apple/macaudio.c
> index 0000000000000..36a62d88bb18b
> --- /dev/null
> +++ b/sound/soc/apple/macaudio.c
> @@ -0,0 +1,1699 @@
[ ... ]
> +static void macaudio_vlimit_unlock(struct macaudio_snd_data *ma, bool unlock)
> +{
> + int ret, max;
> + struct snd_kcontrol *kctl;
> + const char *name = volume_control_names[ma->cfg->amp];
> + int namelen = strlen(name);
> +
> + if (!name) {
> + WARN_ON_ONCE(1);
> + return;
> + }
[Severity: Low]
Does this code dereference name before checking if it is NULL? The call
to strlen(name) happens just before if (!name).
[ ... ]
> + /* The caller has already taken the rw semaphore as necessary */
> + list_for_each_entry(kctl, &ma->card.snd_card->controls, list) {
> + const char *suffix = kctl->id.name + strlen(kctl->id.name) - namelen;
> +
> + if (strncmp(suffix, name, namelen))
> + continue;
[Severity: High]
Can this arithmetic underflow if the kcontrol name is shorter than
namelen? Since strlen() returns an unsigned size_t, subtracting a
larger namelen would result in a very large positive offset, leading
to an out-of-bounds memory read in strncmp().
[ ... ]
> +static void macaudio_vlimit_update(struct macaudio_snd_data *ma, bool take_rwsem)
> +{
[ ... ]
> + /*
> + * If this has been called from either of the safety interlock
> + * workqueues, the core API has not taken controls_rwsem for us.
> + * Take the write semaphore since macaudio_vlimit_unlock writes
> + * to the kcontrols.
> + */
> + if (take_rwsem)
> + down_write(&ma->card.snd_card->controls_rwsem);
[Severity: High]
Could this lead to an ABBA deadlock? When a user interacts with the
"Speaker Volume Unlock" kcontrol, the ALSA core takes controls_rwsem
before calling macaudio_slk_put(), which then acquires
volume_lock_mutex.
Here, the worker thread macaudio_vlimit_timeout_work acquires
volume_lock_mutex first and then attempts to acquire controls_rwsem
via macaudio_vlimit_update().
[ ... ]
> +static void macaudio_vlimit_timeout_work(struct work_struct *wrk)
> +{
> + struct macaudio_snd_data *ma = container_of(to_delayed_work(wrk),
> + struct macaudio_snd_data, lock_timeout_work);
> +
> + guard(mutex)(&ma->volume_lock_mutex);
> + ma->speaker_lock_remain = 0;
> + macaudio_vlimit_update(ma, true);
> +}
[Severity: Medium]
Will this blindly zeroize the timeout if it executes concurrently with a
userspace ping? If macaudio_slk_put() is actively updating the timeout
but the worker has already fired and is waiting on volume_lock_mutex,
the non-synchronous cancel_delayed_work() in macaudio_slk_put()
won't stop it. The worker will then wake up, set
ma->speaker_lock_remain = 0, and lock the volume.
[ ... ]
> +static void macaudio_vlimit_update_work(struct work_struct *wrk)
> +{
> + struct macaudio_snd_data *ma = container_of(wrk,
> + struct macaudio_snd_data, lock_update_work);
> +
> + if (ma->bes_active)
[Severity: Low]
Is this a data race? ma->bes_active is read here without any locking or
READ_ONCE(), while macaudio_be_trigger() concurrently modifies it.
[ ... ]
> +static int macaudio_parse_of(struct macaudio_snd_data *ma)
> +{
[ ... ]
> + for (be_index = 0; be_index < num_bes; be_index++) {
> + /*
> + * Set initial link name to be overwritten by a BE-specific
> + * name later so that we can use at least use the provisional
> + * name in error messages.
> + */
> + link->name = link_name;
> +
> + ret = macaudio_parse_of_be_dai_link(ma, link, be_index,
> + ncodecs_per_cpu, cpu, codec);
> + if (ret)
> + goto err_free;
> +
> + link_props->is_speakers = speakers;
> + link_props->is_headphones = !speakers;
> +
> + link_props->codecs = devm_kcalloc(dev, ncodecs_per_cpu,
> + sizeof(struct ma_codec_idle), GFP_KERNEL);
> + if (!link_props->codecs)
> + return -ENOMEM;
[Severity: Medium]
Does this directly return without cleaning up the OF node references?
Bypassing the err_free label here skips the cleanup logic, leaving the
references acquired in macaudio_parse_of_component() leaked.
Additionally, when taking the err_free path from within this loop,
num_links hasn't been incremented yet for the current iteration, so the
nodes for the currently failing link might not be released.
[ ... ]
> +static int macaudio_dpcm_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params)
> +{
[ ... ]
> + if (props->is_sense) {
> + /*
> + * The sense FE is opened exclusively by speakersafetyd in blocking
> + * mode. At the time of opening, this sample rate may be 0 if the
> + * speaker BE is not running. This does not matter, as speakersafetyd
> + * only cares about the active sample rate exported to the virtual
> + * sample rate kcontrol below.
> + */
> + rate->min = rate->max = cpu_dai->symmetric_rate;
> + return 0;
> + }
> +
> + /* Speakers BE */
> + if (props->is_speakers) {
> + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
> + /* Sense PCM: keep the existing BE rate (0 if not already running) */
> + rate->min = rate->max = cpu_dai->symmetric_rate;
> +
> + return 0;
> + }
[Severity: High]
Does setting rate->min = rate->max = cpu_dai->symmetric_rate mutate
the hardware parameters structure directly during the hw_params phase?
If the speaker BE is not running and symmetric_rate is 0, this forces
the rate to 0 Hz, which may cause downstream hardware drivers to reject
it with -EINVAL and break the stream initialization. Should constraints
like this be applied in the startup callback instead?
[ ... ]
> +static int macaudio_be_trigger(struct snd_pcm_substream *substream, int cmd)
> +{
> + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
> + struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(rtd->card);
> + struct macaudio_link_props *props = &ma->link_props[rtd->dai_link->id];
> +
> + guard(mutex)(&ma->be_link_mutex);
[Severity: High]
Can this attempt to acquire a sleeping lock while in an atomic context?
Because these DAI links are not marked with nonatomic = 1, the ASoC and
ALSA cores invoke the .trigger callback with the PCM substream spinlock
held and IRQs disabled.
[ ... ]
> +static int macaudio_add_backend_dai_route(struct snd_soc_card *card, struct snd_soc_dai *dai,
> + bool is_speakers)
> +{
> + struct snd_soc_dapm_route routes[2];
> + struct snd_soc_dapm_route *r;
> + int nroutes = 0;
> + int ret;
> +
> + memset(routes, 0, sizeof(routes));
> +
> + dev_dbg(card->dev, "adding routes for '%s'\n", dai->name);
> +
> + r = &routes[nroutes++];
> + if (is_speakers)
> + r->source = "Speaker Playback";
> + else
> + r->source = "Headphone Playback";
> + r->sink = dai->stream[SNDRV_PCM_STREAM_PLAYBACK].widget->name;
[Severity: Medium]
What happens if the configured device tree specifies a capture-only DAI?
Without verifying that the playback stream widget is non-NULL before
dereferencing its name, a malformed device tree could trigger a kernel
panic during device probe.
[ ... ]
> +static int macaudio_slk_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue)
> +{
> + struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
> + struct macaudio_snd_data *ma = snd_soc_card_get_drvdata(card);
> +
> + guard(mutex)(&ma->volume_lock_mutex);
[Severity: High]
Could this result in an ABBA deadlock? As mentioned earlier, this function
is called with controls_rwsem held by the core, and takes
volume_lock_mutex. The background worker acquires volume_lock_mutex
first and then attempts to acquire controls_rwsem.
[ ... ]
> + cancel_delayed_work(&ma->lock_timeout_work);
> +
> + ma->speaker_lock_remain = ms_to_ktime(SPEAKER_LOCK_TIMEOUT);
> + ma->speaker_lock_timeout = ktime_add(ktime_get(), ma->speaker_lock_remain);
> + macaudio_vlimit_update(ma, false);
[Severity: Medium]
Will this non-synchronous cancel_delayed_work() fail to stop the worker
if it is already running and waiting on volume_lock_mutex? This ties into
the race condition discussed in macaudio_vlimit_timeout_work().
[ ... ]
> +static int macaudio_snd_platform_probe(struct platform_device *pdev)
> +{
[ ... ]
> + INIT_WORK(&data->lock_update_work, macaudio_vlimit_update_work);
> + INIT_DELAYED_WORK(&data->lock_timeout_work, macaudio_vlimit_timeout_work);
> +
> + return devm_snd_soc_register_card(dev, card);
> +}
[Severity: High]
Does registering the card via devres create a use-after-free window
during unbind? The devres cleanup (including unregistering the card)
runs after macaudio_snd_platform_remove() completes. This leaves a
window where ALSA callbacks can still fire and re-queue workitems on
the workqueues that were cancelled during remove.
[ ... ]
> +static void macaudio_snd_platform_remove(struct platform_device *pdev)
> +{
> + struct macaudio_snd_data *ma = dev_get_drvdata(&pdev->dev);
> +
> + cancel_work_sync(&ma->lock_update_work);
> + cancel_delayed_work_sync(&ma->lock_timeout_work);
> +}
[Severity: High]
Since the sound card is still fully active here (due to devres), can the
work items get re-queued by ongoing ALSA callbacks right after these sync
cancels? When devres later frees macaudio_snd_data, any re-queued work
would execute on freed memory.
[Severity: Medium]
Does this remove handler also leak the OF node references acquired during
probe? It appears to omit the necessary calls to
snd_soc_of_put_dai_link_codecs() and snd_soc_of_put_dai_link_cpus().
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261004-macaudio-v2-0-7b47ed6335a8@gmail.com?part=9
next prev parent reply other threads:[~2026-10-04 6:24 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-04 6:03 [PATCH v2 00/21] Add speaker and headset jack support for Apple Silicon Macs James Calligeros
2026-10-04 6:03 ` [PATCH v2 01/21] ASoC: dt-bindings: cs42l84: Document sound-name-prefix property James Calligeros
2026-10-09 7:09 ` Krzysztof Kozlowski
2026-10-04 6:03 ` [PATCH v2 02/21] ASoC: dt-bindings: cs42l42: Do not require chip power supplies James Calligeros
2026-10-09 7:10 ` Krzysztof Kozlowski
2026-10-04 6:03 ` [PATCH v2 03/21] ASoC: dt-bindings: cs42l42: Document #sound-dai-cells property James Calligeros
2026-10-09 7:10 ` Krzysztof Kozlowski
2026-10-04 6:03 ` [PATCH v2 04/21] ASoC: dt-bindings: cs42l42: Document sound-name-prefix property James Calligeros
2026-10-09 7:11 ` Krzysztof Kozlowski
2026-10-04 6:03 ` [PATCH v2 05/21] ASoC: dt-bindings: Add binding for Apple Silicon Mac audio James Calligeros
2026-10-04 6:15 ` sashiko-bot
2026-10-09 7:17 ` Krzysztof Kozlowski
2026-10-09 7:21 ` James Calligeros
2026-10-09 7:29 ` Krzysztof Kozlowski
2026-10-04 6:03 ` [PATCH v2 06/21] ASoC: ops: Introduce 'snd_soc_deactivate_kctl' James Calligeros
2026-10-09 8:16 ` Cezary Rojewski
2026-10-04 6:03 ` [PATCH v2 07/21] ASoC: ops: Introduce 'soc_set_enum_kctl' James Calligeros
2026-10-04 6:22 ` sashiko-bot
2026-10-07 17:36 ` Ajay Kumar Nandam
2026-10-09 8:27 ` Cezary Rojewski
2026-10-04 6:03 ` [PATCH v2 08/21] ASoC: card: Let 'fixup_controls' return errors James Calligeros
2026-10-07 14:23 ` Charles Keepax
2026-10-04 6:03 ` [PATCH v2 09/21] ASoC: apple: Add macaudio machine driver James Calligeros
2026-10-04 6:24 ` sashiko-bot [this message]
2026-10-07 18:04 ` Ajay Kumar Nandam
2026-10-04 6:03 ` [PATCH v2 10/21] arm64: dts: apple: t8103-j274: Add speaker/headset jack nodes James Calligeros
2026-10-04 6:17 ` sashiko-bot
2026-10-07 18:17 ` Ajay Kumar Nandam
2026-10-04 6:03 ` [PATCH v2 11/21] arm64: dts: apple: t8103-j313: " James Calligeros
2026-10-04 6:19 ` sashiko-bot
2026-10-07 18:32 ` Ajay Kumar Nandam
2026-10-08 8:46 ` James Calligeros
2026-10-08 9:34 ` Ajay Kumar Nandam
2026-10-04 6:03 ` [PATCH v2 12/21] arm64: dts: apple: t8103-j293: " James Calligeros
2026-10-04 6:25 ` sashiko-bot
2026-10-04 6:03 ` [PATCH v2 13/21] arm64: dts: apple: t8103-j45x: Add headset " James Calligeros
2026-10-04 6:21 ` sashiko-bot
2026-10-08 6:18 ` Ajay Kumar Nandam
2026-10-04 6:03 ` [PATCH v2 14/21] arm64: dts: apple: t8112-j413: Add speaker/headset " James Calligeros
2026-10-04 6:03 ` [PATCH v2 15/21] arm64: dts: apple: t8112-j415: " James Calligeros
2026-10-04 6:21 ` sashiko-bot
2026-10-04 6:03 ` [PATCH v2 16/21] arm64: dts: apple: t8112-j473: " James Calligeros
2026-10-04 6:03 ` [PATCH v2 17/21] arm64: dts: apple: t8112-j493: " James Calligeros
2026-10-04 6:03 ` [PATCH v2 18/21] arm64: dts: apple: t600x-j31x: " James Calligeros
2026-10-04 6:24 ` sashiko-bot
2026-10-04 6:03 ` [PATCH v2 19/21] arm64: dts: apple: t600x-j375: " James Calligeros
2026-10-04 6:03 ` [PATCH v2 20/21] arm64: dts: apple: t602x-j41x: " James Calligeros
2026-10-04 6:03 ` [PATCH v2 21/21] arm64: dts: apple: t602x-j47x: " James Calligeros
2026-10-08 9:29 ` Ajay Kumar Nandam
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261004062425.A460A1F000FF@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=jcalligeros99@gmail.com \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox