CVE-2024-0018 AI-generated analysis
platform/frameworks/av, libstagefright color conversion (media/libstagefright/colorconversion/ColorConverter.cpp)
Rewrites the main loop condition in ColorConverter::convertYUV420Planar16ToY410 from `x < src.cropWidth() - 3` to `x + 3 < src.cropWidth()`, so a crop width smaller than 3 no longer wraps the unsigned loop bound and lets the loop run past the source and destination buffers.
Root cause
The non-NEON implementation of ColorConverter::convertYUV420Planar16ToY410 has a per-row loop that processes 4 pixels at a time. That loop was bounded by `x < src.cropWidth() - 3`, with x a size_t. If the crop width is below 3, the subtraction gives a huge unsigned bound, so the loop condition stays true. The loop then keeps reading 32-bit words from ptr_u, ptr_v, ptr_ytop and ptr_ybot and writing 32-bit words to dst_top and dst_bot past the bounds of the source and destination bitmaps. The commit message calls this an overflow for an "unsupported cropwidth".
How the fix works
- media/libstagefright/colorconversion/ColorConverter.cpp:ColorConverter::convertYUV420Planar16ToY410 (the `#if !USE_NEON_Y410` variant): the loop condition changes from `x < src.cropWidth() - 3` to `x + 3 < src.cropWidth()`. The subtraction that could wrap is replaced by an addition on the loop index. x starts at 0 and is always a multiple of 4, so `x + 3` cannot overflow. For cropWidth() < 4 the loop body is never entered.
- A comment is added explaining why `x + 3` is safe. The trailing code that handles the remaining pixels (at most 2, per the code comment) through `if (x < src.cropWidth())` is unchanged. For tiny widths it now receives x == 0.
Completeness
- The fix covers only the 4-pixels-per-iteration loop in the non-NEON ColorConverter::convertYUV420Planar16ToY410. It adds no higher-level validation of cropWidth(). Widths of 1 or 2 go to the existing tail path, and the code comment says that path assumes even alignment.
- The pointer arithmetic for src_u/src_v and the row loop (`y += 2` over cropHeight()) are untouched. The diff does not show whether odd heights or other small-dimension cases are validated elsewhere.
- The material does not show the USE_NEON_Y410 variant of this function, so we cannot see whether it has an equivalent bound.
- A structurally identical loop (`for (; x < width - 3; x += 4)`) exists in frameworks/av/media/codec2/components/base/SimpleC2Component.cpp convertYUV420Planar16ToY410 (per index search). This commit does not touch it (see potential_variants).
Behavior changes
- For crop widths below 4, the 4-pixel loop no longer runs and only the tail path does. For widths of 3 or more, the two conditions are equivalent, so iteration is unchanged. No new error codes or API changes.
Per major
- Android 14: Same fix: commit a424120a625c in android-security-14.0.0_r4 (cherry-pick of the internal change, Merged-In I8631426188af3c5f9b6c1ff6a0039254c252f733). At android-security-14.0.0_r29, 3 of 4 lines of the patched region are present, including the new loop condition and comment.
- Android 15: Not affected per the bulletin. At android-security-15.0.0_r17, 3 of 4 lines of the patched region are present.
- Android 16: Not affected per the bulletin. At android-security-16.0.0_r8, 3 of 4 lines of the patched region are present.
- Android 17: Not affected per the bulletin. At android-security-17.0.0_r1, 3 of 4 lines of the patched region are present.
Unknowns
- Which caller or input path can produce a crop width smaller than 3 that reaches this function (the material shows no direct caller of the ColorConverter method).
- Whether the USE_NEON_Y410 build variant of the function has the same loop bound.
- Which line of the patched region is missing in the latest tags (3 of 4 lines present).
- Whether the SimpleC2Component.cpp copy of the loop was fixed in a separate change not included in this material.