CVE-2024-43091 AI-generated analysis
platform/external/skia, src/effects/SkEmbossMaskFilter.cpp (emboss mask filter, 3D mask allocation)
In SkEmbossMaskFilter::filterMask the 3-plane 3D mask buffer is now sized with dst->computeTotalImageSize() (0 means too big, so the function aborts) instead of multiplying the single-plane size by 3 without an overflow check.
Root cause
After blurring the source A8 mask, SkEmbossMaskFilter::filterMask sets dst->fFormat = SkMask::k3D_Format and allocates a larger buffer for 'the other two channels'. The old code took planeSize = dst->computeImageSize() (single-plane size, 0 meaning too big), checked only that planeSize != 0, and then called SkMask::AllocImage(planeSize * 3). Nothing checked the multiplication by 3 for overflow. For a large enough mask, planeSize could be valid while planeSize * 3 wrapped, so the allocation would be smaller than the three-plane 3D mask that the rest of the function works on.
How the fix works
- src/effects/SkEmbossMaskFilter.cpp:SkEmbossMaskFilter::filterMask: computes size_t totalSize = dst->computeTotalImageSize() first. dst->fFormat has already been set to k3D_Format, so the total is intended to cover all planes. If totalSize is 0, the function returns false ("too big to allocate, abort").
- Only after that check does it compute planeSize = dst->computeImageSize(), used for the memcpy of the existing alpha plane. An added SkASSERT(planeSize != 0) documents that a non-overflowing total implies a non-overflowing plane size.
- The allocation becomes SkMask::AllocImage(totalSize) (SkMaskBuilder::AllocImage(totalSize) on Android 15). The buffer size now comes from the checked total instead of an unchecked planeSize * 3.
Completeness
- The fix covers the single allocation site in SkEmbossMaskFilter::filterMask that creates the 3D mask. The overflow check now covers the full multi-plane size.
- The later memcpy(dst->fImage, alphaPlane, planeSize) and memcpy(dst->fImage, src.fImage, src.computeImageSize()) are unchanged. They copy one plane each into the checked buffer.
- No other allocation paths are touched. The diff and context show no other site with a similar unchecked multiplication.
- The commit notes 'Test: N/A -- unclear if even reachable', so no regression test comes with the change.
Behavior changes
- filterMask now returns false (filter aborted) when computeTotalImageSize() reports the total size as too big (returns 0). Before, it would have continued with a possibly wrapped allocation size. For normal sizes the allocation is expected to be equivalent, but the material does not show the implementation of computeTotalImageSize().
- A debug-only SkASSERT(planeSize != 0) is added.
Per major
- Android 14: adapted fix: commit 0b628a960e74 in android-security-14.0.0_r14, a RESTRICT AUTOMERGE cherry-pick changed for the pre-SkMaskBuilder API (SkMask* dst, dst->fImage, SkMask::AllocImage/FreeImage). At android-security-14.0.0_r29, 4/7 lines of the patched region are present. The code context at r29 (lines 104-115) shows the fixed allocation.
- Android 15: fixed by commit b8081964ce86 in android-security-15.0.0_r2, in the SkMaskBuilder form (SkMaskBuilder* dst, dst->image(), SkMaskBuilder::AllocImage(totalSize)). At android-security-15.0.0_r17, 4/7 lines of the patched region are present.
- Android 16: not listed by the bulletin (not affected per the bulletin). At android-security-16.0.0_r8 only 1/7 lines of the patched region are present. The material does not show the current form of this code.
- Android 17: not listed by the bulletin (not affected per the bulletin). At android-security-17.0.0_r1 only 1/7 lines of the patched region are present. The material does not show the current form of this code.
Unknowns
- Whether the overflowing size is reachable from an untrusted caller on a real device (the commit says 'unclear if even reachable'). The material does not show the mask dimension limits applied before filterMask.
- The form of the code in Android 16/17 (only 1/7 lines of the patched region present) and whether it was moved, rewritten or removed.
- The implementation of SkMask::computeTotalImageSize() is not in the material. The analysis relies on the diff comment that 0 means too big.
- How SkEmbossMask::Emboss uses the three planes is not shown.
- The full native path from android.graphics.EmbossMaskFilter to SkEmbossMaskFilter (the index excerpt is truncated).