summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHongchan Choi <hongchan@chromium.org>2021-02-25 20:35:15 +0000
committerMichael BrĂ¼ning <michael.bruning@qt.io>2021-03-29 08:11:35 +0000
commite7f04e4918852ccc74dca2991bc1684ae5948481 (patch)
treea5f41f64af01bfb5702cdd1b9614bfee2b75906a
parentc6a229dccba124d5403b8a17cab10f7975d7e60f (diff)
[Backport] CVE-2021-21166: Object lifecycle issue in audio
Cherry-pick of patch originally reviewed on https://chromium-review.googlesource.com/c/chromium/src/+/2718543: Introduce AudioBuffers for user access in ScriptProcessorNode This CL adds new AudioBuffers for the access from the user code. Bug: 1177465 Test: The local ASAN build doesn't reproduce on given POCs. Change-Id: Id9a3505ddb9ab61b4442385d0b830ef56f65f797 Auto-Submit: Hongchan Choi <hongchan@chromium.org> Reviewed-by: Raymond Toy <rtoy@chromium.org> Commit-Queue: Hongchan Choi <hongchan@chromium.org> Cr-Commit-Position: refs/heads/master@{#857817} Reviewed-by: Kirill Burtsev <kirill.burtsev@qt.io>
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc89
-rw-r--r--chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h2
2 files changed, 87 insertions, 4 deletions
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
index 6e80b23a32d..d46e17440a9 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
+++ b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
@@ -42,6 +42,28 @@
namespace blink {
+namespace {
+
+bool IsAudioBufferDetached(AudioBuffer* buffer) {
+ bool is_buffer_detached = false;
+ for (unsigned channel = 0; channel < buffer->numberOfChannels(); ++channel) {
+ if (buffer->getChannelData(channel)->buffer()->IsDetached()) {
+ is_buffer_detached = true;
+ break;
+ }
+ }
+
+ return is_buffer_detached;
+}
+
+bool BufferTopologyMatches(AudioBuffer* buffer_1, AudioBuffer* buffer_2) {
+ return (buffer_1->numberOfChannels() == buffer_2->numberOfChannels()) &&
+ (buffer_1->length() == buffer_2->length()) &&
+ (buffer_1->sampleRate() == buffer_2->sampleRate());
+}
+
+} // namespace
+
ScriptProcessorHandler::ScriptProcessorHandler(
AudioNode& node,
float sample_rate,
@@ -335,6 +357,12 @@ ScriptProcessorNode::ScriptProcessorNode(BaseAudioContext& context,
input_buffers_.push_back(input_buffer);
output_buffers_.push_back(output_buffer);
}
+
+ external_input_buffer_ = AudioBuffer::Create(
+ number_of_input_channels, buffer_size, sample_rate);
+ external_output_buffer_ = AudioBuffer::Create(
+ number_of_output_channels, buffer_size, sample_rate);
+
SetHandler(ScriptProcessorHandler::Create(
*this, sample_rate, buffer_size, number_of_input_channels,
number_of_output_channels, input_buffers_, output_buffers_));
@@ -476,11 +504,62 @@ uint32_t ScriptProcessorNode::bufferSize() const {
void ScriptProcessorNode::DispatchEvent(double playback_time,
uint32_t double_buffer_index) {
- AudioBuffer* input_buffer = input_buffers_.at(double_buffer_index).Get();
- AudioBuffer* output_buffer = output_buffers_.at(double_buffer_index).Get();
- DCHECK(output_buffer);
+ DCHECK(IsMainThread());
+
+ AudioBuffer* backing_input_buffer =
+ input_buffers_.at(double_buffer_index).Get();
+
+ // The backing buffer can be nullptr, when the number of input channels is 0.
+ if (backing_input_buffer) {
+ // Also the author code might have transferred |external_input_buffer| to
+ // other threads or replaced it with a different AudioBuffer object. Then
+ // re-create a new buffer instance.
+ if (IsAudioBufferDetached(external_input_buffer_) ||
+ !BufferTopologyMatches(backing_input_buffer,
+ external_input_buffer_)) {
+ external_input_buffer_ = AudioBuffer::Create(
+ backing_input_buffer->numberOfChannels(),
+ backing_input_buffer->length(),
+ backing_input_buffer->sampleRate());
+ }
+
+ for (unsigned channel = 0;
+ channel < backing_input_buffer->numberOfChannels(); ++channel) {
+ const float* source = static_cast<float*>(
+ backing_input_buffer->getChannelData(channel)->buffer()->Data());
+ float* destination = static_cast<float*>(
+ external_input_buffer_->getChannelData(channel)->buffer()->Data());
+ memcpy(destination, source,
+ backing_input_buffer->length() * sizeof(float));
+ }
+ }
+
AudioNode::DispatchEvent(*AudioProcessingEvent::Create(
- input_buffer, output_buffer, playback_time));
+ external_input_buffer_, external_output_buffer_, playback_time));
+
+ AudioBuffer* backing_output_buffer =
+ output_buffers_.at(double_buffer_index).Get();
+
+ if (backing_output_buffer) {
+ if (IsAudioBufferDetached(external_output_buffer_) ||
+ !BufferTopologyMatches(backing_output_buffer,
+ external_output_buffer_)) {
+ external_output_buffer_ = AudioBuffer::Create(
+ backing_output_buffer->numberOfChannels(),
+ backing_output_buffer->length(),
+ backing_output_buffer->sampleRate());
+ }
+
+ for (unsigned channel = 0;
+ channel < backing_output_buffer->numberOfChannels(); ++channel) {
+ const float* source = static_cast<float*>(
+ external_output_buffer_->getChannelData(channel)->buffer()->Data());
+ float* destination = static_cast<float*>(
+ backing_output_buffer->getChannelData(channel)->buffer()->Data());
+ memcpy(destination, source,
+ backing_output_buffer->length() * sizeof(float));
+ }
+ }
}
bool ScriptProcessorNode::HasPendingActivity() const {
@@ -499,6 +578,8 @@ bool ScriptProcessorNode::HasPendingActivity() const {
void ScriptProcessorNode::Trace(Visitor* visitor) const {
visitor->Trace(input_buffers_);
visitor->Trace(output_buffers_);
+ visitor->Trace(external_input_buffer_);
+ visitor->Trace(external_output_buffer_);
AudioNode::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h
index b166a044e76..9ae1789ab65 100644
--- a/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h
+++ b/chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h
@@ -168,6 +168,8 @@ class ScriptProcessorNode final
private:
HeapVector<Member<AudioBuffer>> input_buffers_;
HeapVector<Member<AudioBuffer>> output_buffers_;
+ Member<AudioBuffer> external_input_buffer_;
+ Member<AudioBuffer> external_output_buffer_;
};
} // namespace blink