CVE-2026-0035 AI-generated analysis
platform/packages/providers/MediaProvider, MediaStore createRequest (PermissionActivity request creation)
MediaProvider now rejects MediaStore CREATE_WRITE/DELETE/..._REQUEST calls with an IllegalArgumentException when any requested URI does not resolve to exactly one existing row at request time.
Root cause
In src/com/android/providers/media/MediaProvider.java, the code path that builds the PermissionActivity Intent for the MediaStore CREATE_*_REQUEST methods (createWriteRequest, createDeleteRequest, etc.) took the caller-supplied list of URIs and built the request without checking that each URI referred to an existing item. A caller could therefore obtain a request for a media URI that did not exist in the Files table at the time of the call. Before the fix, testCreateRequest asserted success for a non-existent id (42), which confirms the old behavior.
How the fix works
- src/com/android/providers/media/MediaProvider.java (the createRequest handler; the hunk header does not show the enclosing method name): after the existing per-URI validation block and before the PermissionActivity Intent is created, a new loop goes over all `uris`. For each URI it calls queryForSingleItem(uri, new String[]{FileColumns._ID}, null, null, null) in a try-with-resources. queryForSingleItem throws FileNotFoundException if it finds zero rows or multiple rows, or if there is a read error. The handler converts that exception to IllegalArgumentException("Invalid Uri: " + uri, e), which aborts the request.
- The loop runs under clearLocalCallingIdentity()/restoreLocalCallingIdentity(token) inside a try/finally. The existence query therefore runs with MediaProvider's own identity, and the identity is always restored.
- tests/src/com/android/providers/media/MediaProviderTest.java: testCreateRequest now inserts a real audio row via sIsolatedResolver.insert (assumeTrue(uri != null)) and makes the request on that URI. The new test testCreateRequest_invalidUri_throwsException asserts IllegalArgumentException for the non-existent id 42.
Completeness
- Every URI in the list is checked. The check comes before the Intent is built with `method` as its action, which suggests it covers every CREATE_*_REQUEST method. The commit message explicitly names CREATE_WRITE/DELETE/.._REQUEST.
- The check runs only when the request is created. The material does not show whether PermissionActivity checks existence again when the grant is applied; this diff does not address any window between the check and the grant.
- queryForSingleItem also throws when it finds multiple matches, so URIs that resolve to more than one row are rejected too. This is stricter than rejecting only non-existent URIs.
- Rejection happens at the first invalid URI, before the Intent is created, so no partial request is built.
Behavior changes
- MediaStore create*Request calls (createWriteRequest is shown in the tests) now throw IllegalArgumentException("Invalid Uri: ...") when any supplied URI does not exist or is ambiguous. Before the fix, the old test shows that a non-null request was returned for a non-existent id.
- One additional database query per requested URI, run with cleared calling identity.
- Callers that create requests for URIs that are not yet inserted will now get an exception. The existing test testCreateRequest was changed to use a real inserted row.
Per major
- Android 14: same fix: commit 003dd55147bf in android-security-14.0.0_r25 (cherry-pick of internal changes 268fc3fb/027c6c2c, Change-Id I00a3b15d). 8/8 lines of the patched region are present at android-security-14.0.0_r29.
- Android 15: same fix: commit 56e6173dcc97 in android-security-15.0.0_r13. The MediaProvider.java hunk is identical but at a different offset (line ~7644). The test hunk differs only in context and indentation around testGrantMediaReadForPackage. 8/8 lines are present at android-security-15.0.0_r17.
- Android 16: same fix: commit 119013a3d7e8 in android-security-16.0.0_r4. The MediaProvider.java hunk is identical, at line ~8383. 8/8 lines are present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin). The patched region is present (8/8 lines) at android-security-17.0.0_r1.
Unknowns
- The exact name of the enclosing method in MediaProvider.java (the hunk header shows only the class).
- What concrete privilege escalation a request on a non-existent URI led to (for example, how PermissionActivity behaves when the row appears later). The material does not show the grant-side code.
- Whether PermissionActivity runs its own existence check at grant time.
- Whether trash and favorite requests go through the same code path (the commit message names only write and delete explicitly).