]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Apr 2024 08:37:21 +0000 (10:37 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 1 Apr 2024 08:37:21 +0000 (10:37 +0200)
added patches:
alsa-sh-aica-reorder-cleanup-operations-to-avoid-uaf-bugs.patch

queue-6.6/alsa-sh-aica-reorder-cleanup-operations-to-avoid-uaf-bugs.patch [new file with mode: 0644]
queue-6.6/series

diff --git a/queue-6.6/alsa-sh-aica-reorder-cleanup-operations-to-avoid-uaf-bugs.patch b/queue-6.6/alsa-sh-aica-reorder-cleanup-operations-to-avoid-uaf-bugs.patch
new file mode 100644 (file)
index 0000000..9119274
--- /dev/null
@@ -0,0 +1,95 @@
+From 051e0840ffa8ab25554d6b14b62c9ab9e4901457 Mon Sep 17 00:00:00 2001
+From: Duoming Zhou <duoming@zju.edu.cn>
+Date: Tue, 26 Mar 2024 17:42:38 +0800
+Subject: ALSA: sh: aica: reorder cleanup operations to avoid UAF bugs
+
+From: Duoming Zhou <duoming@zju.edu.cn>
+
+commit 051e0840ffa8ab25554d6b14b62c9ab9e4901457 upstream.
+
+The dreamcastcard->timer could schedule the spu_dma_work and the
+spu_dma_work could also arm the dreamcastcard->timer.
+
+When the snd_pcm_substream is closing, the aica_channel will be
+deallocated. But it could still be dereferenced in the worker
+thread. The reason is that del_timer() will return directly
+regardless of whether the timer handler is running or not and
+the worker could be rescheduled in the timer handler. As a result,
+the UAF bug will happen. The racy situation is shown below:
+
+      (Thread 1)                 |      (Thread 2)
+snd_aicapcm_pcm_close()          |
+ ...                             |  run_spu_dma() //worker
+                                 |    mod_timer()
+  flush_work()                   |
+  del_timer()                    |  aica_period_elapsed() //timer
+  kfree(dreamcastcard->channel)  |    schedule_work()
+                                 |  run_spu_dma() //worker
+  ...                            |    dreamcastcard->channel-> //USE
+
+In order to mitigate this bug and other possible corner cases,
+call mod_timer() conditionally in run_spu_dma(), then implement
+PCM sync_stop op to cancel both the timer and worker. The sync_stop
+op will be called from PCM core appropriately when needed.
+
+Fixes: 198de43d758c ("[ALSA] Add ALSA support for the SEGA Dreamcast PCM device")
+Suggested-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
+Message-ID: <20240326094238.95442-1-duoming@zju.edu.cn>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/sh/aica.c |   17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+--- a/sound/sh/aica.c
++++ b/sound/sh/aica.c
+@@ -278,7 +278,8 @@ static void run_spu_dma(struct work_stru
+               dreamcastcard->clicks++;
+               if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
+                       dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
+-              mod_timer(&dreamcastcard->timer, jiffies + 1);
++              if (snd_pcm_running(dreamcastcard->substream))
++                      mod_timer(&dreamcastcard->timer, jiffies + 1);
+       }
+ }
+@@ -290,6 +291,8 @@ static void aica_period_elapsed(struct t
+       /*timer function - so cannot sleep */
+       int play_period;
+       struct snd_pcm_runtime *runtime;
++      if (!snd_pcm_running(substream))
++              return;
+       runtime = substream->runtime;
+       dreamcastcard = substream->pcm->private_data;
+       /* Have we played out an additional period? */
+@@ -350,12 +353,19 @@ static int snd_aicapcm_pcm_open(struct s
+       return 0;
+ }
++static int snd_aicapcm_pcm_sync_stop(struct snd_pcm_substream *substream)
++{
++      struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
++
++      del_timer_sync(&dreamcastcard->timer);
++      cancel_work_sync(&dreamcastcard->spu_dma_work);
++      return 0;
++}
++
+ static int snd_aicapcm_pcm_close(struct snd_pcm_substream
+                                *substream)
+ {
+       struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+-      flush_work(&(dreamcastcard->spu_dma_work));
+-      del_timer(&dreamcastcard->timer);
+       dreamcastcard->substream = NULL;
+       kfree(dreamcastcard->channel);
+       spu_disable();
+@@ -401,6 +411,7 @@ static const struct snd_pcm_ops snd_aica
+       .prepare = snd_aicapcm_pcm_prepare,
+       .trigger = snd_aicapcm_pcm_trigger,
+       .pointer = snd_aicapcm_pcm_pointer,
++      .sync_stop = snd_aicapcm_pcm_sync_stop,
+ };
+ /* TO DO: set up to handle more than one pcm instance */
index 8af5f91dd284b80f29fff6b1c3d3a2ddfa6789e6..fb12705c14c2cb8117b324b0f24fd6587babd8ec 100644 (file)
@@ -353,3 +353,4 @@ drm-amd-display-fix-hang-underflow-when-transitionin.patch
 drm-amd-display-disconnect-phantom-pipe-opp-from-opt.patch
 drm-amd-display-clear-optc-mem-select-on-disable.patch
 vfio-pds-make-sure-migration-file-isn-t-accessed-aft.patch
+alsa-sh-aica-reorder-cleanup-operations-to-avoid-uaf-bugs.patch