CVE-2026-45516 AI-generated analysis
platform/external/freetype, TrueType GX/OpenType variation parsing (src/truetype/ttgxvar.c)
Adds an unsigned-multiplication wraparound check on per_region_size * item_count in tt_var_load_item_variation_store (src/truetype/ttgxvar.c) before varData->deltaSet is allocated. When the product wraps, the function now returns Array_Too_Large.
Root cause
In tt_var_load_item_variation_store, the size of each varData delta set array was computed as per_region_size * item_count in FT_UInt arithmetic with no overflow check. item_count, word_delta_count and region_idx_count are read from the font with FT_READ_USHORT. per_region_size is doubled when long_words is set. The product could wrap, and the wrapped value went straight to FT_NEW_ARRAY( varData->deltaSet, ... ), giving an allocation smaller than per_region_size * item_count.
How the fix works
- src/truetype/ttgxvar.c:tt_var_load_item_variation_store: adds a new local FT_UInt delta_set_size and computes delta_set_size = per_region_size * item_count. If per_region_size is non-zero and delta_set_size / per_region_size != item_count (meaning the multiplication wrapped), the function emits an FT_TRACE2 message, sets error = FT_THROW( Array_Too_Large ) and jumps to Exit.
- The FT_NEW_ARRAY( varData->deltaSet, ... ) call that follows now uses the checked delta_set_size instead of computing the product inline. The FT_Stream_Read after it does not appear in the diff.
- The fix is a single commit, with the same hunk on Android 15, 16 and 17. No other function is touched.
Completeness
- The fix covers exactly one multiplication: per_region_size * item_count for varData->deltaSet in tt_var_load_item_variation_store. The guard skips the per_region_size == 0 case, where the product is 0 and cannot wrap.
- Other code in the same function shown in the context, such as FT_NEW_ARRAY( itemStore->varData, data_count ) and the varRegionList axisList parsing, is not changed by this commit. The material does not show whether any similar multiplications exist there.
- The fix only rejects the font. It does not change how deltaSet is used afterwards.
- No regression test is included (Test: locally built).
Behavior changes
- Fonts whose item variation store has a per_region_size * item_count that wraps FT_UInt now fail with Array_Too_Large. Before the fix, the wrapped size was passed to the allocation.
- New FT_TRACE2 diagnostic: 'tt_var_load_item_variation_store: bad delta set array size'.
Per major
- Android 14: Not affected per the bulletin (not listed). At android-security-14.0.0_r30 only 2/8 lines of the patched region are present, so the fix is not applied there. The material does not show whether the vulnerable multiplication exists in that FreeType version.
- Android 15: Same fix: commit 2e564343a4ce in android-security-15.0.0_r17, cherry-picked from internal change 68c9652af5e4 (Change-Id I44bdd6333551b1452f540a120fe29d5b9361823a). Hunks at lines 625/682. 7/8 lines present at android-security-15.0.0_r18.
- Android 16: Same fix: commit 285b264bf272 in android-security-16.0.0_r8. The diff and blob hashes (ad4f266b2..7fa8256d4) are identical to the Android 15 change. 7/8 lines present at android-security-16.0.0_r9.
- Android 17: Same fix: commit 333924d9d5ea in android-security-17.0.0_r1. The hunk content is identical but applies to a newer ttgxvar.c base (blob ef4ca0933..47076d945), with hunks at lines 628/697 instead of 625/682. 7/8 lines present at android-security-17.0.0_r2.
Unknowns
- How per_region_size is computed from region_idx_count and word_delta_count (lines 655-682 are not shown), so the exact overflow bound is not visible.
- How deltaSet is used after the allocation, and which code would access memory out of bounds, is not shown.
- Which Android font-loading paths actually reach item variation store parsing with untrusted fonts.
- Whether the Android 14 FreeType version contains the same unchecked multiplication.