CVE-2026-58815 AI-generated analysis
platform/frameworks/av, services/camera/libcameraservice/device3 (cameraserver metadata mappers)
Changes the per-region loop bound in the camera metering-region mappers (DistortionMapper, RotateAndCropMapper, ZoomRatioMapper) from `j < entry.count` to `j + 5 <= entry.count`. A 5-int32 region tuple is now processed only when all five elements lie inside the metadata entry, which prevents heap out-of-bounds read and write when the region array length is not a multiple of 5.
Root cause
The metering-region tags in kMeteringRegionsToCorrect (e.g. ANDROID_CONTROL_AE_REGIONS) are processed as 5-element int32 tuples, with the weight at offset 4. Six loops iterated with `for (j = 0; j < entry.count; j += 5)`, read `entry.data.i32[j + 4]` (the weight), and passed `entry.data.i32 + j` to an in-place coordinate transform. The loops are in DistortionMapper::correctCaptureRequest / correctCaptureResult, RotateAndCropMapper::updateCaptureRequest / updateCaptureResult and ZoomRatioMapper::separateZoomFromCropLocked / combineZoomAndCropLocked. The transforms are mapCorrectedToRaw, transformPoints plus swapRectToMinFirst, and the zoom region scaling. The loop condition only checked that the first element of the tuple was in range. When entry.count is not a multiple of 5 (the new tests use count 6), the last iteration starts at j = 5 with one element left. The weight read at index 9 and any coordinate access at indices 6..8 then go past the end of the metadata entry buffer. Per the commit message, this is triggered by a CaptureRequest containing such a metering region.
How the fix works
- services/camera/libcameraservice/device3/DistortionMapper.cpp: in correctCaptureRequest and correctCaptureResult, the kMeteringRegionsToCorrect loop condition becomes `j + 5 <= e.count`. The weight read at e.data.i32[j + 4] and the in-place mapCorrectedToRaw(e.data.i32 + j, 2, ...) now happen only for complete 5-element tuples.
- services/camera/libcameraservice/device3/RotateAndCropMapper.cpp: in updateCaptureRequest and updateCaptureResult, the loop condition becomes `i + 5 <= entry.count`. This is checked before entry.data.i32[i + 4] is read and before transformPoints / swapRectToMinFirst operate on entry.data.i32 + i.
- services/camera/libcameraservice/device3/ZoomRatioMapper.cpp: in separateZoomFromCropLocked and combineZoomAndCropLocked, the loop condition becomes `j + 5 <= entry.count` before the weight read and the region scaling.
- Tests (MeteringRegionsBoundsTest) are added in tests/DistortionMapperTest.cpp, tests/RotateAndCropMapperTest.cpp and tests/ZoomRatioTest.cpp. Each test first writes a 10-element AE region array as poison, then overwrites the tag with a 6-element array {.., 50, 999} and runs the request mapper. It asserts that the count stays 6 and element [5] is still 999.
Completeness
- The six kMeteringRegionsToCorrect loops shown in the three mappers are all fixed, covering both the request and result directions.
- The fix does not check that entry.count is a multiple of 5 and does not return an error. A trailing partial tuple is silently left untransformed by the mappers.
- The kRectsToCorrect loop in DistortionMapper::correctCaptureRequest uses `e.count / 4` as the rect count, which already truncates to whole rects. This fix does not change it.
- The commit message names a fourth location, `correctMeteringRegions`, but no function by that name appears in the diff or the provided code context.
Behavior changes
- Metering-region arrays whose length is not a multiple of 5 now have their trailing incomplete tuple skipped by the mappers instead of being processed with out-of-bounds accesses. No new error code is introduced, and the mapper return values are unchanged.
- For well-formed arrays (count a multiple of 5), behaviour is identical.
Per major
- Android 14: same fix: platform/frameworks/av 6654633902f8 in android-security-14.0.0_r29 (cherry-pick of cc78e7aa1be9). It has the six one-line condition changes plus the three tests. The resolver reports 7/8 lines of the patched region present at android-security-14.0.0_r30.
- Android 15: same fix: ff3f3a6b8194 in android-security-15.0.0_r17. Same hunks with small line offsets (DistortionMapper 145/184, RotateAndCropMapper 165/294, ZoomRatioMapper 352/390). 7/8 lines present at android-security-15.0.0_r18.
- Android 16: same fix: aff9120ec0b8 in android-security-16.0.0_r8. Same hunks (ZoomRatioMapper at 386/424). 7/8 lines present at android-security-16.0.0_r9.
- Android 17: same fix: 77f8ddbbd65b in android-security-17.0.0_r1, with the same blob indexes as the Android 16 diff. 7/8 lines present at android-security-17.0.0_r2.
Unknowns
- Where the `correctMeteringRegions` function named in the commit message is and what its status is. It is absent from the diff and the provided code context.
- Whether any length check on metering-region arrays exists upstream of the mappers (e.g. at request validation).
- Where the result-path metadata entries come from, and the exact call chain into ZoomRatioMapper's *Locked functions.
- What the resolver's '7/8 lines present' metric means relative to the six changed source lines.