CVE-2025-26452 AI-generated analysis
platform/frameworks/base, core resources (ResourcesImpl drawable loading for fabricated runtime resource overlays, ResourcesManager)
Restricts the "frro:" drawable-loading branch in ResourcesImpl. The file named in the resource value is now opened only if its canonical path is under /data/resource-cache/, ends in ".frro" and is readable, and only if the offset parameter is non-negative and the size parameter is positive.
Root cause
In core/java/android/content/res/ResourcesImpl.java, when a drawable resource's string value started with "frro://", the code parsed it as a Uri and built a File from '/' + host + path. It opened that file with ParcelFileDescriptor.open(MODE_READ_ONLY), wrapped it in an AssetFileDescriptor using the unchecked "offset" and "size" query parameters, and decoded it as an image. Nothing limited the file to the fabricated-overlay cache directory or to .frro files. Any process loading such a resource value would therefore open and decode whatever readable file the value pointed to, at any offset and size.
How the fix works
- core/java/android/app/ResourcesManager.java: adds public static final String RESOURCE_CACHE_DIR = "/data/resource-cache/" and makes overlayPathToIdmapPath use it. This is a pure refactor so that ResourcesImpl can share the constant.
- core/java/android/content/res/ResourcesImpl.java (frro drawable-loading branch; the enclosing method is not shown in the hunk): widens the prefix test from "frro://" to "frro:/". Values that start with "frro:/" but not "frro://" now go through the validated branch instead of falling through to the following else branch.
- ResourcesImpl.java: parses offset and size up front and throws NotFoundException("invalid frro parameters") if offset < 0 or size <= 0.
- ResourcesImpl.java: after building File f, requires that f.getCanonicalPath() starts with ResourcesManager.RESOURCE_CACHE_DIR, that it ends with ".frro", and that f.canRead() is true. Otherwise it throws NotFoundException("invalid frro path"). Only after these checks does it open the ParcelFileDescriptor and build the AssetFileDescriptor with the already-validated offset and size.
Completeness
- Covers the single frro drawable branch in ResourcesImpl. The material shows no other consumer of frro: values.
- getCanonicalPath() resolves symlinks before the prefix check, so a symlink inside /data/resource-cache/ that points elsewhere is rejected. A null host yields "/null...", which also fails the prefix check.
- Does not check that offset+size lies within the file, or that the .frro file belongs to the overlay the resource value came from. Any readable .frro file under /data/resource-cache/ is accepted.
- A missing or non-numeric offset or size still makes Long.parseLong throw NumberFormatException. How that exception, and an IOException from getCanonicalPath, are handled depends on enclosing exception handling that the hunk does not show.
Behavior changes
- frro drawable values that point outside /data/resource-cache/, do not end in .frro, or are not readable now fail with Resources.NotFoundException("invalid frro path") instead of loading.
- A negative offset or a non-positive size now fails with NotFoundException("invalid frro parameters").
- Values starting with "frro:/" (single slash) now go to the frro branch rather than the following else branch.
- New public constant ResourcesManager.RESOURCE_CACHE_DIR (the class is @hide).
Per major
- Android 14: same fix: cherry-pick 37a272435a23 in android-security-14.0.0_r21 (Merged-In I4247e54f3ea0d9e4bf0d9f404e0272751a258ba2). 7/8 lines of the patched region are still present at android-security-14.0.0_r29.
- Android 15: same fix: 26c58543f19d in android-security-15.0.0_r9. Same diff content at different line offsets. 6/8 lines present at android-security-15.0.0_r17.
- Android 16: same fix: original commit 12e49e7a4e56 in android-16.0.0_r2. 6/8 lines present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin). 5/8 lines of the patched region present at android-security-17.0.0_r1.
Unknowns
- Which privileged processes load attacker-supplied resource values through this branch (the bulletin only states EoP, High).
- The name of the enclosing method and its exception handling, which the hunk does not show.
- What the else branch after the frro branch does.
- Whether other code paths consume frro: values (none shown in the material).