CVE-2026-0049 AI-generated analysis
platform/external/dng_sdk (dng_misc_opcodes.cpp, MapTable opcode) and platform/frameworks/base (com.android.internal.widget.LocalImageResolver, MessagingStyle/ConversationStyle image loading)
Two-part fix: external/dng_sdk rewrites the plane loop in dng_opcode_MapTable::ProcessArea so the bound no longer computes fAreaSpec.Plane() + fAreaSpec.Planes() (which can wrap in uint32) and marks dng_area_spec::ScaledOverlap no-sanitize for unsigned-integer-overflow; frameworks/base adds a MIME-type allowlist to LocalImageResolver so images in non-allowlisted formats (including DNG) are rejected.
Root cause
In source/dng_misc_opcodes.cpp, dng_opcode_MapTable::ProcessArea iterated planes with the condition `plane < fAreaSpec.Plane () + fAreaSpec.Planes ()`, a uint32 addition of area-spec values that can wrap. The commit title ("Handle underflows") and the added DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow") on dng_area_spec::ScaledOverlap indicate unsigned arithmetic in these functions wraps on crafted input; the bulletin classifies the issue as DoS. On the frameworks/base side, LocalImageResolver previously did not restrict which codec/MIME type was decoded, so DNG input reached the decoder.
How the fix works
- external/dng_sdk source/dng_misc_opcodes.cpp : dng_opcode_MapTable::ProcessArea: the loop now caches planeStart = fAreaSpec.Plane(), planeCount = fAreaSpec.Planes(), bufferPlanes = buffer.Planes() and uses `plane < bufferPlanes && plane - planeStart < planeCount`. Since plane starts at planeStart and only increments, the subtraction does not wrap and no overflowing addition is performed; the plane index stays below buffer.Planes() before DirtyPixel_uint16 / DoMapArea16 are called.
- external/dng_sdk source/dng_misc_opcodes.cpp : dng_area_spec::ScaledOverlap: annotated with DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow"). This does not change the arithmetic; it only exempts the function from the unsigned overflow sanitizer (the function body is not in the material).
- frameworks/base core/java/com/android/internal/widget/LocalImageResolver.java : the method taking (ImageInfo info, int maxWidth, int maxHeight) now reads info.getMimeType(), lowercases it with Locale.US, and accepts only image/png, image/jpeg, image/webp, image/gif, image/bmp, image/x-ico, image/vnd.wap.wbmp, image/heif, image/heic, image/avif. Any other or null MIME type throws RuntimeException("Image mime type (...) is not allowed.") before the existing DEFAULT_DECODE_HARD_LIMIT_PX size check, aborting decoding of non-allowlisted images at that point.
- frameworks/base core/tests/coretests: adds the sample image res/raw/dng_opcode_MapTable_ProcessArea.png and LocalImageResolverTest.resolveImage_asset_invalidMimeType expecting IOException from resolveImage(uri, context). The android-security-14.0.0_r29 tree additionally contains resolveImage_asset_invalidMimeType_withSize expecting RuntimeException from resolveImage(uri, context, 480, 480), which is not part of this diff.
Completeness
- In dng_sdk only the plane loop of dng_opcode_MapTable::ProcessArea is corrected arithmetically. dng_area_spec::ScaledOverlap is only exempted from the sanitizer, so any wrap in its arithmetic still occurs silently; the material does not show its body or whether the result is subsequently range-checked.
- The material does not show other opcode classes in dng_sdk, so whether sibling opcodes use the same Plane()+Planes() bound cannot be judged.
- The LocalImageResolver allowlist only covers images decoded through that class. Other code paths that decode DNG via ImageDecoder/BitmapFactory are not gated by this commit and rely on the dng_sdk change.
Behavior changes
- LocalImageResolver now rejects any image whose MIME type is not in the ten-entry allowlist (including DNG, and null MIME type). Per the tests present at android-security-14.0.0_r29, the rejection surfaces as IOException from resolveImage(Uri, Context) and as RuntimeException from resolveImage(Uri, Context, int, int). Images in other formats will fail to load through this class.
- MIME comparison is case-insensitive (Locale.US lowercasing).
- In dng_sdk, the MapTable plane loop bound no longer uses the wrapping Plane()+Planes() addition; ScaledOverlap is excluded from unsigned-integer-overflow sanitizer instrumentation.
Per major
- Android 14: same fix: both commits landed in android-security-14.0.0_r26 (external/dng_sdk d19069e8178f and frameworks/base d98c9421fff9); at android-security-14.0.0_r29 the patched region is present (8/8 lines).
- Android 15: same fix: external/dng_sdk b8207c04aeeb in android-security-15.0.0_r14 with the identical dng_misc_opcodes.cpp diff; patched region present at android-security-15.0.0_r17 (8/8 lines). The frameworks/base commit for 15 is not shown in the material.
- Android 16: same fix: external/dng_sdk 80a267ed1ac7 in android-security-16.0.0_r5 with the identical diff; patched region present at android-security-16.0.0_r8 (8/8 lines). The frameworks/base commit for 16 is not shown in the material.
- Android 17: not affected per the bulletin; android-security-17.0.0_r1 contains the patched region (8/8 lines).
Unknowns
- The body of dng_area_spec::ScaledOverlap and which arithmetic in it overflows; whether a wrapped result is used unchecked.
- The exact failure mode before the fix (for example a sanitizer abort versus out-of-range access), whether dng_sdk is built with the integer overflow sanitizer, and the process in which the crash occurs.
- Whether other opcode classes in dng_sdk use the same Plane()+Planes() loop bound.
- How both resolveImage overloads route through the allowlisted method, and which commit added the sized-variant test.
- The frameworks/base cherry-picks for Android 15 and 16 (only the dng_sdk commits are shown for those branches).