CVE-2024-23709 AI-generated analysis
platform/external/sonivox, arm-wt-22k wavetable synth engine (eas_wtsynth.c, eas_wtengine.c)
Clamps the per-frame sample count in the sonivox wavetable synthesizer to BUFFER_SIZE_IN_MONO_SAMPLES, both where it is computed (WT_CheckSampleEnd in eas_wtsynth.c) and in each engine routine that uses it (eas_wtengine.c), so the gain, interpolation and filter loops cannot run past the frame audio and mix buffers.
Root cause
When a voice is about to reach loopEnd, WT_CheckSampleEnd in arm-wt-22k/lib_src/eas_wtsynth.c computes pWTIntFrame->numSamples as 1 + (numSamples / phaseIncrement), or uses the raw value when phaseIncrement is 0. It rejected only a negative result (the existing b/26366256 check) and had no upper bound. The engine routines in eas_wtengine.c (WT_VoiceGain, WT_Interpolate, WT_InterpolateNoLoop, WT_VoiceFilter, WT_InterpolateMono) copy pWTIntFrame->numSamples into a local count and also check only for <= 0 before processing pWTIntFrame->pAudioBuffer and/or pMixBuffer. WT_VoiceGain, for example, loops while(numSamples--) over both buffers. A count larger than the frame buffer size (BUFFER_SIZE_IN_MONO_SAMPLES) can therefore drive accesses past those buffers.
How the fix works
- arm-wt-22k/lib_src/eas_wtsynth.c:WT_CheckSampleEnd: the sample-count formula changes from 1 + (numSamples / phaseIncrement) to a ceiling division, (numSamples + phaseIncrement - 1) / phaseIncrement. The old value is still computed, and ALOGE('b/317780080 old %ld new %ld') is logged when the two differ.
- arm-wt-22k/lib_src/eas_wtsynth.c:WT_CheckSampleEnd: after the existing < 0 check, a new else-if clips pWTIntFrame->numSamples to BUFFER_SIZE_IN_MONO_SAMPLES and logs ALOGE and android_errorWriteLog(0x534e4554, "317780080"). Because the clamp comes after both assignments, it also covers the phaseIncrement == 0 branch.
- arm-wt-22k/lib_src/eas_wtengine.c: the same clip (if numSamples > BUFFER_SIZE_IN_MONO_SAMPLES, set numSamples = BUFFER_SIZE_IN_MONO_SAMPLES, with ALOGE and android_errorWriteLog) is added as an else-if to the existing <= 0 check at six sites: WT_VoiceGain, WT_Interpolate, WT_InterpolateNoLoop, two sites whose hunk headers name WT_VoiceFilter (around lines 409 and 481), and WT_InterpolateMono. Only the local numSamples copy is clipped. pWTIntFrame->numSamples is not changed there.
Completeness
- Defense in depth: the code that computes the count (WT_CheckSampleEnd) and all six engine sites in the diff that already had the b/26366256 <= 0 check are now bounded by BUFFER_SIZE_IN_MONO_SAMPLES.
- The clamp assumes pAudioBuffer and pMixBuffer each hold at least BUFFER_SIZE_IN_MONO_SAMPLES entries. The buffer allocations are not in the material, so the diff cannot confirm this.
- The material does not show any other user of pWTIntFrame->numSamples outside the six patched engine sites (for example alternative or conditionally compiled engine paths), and this commit does not touch any.
- For a positive remaining distance, the formula change (ceiling instead of 1 + floor) lowers the count by one when the distance divides evenly by phaseIncrement. The clamp, not the formula change, is what enforces the bound.
Behavior changes
- New ALOGE log lines tagged b/317780080 and android_errorWriteLog(0x534e4554, "317780080") events whenever a sample count is clipped.
- A sample count above the limit is clipped to BUFFER_SIZE_IN_MONO_SAMPLES (and logged) instead of overrunning, so that frame renders fewer samples than computed.
- WT_CheckSampleEnd yields one fewer sample than before when the remaining phase distance divides evenly by phaseIncrement. It logs an ALOGE whenever the new and old formulas differ, whether or not clipping happens.
Per major
- Android 14: same fix: commit 0205dff2273f in android-security-14.0.0_r8 (cherry-picked from main, Change-Id I3609d6a36d89b26ae7eb3ae84cbe7772f6c3bee0). At android-security-14.0.0_r29 the full patched region (8/8 lines) is present.
- Android 15: not affected (not listed by the bulletin); the patched region (8/8 lines) is present at android-security-15.0.0_r17.
- Android 16: not affected (not listed by the bulletin); the patched region (8/8 lines) is present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin); the patched region (8/8 lines) is present at android-security-17.0.0_r1.
Unknowns
- The sizes of pWTIntFrame->pAudioBuffer and pWTIntFrame->pMixBuffer relative to BUFFER_SIZE_IN_MONO_SAMPLES are not shown.
- Which function actually contains the second WT_VoiceFilter-labelled hunk in eas_wtengine.c (around line 481) is not shown. Its header names WT_VoiceFilter, but the body references phaseIncrement.
- How input data (MIDI/DLS) drives loopEnd or phaseIncrement to produce an oversized count. The material only references a POC in bug 317780080.
- Whether other engine paths that use pWTIntFrame->numSamples exist beyond the six patched sites.
- The loop bodies of the engine routines other than WT_VoiceGain are not shown.