From b951404ea74ae432312a83138f5c8945a0d09e1b Mon Sep 17 00:00:00 2001
From: Jean-Yves Avenard <jya@apple.com>
Date: Wed, 24 Apr 2024 19:01:06 -0700
Subject: [PATCH] CVE-2024-40776: Always copy all audio channels to the AudioBus 
to guarantee data lifetime.

Upstream-Status: Backport from https://github.com/WebKit/WebKit/commit/b951404ea74ae432312a83138f5c8945a0d09e1b
CVE: CVE-2024-40776

Signed-off-by: Rohini Sangam <rsangam@mvista.com>
---
 ...et-concurrent-resampler-crash-expected.txt |  1 +
 ...dioworklet-concurrent-resampler-crash.html | 44 +++++++++++++++++++
 .../platform/audio/MultiChannelResampler.cpp  | 21 ++-------
 .../platform/audio/MultiChannelResampler.h    |  2 -
 4 files changed, 48 insertions(+), 20 deletions(-)
 create mode 100644 LayoutTests/webaudio/crashtest/audioworklet-concurrent-resampler-crash-expected.txt
 create mode 100644 LayoutTests/webaudio/crashtest/audioworklet-concurrent-resampler-crash.html

diff --git a/LayoutTests/webaudio/crashtest/audioworklet-concurrent-resampler-crash-expected.txt b/LayoutTests/webaudio/crashtest/audioworklet-concurrent-resampler-crash-expected.txt
new file mode 100644
index 00000000..654ddf7f
--- /dev/null
+++ b/LayoutTests/webaudio/crashtest/audioworklet-concurrent-resampler-crash-expected.txt
@@ -0,0 +1 @@
+This test passes if it does not crash.
diff --git a/LayoutTests/webaudio/crashtest/audioworklet-concurrent-resampler-crash.html b/LayoutTests/webaudio/crashtest/audioworklet-concurrent-resampler-crash.html
new file mode 100644
index 00000000..b3ab181d
--- /dev/null
+++ b/LayoutTests/webaudio/crashtest/audioworklet-concurrent-resampler-crash.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+    <script>
+        let worklet_source = `
+            class Processor extends AudioWorkletProcessor {
+                process(inputs, outputs, parameters) {
+                    return true;
+                }
+            }
+            registerProcessor('P2', Processor);
+        `;
+
+        let blob = new Blob([worklet_source], { type: 'application/javascript' });
+        let worklet = URL.createObjectURL(blob);
+
+        var ctx = new AudioContext({ sampleRate: 44100});
+        const dest = ctx.destination;
+        dest.channelCountMode = "max";
+
+        async function main() {
+            await ctx.audioWorklet.addModule(worklet);
+            var script_processor = ctx.createScriptProcessor();
+            script_processor.onaudioprocess = function() {
+                dest.channelCount = 1;
+                audio_worklet.disconnect();
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }
+            var audio_worklet = new AudioWorkletNode(ctx, "P2");
+            script_processor.connect(audio_worklet);
+            audio_worklet.connect(dest);
+        }
+    </script>
+</head>
+<body onload="main()">
+    <p>This test passes if it does not crash.</p>
+    <script>
+    if (window.testRunner) {
+        testRunner.waitUntilDone();
+        testRunner.dumpAsText();
+    }
+    </script>
+</body>
+</html>
diff --git a/Source/WebCore/platform/audio/MultiChannelResampler.cpp b/Source/WebCore/platform/audio/MultiChannelResampler.cpp
index 1dadc58c..13db6f26 100644
--- a/Source/WebCore/platform/audio/MultiChannelResampler.cpp
+++ b/Source/WebCore/platform/audio/MultiChannelResampler.cpp
@@ -41,18 +41,8 @@ namespace WebCore {
 MultiChannelResampler::MultiChannelResampler(double scaleFactor, unsigned numberOfChannels, unsigned requestFrames, Function<void(AudioBus*, size_t framesToProcess)>&& provideInput)
     : m_numberOfChannels(numberOfChannels)
     , m_provideInput(WTFMove(provideInput))
-    , m_multiChannelBus(AudioBus::create(numberOfChannels, requestFrames, false))
+    , m_multiChannelBus(AudioBus::create(numberOfChannels, requestFrames))
 {
-    // As an optimization, we will use the buffer passed to provideInputForChannel() as channel memory for the first channel so we
-    // only need to allocate memory if there is more than one channel.
-    if (numberOfChannels > 1) {
-        m_channelsMemory.reserveInitialCapacity(numberOfChannels - 1);
-        for (unsigned channelIndex = 1; channelIndex < numberOfChannels; ++channelIndex) {
-            m_channelsMemory.uncheckedAppend(makeUnique<AudioFloatArray>(requestFrames));
-            m_multiChannelBus->setChannelMemory(channelIndex, m_channelsMemory.last()->data(), requestFrames);
-        }
-    }
-
     // Create each channel's resampler.
     for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex)
         m_kernels.append(makeUnique<SincResampler>(scaleFactor, requestFrames, std::bind(&MultiChannelResampler::provideInputForChannel, this, std::placeholders::_1, std::placeholders::_2, channelIndex)));
@@ -89,15 +79,10 @@ void MultiChannelResampler::process(AudioBus* destination, size_t framesToProces
 void MultiChannelResampler::provideInputForChannel(float* buffer, size_t framesToProcess, unsigned channelIndex)
 {
     ASSERT(channelIndex < m_multiChannelBus->numberOfChannels());
-    ASSERT(framesToProcess == m_multiChannelBus->length());
+    ASSERT(framesToProcess <= m_multiChannelBus->length());
 
-    if (!channelIndex) {
-        // As an optimization, we use the provided buffer as memory for the first channel in the AudioBus. This avoids
-        // having to memcpy() for the first channel.
-        m_multiChannelBus->setChannelMemory(0, buffer, framesToProcess);
+    if (!channelIndex)
         m_provideInput(m_multiChannelBus.get(), framesToProcess);
-        return;
-    }
 
     // Copy the channel data from what we received from m_multiChannelProvider.
     memcpy(buffer, m_multiChannelBus->channel(channelIndex)->data(), sizeof(float) * framesToProcess);
diff --git a/Source/WebCore/platform/audio/MultiChannelResampler.h b/Source/WebCore/platform/audio/MultiChannelResampler.h
index e96cc56b..274fe364 100644
--- a/Source/WebCore/platform/audio/MultiChannelResampler.h
+++ b/Source/WebCore/platform/audio/MultiChannelResampler.h
@@ -29,7 +29,6 @@
 #ifndef MultiChannelResampler_h
 #define MultiChannelResampler_h
 
-#include "AudioArray.h"
 #include <memory>
 #include <wtf/Function.h>
 #include <wtf/Vector.h>
@@ -62,7 +61,6 @@ private:
     size_t m_outputFramesReady { 0 };
     Function<void(AudioBus*, size_t framesToProcess)> m_provideInput;
     RefPtr<AudioBus> m_multiChannelBus;
-    Vector<std::unique_ptr<AudioFloatArray>> m_channelsMemory;
 };
 
 } // namespace WebCore
-- 
2.35.7

