diff options
author | Hongchan Choi <hongchan@chromium.org> | 2021-02-25 20:35:15 +0000 |
---|---|---|
committer | Michael BrĂ¼ning <michael.bruning@qt.io> | 2021-03-29 08:11:35 +0000 |
commit | e7f04e4918852ccc74dca2991bc1684ae5948481 (patch) | |
tree | a5f41f64af01bfb5702cdd1b9614bfee2b75906a | |
parent | c6a229dccba124d5403b8a17cab10f7975d7e60f (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.cc | 89 | ||||
-rw-r--r-- | chromium/third_party/blink/renderer/modules/webaudio/script_processor_node.h | 2 |
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 |