CVE-2025-64784 AI-generated analysis
platform/external/dng_sdk (Adobe DNG SDK: DNG/TIFF/JXL parsing, image reading, opcodes, fingerprinting)
Google fixed this High-severity information-disclosure issue in platform/external/dng_sdk by replacing the vendored Adobe DNG SDK with upstream version 1.7.1 build 2410 (61 files, +2721/-694). This is a wholesale update with many parser, stream and fingerprinting changes rather than a single targeted check.
Root cause
Not determinable from the material. The fix commit "Update to DNG SDK 1.7.1 2410" (Bug 465781139) imports a full upstream SDK release, and the material does not identify which changed code path is behind the information-disclosure report. Changes visible in the shown diff: - dng_ifd.cpp ParseTag adds a bounded (4 MiB) reader for the new tcGainMapMetadata_ISO_21496_1 tag. - dng_gain_map.cpp dng_opcode_GainMap::ProcessArea reworks row/column stepping: rowPitch and colPitch are clamped to the overlap size, and iteration uses explicit row/column counts. - dng_fingerprint's raw data[] array becomes private, with Data()/MutableData() accessors, and typed Get/Put(dng_fingerprint) calls replace raw 16-byte pointer reads/writes. The post-fix dng_jxl.cpp dng_jxl_io_buffer::ReadChunk checks the bytes remaining in the stream, throws ThrowEndOfFile when none remain, and clamps the read size. The old body is truncated in the diff, so it is unknown whether this logic is new. Post-fix context also shows: - DNG_REQUIRE bounds checks in dng_linearize_plane::Process and dng_pixel_buffer::SetConstant; - scale/radius/overflow checks in dng_resample_weights::Initialize; - a dng_stream::Get overload with a maxOverRead parameter. The diff hunks for those files are not shown, so it is unknown whether this commit introduced them.
How the fix works
- Single commit d0bfe8eeee73 (Change-Id Ia850e7c3a3ab1b35dd619cc78159663df3b2b2c8, cherry-picked from two internal commits). It sets source/dng_flags.h to kDNGSDK_VersionString "1.7.1" / kDNGSDK_BuildVersion 2410 and updates 61 source files to that upstream release.
- source/dng_jxl.cpp dng_jxl_io_buffer::ReadChunk, as it reads after the fix: computes bytes_remaining_in_stream; throws ThrowEndOfFile("dng_jxl_io_buffer") when it is zero; limits next_read_size to min(fChunkSize, remaining stream bytes); memmoves leftover data to the buffer start when the next chunk would exceed fMaxBufferSize; then reads with stream.Get. The diff does not show whether the old ReadChunk already did this, because its body is truncated and the hunk appears to be a realignment around large added blocks.
- source/dng_ifd.cpp dng_ifd::ParseTag: new case tcGainMapMetadata_ISO_21496_1. It requires ttUndefined, rejects tagCount > 4*1024*1024 with ThrowBadFormat, allocates tagCount bytes via host.Allocate and reads them into fGainMapMetadata. dng_ifd::IsValidDNG now accepts sfPreviewGainMap alongside sfGainMap.
- source/dng_gain_map.cpp dng_opcode_GainMap::ProcessArea: rowPitch = Min(fAreaSpec.RowPitch(), overlap.H()) and colPitch = Min(fAreaSpec.ColPitch(), overlap.W()); rows and cols are computed as ceil(overlap/pitch); the row and column loops iterate by index counts and advance by the clamped pitch. This replaces loops that stepped by the unclamped fAreaSpec.RowPitch() and by colPitch against overlap.W().
- source/dng_fingerprint.h/.cpp changes: - dng_fingerprint::data is made private (friends: dng_fingerprint_less_than, dng_md5_printer), with an explicit copy constructor/assignment and Data()/MutableData(). - dng_md5_printer::Process(const void*, uint32) is renamed to virtual ProcessPtr. New methods: Process(const dng_fingerprint&), Process(const dng_string&), Process_bool, Process_size. - The dng_md5_printer constructor is made protected. New classes: dng_md5_printer_le_stream (always little-endian) and dng_md5_direct_printer. - dng_md5_printer_stream::ProcessPtr flushes before hashing, so interleaved Put and Process calls are serialized correctly. Callers across the SDK are converted to typed fingerprint Get/Put and to Put_uint32/Put_real32/Put_real64/Put_swap4/Put_swap8 instead of hashing raw in-memory bytes.
- source/dng_exceptions.h/.cpp: dng_exception now derives from std::exception, carries an fErrorMsg string and implements what(). With qDNGVerboseExceptions (default 1 in dng_flags.h), Throw_dng_error passes message and sub_message into the exception. DNG_NO_RETURN is placed before the return type and uses [[noreturn]] on C++11.
- source/dng_abort_sniffer.cpp/.h: the dng_sniffer_task destructor is made virtual and out-of-line, and wraps fSniffer->EndTask() in try/catch(...). dng_abort_sniffer gains virtual SniffSlowHint().
- source/dng_image_writer.cpp/.h: WriteTIFF, WriteTIFFWithProfile, WriteDNG and WriteDNGWithMetadata gain gainMapMetadataBlock and gainMapAltProfileData/Size parameters. The TIFF gain-map IFD is only written when both the image and the metadata block are present. The PGTM duplicate-write logic now keys off profile_tag_set::ProfileDidWritePGTMToMainIFD().
- Other visible changes: - dng_file_stream(int fd, ...) delegates to the mode-string constructor. - dng_info::fTIFFBlockOriginalOffset is initialised to 0 instead of kDNGStreamInvalidOffset. - dng_info::ParseDNGPrivateData gains a RICOH branch that calls ParseMakerNoteIFD. - dng_ifd::IsBaselineJPEG treats ccJPEG + piRGB with 3 or 4 samples as baseline. - dng_host::MakeJXLEncodeSettings uses host-attached JXLEncodeSettings when present. - dng_flags.h adds sanitizer detection macros and DNG_FALLTHROUGH. - The dng_area_task range struct gains fAllocator. The remaining ~3000 diff lines are truncated in the material.
Completeness
- The fix is a full upstream release import, so it covers every code path changed between the previously vendored SDK and 1.7.1 build 2410. The material cannot show which single change closes the reported issue, so completeness against the CVE's trigger cannot be judged from the code.
- At android-security-14.0.0_r29, dng_flags.h shows kDNGSDK_BuildVersion 2502, so a later SDK update was applied on top of this one. The build 2410 state described by this diff is not the final state of the branch.
- The diffs for most of dng_jxl.cpp (about 1200 changed lines) and for dng_stream.cpp (189 lines, including the Get overload with maxOverRead seen in context) are truncated. It is not visible whether all stream-read sites have equivalent end-of-stream handling.
- A Google-specific modification (the BEGIN/END GOOGLE MODIFICATION plane-bounds loop in dng_misc_opcodes.cpp dng_opcode_MapTable::ProcessArea) is present in the post-fix tree, so Android's local patch was kept. The truncated dng_misc_opcodes.cpp diff does not show whether this commit touched it.
Behavior changes
- dng_exception is now a std::exception, with what() returning "dng_error: <code>[: message (sub_message)]". qDNGVerboseExceptions defaults to 1, so messages are kept in thrown exceptions.
- The new tag tcGainMapMetadata_ISO_21496_1 is parsed. A tag larger than 4 MiB throws dng_error_bad_format ("Gain map metadata block too large").
- NewSubFileType sfPreviewGainMap is now accepted as a valid gain-map IFD.
- JPEG-compressed RGB IFDs with 3 or 4 samples are treated as baseline JPEG for reading.
- RICOH-prefixed DNGPrivateData is parsed as a Pentax maker note.
- Public API changes for in-tree users: - dng_fingerprint::data is private; use Data()/MutableData(). - dng_md5_printer::Process(ptr, len) is now ProcessPtr. - dng_md5_printer cannot be instantiated directly; use dng_md5_direct_printer or the stream variants. - The WriteTIFF/WriteDNG family gain extra trailing parameters, which shifts the position of useHalfFloat in WriteTIFF/WriteTIFFWithProfile.
- Several fingerprints that previously hashed native in-memory byte order (masked RGB tables, hue/sat map interpolation, RGB-to-RGB table data, HDR hint) now hash little-endian serialized values. This can change computed digests on big-endian hosts.
- The dng_sniffer_task destructor swallows exceptions from EndTask(). dng_info::fTIFFBlockOriginalOffset starts at 0.
Per major
- Android 14: same fix: commit d0bfe8eeee73 "Update to DNG SDK 1.7.1 2410" (Change-Id Ia850e7c3a3ab1b35dd619cc78159663df3b2b2c8) in android-security-14.0.0_r25. At android-security-14.0.0_r29 the patched region is fully present (8/8 lines), and dng_flags.h already reports a later build (2502), so a further SDK update was applied on top.
- Android 15: same fix: commit 45da10961287 with the same subject, linked by change_id, in android-security-15.0.0_r13. 8/8 lines present at android-security-15.0.0_r17.
- Android 16: same fix: commit 6b5cf2a88ebd (the ref the Android 14 commit is linked from) in android-security-16.0.0_r4. 8/8 lines present at android-security-16.0.0_r8.
- Android 17: not affected per the bulletin; android-security-17.0.0_r1 already contains the patched region (8/8 lines present).
Unknowns
- Which specific change in the 1.7.1 build 2410 update addresses the reported information disclosure, and what file construct triggers it (the diff is a bulk version bump with roughly 3000 lines truncated).
- Whether the dng_jxl_io_buffer::ReadChunk end-of-stream check and read clamp are new in this commit or were already present before it (the old body is truncated in the diff).
- Whether the DNG_REQUIRE bounds checks visible in post-fix context (dng_linearize_plane::Process, dng_pixel_buffer::SetConstant), the checks in dng_resample_weights::Initialize and the dng_stream::Get maxOverRead overload were introduced by this commit or by the later build 2502 update.
- Which Android processes link libdng_sdk and expose the parser to untrusted input (the index search returned no conclusive consumer).