Skip to content

Commit a84e05c

Browse files
Raymond Toymibrunin
authored andcommitted
[Backport] CVE-2021-21160: Heap buffer overflow in WebAudio
Manual cherry-pick of patch originally reviewed on https://chromium-review.googlesource.com/c/chromium/src/+/2727697: Convert AudioParam NaN values to the default value If any output value of an AudioParam (including the intrinsic values and any inputs to the AudioParam), should be NaN, replace the NaN value with the associated defaultValue. This causes some slowdowns so SIMD/NEON code was added to mitigate the degradation. There is still some slowdown, but the worst case is now about 7% slower on x86 and 10% on arm. Generally, the slowdown is less than 2% and 5%, respectively. (Perversely, some results got faster, and the differences are statistically significant.) Full details can be found at https://docs.google.com/spreadsheets/d/1EhbLHm-9cUoEO5aj1vYemVBLQ3Dh4dCJPPLTfZPrZt4/edit?usp=sharing Manually tested the test case from the bug and the issue no longer occurs. (cherry picked from commit ab1862017b5717271a28376659944dddc602195c) (cherry picked from commit eb0c0353bf245885797d8ce0d1b864d88a381fbb) Bug: 1170531 Change-Id: I00d902b40a9ef9da990c6d68b664b1dcfc31b091 Commit-Queue: Raymond Toy <[email protected]> Reviewed-by: Hongchan Choi <[email protected]> Cr-Original-Original-Commit-Position: refs/heads/master@{#851733} Reviewed-by: Raymond Toy <[email protected]> Cr-Original-Commit-Position: refs/branch-heads/4389@{#880} Cr-Original-Branched-From: 9251c5db2b6d5a59fe4eac7aafa5fed37c139bb7-refs/heads/master@{#843830} Reviewed-by: Victor-Gabriel Savu <[email protected]> Commit-Queue: Artem Sumaneev <[email protected]> Cr-Commit-Position: refs/branch-heads/4240@{#1551} Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218} Reviewed-by: Allan Sandfeld Jensen <[email protected]> Reviewed-by: Jüri Valdmann <[email protected]>
1 parent 1375de9 commit a84e05c

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

chromium/third_party/blink/renderer/modules/webaudio/audio_param.cc

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@
2525

2626
#include "third_party/blink/renderer/modules/webaudio/audio_param.h"
2727

28+
#include "build/build_config.h"
2829
#include "third_party/blink/renderer/core/inspector/console_message.h"
2930
#include "third_party/blink/renderer/modules/webaudio/audio_node.h"
3031
#include "third_party/blink/renderer/modules/webaudio/audio_node_output.h"
3132
#include "third_party/blink/renderer/platform/audio/audio_utilities.h"
33+
#include "third_party/blink/renderer/platform/audio/vector_math.h"
3234
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
3335
#include "third_party/blink/renderer/platform/histogram.h"
3436
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
@@ -227,6 +229,48 @@ void AudioParamHandler::CalculateSampleAccurateValues(
227229
CalculateFinalValues(values, number_of_values, IsAudioRate());
228230
}
229231

232+
// Replace NaN values in |values| with |default_value|.
233+
static void HandleNaNValues(float* values,
234+
unsigned number_of_values,
235+
float default_value) {
236+
unsigned k = 0;
237+
#if defined(ARCH_CPU_X86_FAMILY)
238+
if (number_of_values >= 4) {
239+
__m128 defaults = _mm_set1_ps(default_value);
240+
for (k = 0; k < number_of_values; k += 4) {
241+
__m128 v = _mm_loadu_ps(values + k);
242+
// cmpuord returns all 1's if v is NaN for each elmeent of v.
243+
__m128 isnan = _mm_cmpunord_ps(v, v);
244+
// Replace NaN parts with default.
245+
__m128 result = _mm_and_ps(isnan, defaults);
246+
// Merge in the parts that aren't NaN
247+
result = _mm_or_ps(_mm_andnot_ps(isnan, v), result);
248+
_mm_storeu_ps(values + k, result);
249+
}
250+
}
251+
#elif defined(CPU_ARM_NEON)
252+
if (number_of_values >= 4) {
253+
uint32x4_t defaults = vreinterpretq_u32_f32(vdupq_n_f32(default_value));
254+
for (k = 0; k < number_of_values; k += 4) {
255+
float32x4_t v = vld1q_f32(values + k);
256+
// Returns true (all ones) if v is not NaN
257+
uint32x4_t is_not_nan = vceqq_f32(v, v);
258+
// Get the parts that are not NaN
259+
uint32x4_t result = vandq_u32(is_not_nan, vreinterpretq_u32_f32(v));
260+
// Replace the parts that are NaN with the default and merge with previous
261+
// result. (Note: vbic_u32(x, y) = x and not y)
262+
result = vorrq_u32(result, vbicq_u32(defaults, is_not_nan));
263+
vst1q_f32(values + k, vreinterpretq_f32_u32(result));
264+
}
265+
}
266+
#endif
267+
for (; k < number_of_values; ++k) {
268+
if (std::isnan(values[k])) {
269+
values[k] = default_value;
270+
}
271+
}
272+
}
273+
230274
void AudioParamHandler::CalculateFinalValues(float* values,
231275
unsigned number_of_values,
232276
bool sample_accurate) {
@@ -276,6 +320,25 @@ void AudioParamHandler::CalculateFinalValues(float* values,
276320
// Sum, with unity-gain.
277321
summing_bus->SumFrom(*connection_bus);
278322
}
323+
324+
float min_value = MinValue();
325+
float max_value = MaxValue();
326+
327+
if (NumberOfRenderingConnections() > 0) {
328+
// AudioParams by themselves don't produce NaN because of the finite min
329+
// and max values. But an input to an AudioParam could have NaNs.
330+
//
331+
// NaN values in AudioParams must be replaced by the AudioParam's
332+
// defaultValue. Then these values must be clamped to lie in the nominal
333+
// range between the AudioParam's minValue and maxValue.
334+
//
335+
// See https://webaudio.github.io/web-audio-api/#computation-of-value.
336+
HandleNaNValues(values, number_of_values, DefaultValue());
337+
}
338+
339+
VectorMath::Vclip(values, 1, &min_value, &max_value, values, 1,
340+
number_of_values);
341+
279342
}
280343

281344
void AudioParamHandler::CalculateTimelineValues(float* values,

0 commit comments

Comments
 (0)