CVE-2025-64893 AI-generated analysis
platform/external/dng_sdk (Adobe DNG SDK: DNG/TIFF parsing, JXL codec glue, opcode processing, fingerprinting)
The fix syncs platform/external/dng_sdk to Adobe DNG SDK 1.7.1 build 2410 (61 files, +2721/-694). Among many unrelated changes it adds a size cap on the new GainMapMetadata tag, rewrites the dng_opcode_GainMap::ProcessArea loop, adds new JXL chunked reader/writer classes with checked sizing, and encapsulates dng_fingerprint and dng_md5_printer. The material does not isolate which change closes the bulletin's information-disclosure bug.
Root cause
Not identifiable from the material. The commit message says only "Update to DNG SDK 1.7.1 2410" (Bug 465781139), and the diff is cut off inside dng_jxl.cpp (3031 more lines not shown). Pre-fix code that the update visibly replaces includes: dng_ifd::ParseTag had no handler, and so no size limit, for tcGainMapMetadata_ISO_21496_1; dng_opcode_GainMap::ProcessArea stepped rows by fAreaSpec.RowPitch() without clamping it to the overlap height; AddDigest routines hashed raw host memory through dng_md5_printer::Process; dng_fingerprint exposed its raw data[] array publicly. The material does not show which of these, or which of the unseen changes in other files, corresponds to the reported disclosure.
How the fix works
- source/dng_jxl.cpp: adds the new classes jxl_data_writer, jxl_data_writer2 and jxl_image_chunk_reader, plus jxl_buffer_chunk_reader (its body is cut off). jxl_image_chunk_reader::get_color_channel_data_at computes fRowStep and bytesNeeded with SafeUint32Mult (dng_safe_arithmetic.h is now included) before fHost.Allocate. jxl_data_writer2 caps requested buffer sizes at kMaxSize (1073741824 bytes) and only writes finalized ranges within that bound. The ReadChunk body appears as added lines, but the hunk is cut off, so the material does not show whether its checks are new.
- source/dng_ifd.cpp: dng_ifd::ParseTag adds a tcGainMapMetadata_ISO_21496_1 case. It requires ttUndefined, rejects tagCount > 4 MiB with ThrowBadFormat("Gain map metadata block too large"), then allocates exactly tagCount bytes and reads them with stream.Get into the new dng_ifd::fGainMapMetadata. dng_ifd::IsValidDNG now accepts sfPreviewGainMap alongside sfGainMap.
- source/dng_gain_map.cpp: dng_opcode_GainMap::ProcessArea now clamps rowPitch to overlap.H() and colPitch to overlap.W(). It precomputes rows and cols as ceiling divisions and loops by index (rowIdx/colIdx) with explicit row += rowPitch and col += colPitch. This replaces the row loop that stepped by the unclamped fAreaSpec.RowPitch().
- source/dng_fingerprint.h/.cpp: dng_fingerprint::data becomes private (friends: dng_md5_printer and dng_fingerprint_less_than), with an explicit copy constructor, operator= and Data()/MutableData() accessors. dng_md5_printer::Process(const void*, uint32) is renamed to the virtual ProcessPtr. New methods: Process(const dng_fingerprint&), Process(const dng_string&), Process_bool, Process_size. dng_md5_printer_stream now inherits dng_md5_printer publicly, and its ProcessPtr calls Flush() before hashing. New classes dng_md5_printer_le_stream and dng_md5_direct_printer are added. Visible call sites (dng_big_table.cpp, dng_bmff.cpp, dng_camera_profile.cpp, dng_exif.cpp, dng_hue_sat_map.cpp, dng_image_writer.cpp, dng_jpeg_image.cpp, dng_ifd.cpp) switch to Get/Put(fingerprint) and to Put_uint32/Put_real32/Put_real64/Put_swap4/Put_swap8 instead of hashing raw memory.
- source/dng_exceptions.h/.cpp, dng_errors.h, dng_flags.h: dng_exception now derives from std::exception and carries a message string (qDNGVerboseExceptions defaults to 1). DNG_NO_RETURN uses [[noreturn]]. Sanitizer detection macros and DNG_FALLTHROUGH are added. The SDK version constants are set to 1.7.1 / 2410.
- source/dng_abort_sniffer.cpp/.h: the dng_sniffer_task destructor moves out of line, becomes virtual, and wraps fSniffer->EndTask() in try/catch(...).
- The diff hunks for the remaining files in the stat (dng_stream.cpp, dng_misc_opcodes.cpp, dng_negative.cpp, dng_linearization_info.cpp, dng_pixel_buffer.cpp, dng_read_image.cpp, dng_resample.cpp, dng_shared.cpp, dng_string.cpp, dng_preview.cpp, dng_update_meta.cpp, dng_xmp*.cpp and others) are not shown and cannot be analysed.
Completeness
- The fix is a monolithic SDK sync, not a targeted patch. The material does not identify which code path produced the information disclosure, so coverage of the specific bug cannot be judged from the code.
- Visible hardening covers: the new GainMapMetadata tag (4 MiB cap, exact-size allocation), the GainMap opcode row/column loop (pitch clamped to the overlap), checked sizing in the new JXL chunk reader and writer, and digest computation (fields are serialized through the stream Put routines instead of hashed as raw struct memory).
- About 3031 lines of the diff are not shown (the rest of dng_jxl.cpp, plus dng_stream.cpp, dng_linearization_info.cpp, dng_misc_opcodes.cpp, dng_pixel_buffer.cpp, dng_negative.cpp, dng_read_image.cpp and others), so whatever checks they add or omit is unknown.
- The code context at android-security-14.0.0_r29 shows kDNGSDK_BuildVersion 2502 and a 2025 copyright in dng_stream.cpp, so the branch has since taken a further SDK update. Checks seen in that context (DNG_REQUIRE in dng_pixel_buffer::SetConstant and dng_linearize_plane::Process, the finite/zero checks in dng_resample_weights::Initialize) cannot be attributed to this commit.
Behavior changes
- A GainMapMetadata (ISO 21496-1) tag larger than 4 MiB is rejected with dng_error_bad_format. Before the update, ParseTag had no case for this tag.
- dng_exception derives from std::exception, and what() returns "dng_error: <code>[: message (sub_message)]" because qDNGVerboseExceptions defaults to 1. Throw_dng_error now passes message and sub_message into the exception.
- dng_ifd::IsValidDNG accepts NewSubFileType sfPreviewGainMap (33). dng_ifd::IsBaselineJPEG returns true for ccJPEG + piRGB with 3 or 4 samples per pixel.
- dng_info::ParseDNGPrivateData now parses RICOH-prefixed DNGPrivateData as a Pentax maker note IFD. The default of dng_info::fTIFFBlockOriginalOffset changes from kDNGStreamInvalidOffset to 0.
- dng_host::MakeJXLEncodeSettings uses settings attached to the host for the lossless use cases.
- dng_image_writer: WriteTIFF and WriteTIFFWithProfile gain a gainMapMetadataBlock parameter, inserted before useHalfFloat, followed by the gain map alternate ICC profile data and size. WriteDNG and WriteDNGWithMetadata gain the same three parameters, appended after gainMapLossyCompressed. A TIFF gain map is written only when both the image and the metadata block are supplied. Whether the PGTM tag is written from the negative now depends on whether the main profile actually wrote it.
- Digest inputs for masked RGB tables and hue/sat map interpolation are now serialized through stream Put routines. The material does not show whether the resulting values change on little-endian hosts.
- Source-incompatible API changes for dependents: dng_fingerprint::data is private (use Data()/MutableData()); dng_md5_printer::Process(ptr, len) is now ProcessPtr; the dng_md5_printer constructor is protected; the dng_sniffer_task destructor is virtual.
Per major
- Android 14: Same fix: commit d0bfe8eeee73 (Change-Id Ia850e7c3a3ab1b35dd619cc78159663df3b2b2c8, cherry-picked from internal commits 403d0a45 and defc6b20) in android-security-14.0.0_r25. At r29, 8/8 lines of the patched region are present, and the code context shows SDK build 2502.
- Android 15: Same fix: commit 45da10961287 (linked by Change-Id, same commit title and matching visible diff) in android-security-15.0.0_r13. 8/8 lines present at r17.
- Android 16: Same fix: commit 6b5cf2a88ebd (linked by Change-Id, matching visible diff) in android-security-16.0.0_r4. 8/8 lines present at r8.
- Android 17: Not affected per the bulletin. The patched region (8/8 lines) is present at android-security-17.0.0_r1.
Unknowns
- Which code path and input construct cause the information disclosure. The commit message gives no detail and the diff is a version bump.
- Whether the checks in dng_jxl_io_buffer::ReadChunk (EOF and buffer spill) are new in this commit or were already present. The hunk is cut off and appears to be realigned.
- The content of the roughly 3031 cut-off diff lines (the rest of dng_jxl.cpp, plus dng_stream.cpp, dng_linearization_info.cpp, dng_misc_opcodes.cpp, dng_pixel_buffer.cpp, dng_negative.cpp, dng_read_image.cpp, dng_resample.cpp, dng_shared.cpp, dng_string.cpp, dng_xmp*.cpp, dng_preview.cpp, dng_update_meta.cpp, dng_matrix.cpp).
- What each of the two internal cherry-picked commits (403d0a45641560631b0d6a9653c94a22163e3008 and defc6b209f2ea4b724c0122f9c82d5b6053f9425) contained.
- Whether the 15 and 16 diffs are byte-identical to the 14 diff beyond the visible portion.
- Which Android platform component links dng_sdk and exposes the parser to untrusted input.