CVE-2026-45519 AI-generated analysis
platform/packages/providers/MediaProvider, photopicker (PickerUriResolver / preselection URI handling)
Adds structural, scheme, authority and user-ID validation of caller-supplied photopicker preselection URIs (EXTRA_PICKER_PRE_SELECTION_URIS) in PickerUriResolver.processUrisForSelection before they are used to build the picker database query.
Root cause
PickerUriResolver.processUrisForSelection parsed each string in the preselection list (QUERY_ID_SELECTION) with Uri.parse and relied only on checkUriPermission(uri, -1, callingUid) before adding it to accessibleUris, whose IDs then feed the picker DB query selection. Nothing checked that the URI used the content scheme, the MediaStore.AUTHORITY authority, or a valid picker path shape (content://media/picker/<user-id>/<authority>/media/<id>, per the 16/17 tests). Nothing checked that the user ID encoded in the URI matched the user the picker runs as (UserHandle.myUserId()). A URI with a foreign user ID or an unexpected structure could therefore be accepted, and the commit message describes the result as a data mismatch during database queries (the bulletin classifies the issue as information disclosure).
How the fix works
- src/com/android/providers/media/PickerUriResolver.java: adds a static LocalUriMatcher sStaticUriMatcher = new LocalUriMatcher(MediaStore.AUTHORITY) and a new public static method isValidPickerUri(@Nullable Uri). It rejects null and any scheme other than ContentResolver.SCHEME_CONTENT, then requires sStaticUriMatcher.matchUri(uri, /* allowHidden */ false) to return PICKER_ID or PICKER_GET_CONTENT_ID. Per its javadoc, this also enforces the MediaStore.AUTHORITY authority and the picker path segments.
- src/com/android/providers/media/PickerUriResolver.java: processUrisForSelection now runs two checks inside the per-URI try block, before checkUriPermission. It skips (continue, Log.d) any URI that fails isValidPickerUri, then skips any URI whose getUserId(uriForSelection) != UserHandle.myUserId(). In the 16/17 diffs, getUserId is Integer.parseInt of path segment 1. Only URIs that pass both checks reach checkUriPermission and accessibleUris.
- tests/src/com/android/providers/media/PickerUriResolverTest.java: testProcessUrisForSelection_permissionChecks and the cloud-authority test now build picker URIs with UserHandle.myUserId() instead of TEST_USER, so they pass the new user-ID filter.
Completeness
- Covers only the PickerUriResolver.processUrisForSelection path. The checks run per URI before the existing permission check, so a URI must be a well-formed picker URI for the current user AND be permission-granted to the calling uid.
- On Android 15, isValidPickerUri accepts only PICKER_ID and PICKER_GET_CONTENT_ID. The 16/17 versions also accept PICKER_TRANSCODED_ID. Transcoded picker URIs, if they exist on 15, would be filtered out.
- The Android 15 commit does not touch photopicker/v2/model/MediaQueryForPreSelection.java, which the 16/17 commits patch with the same check sequence. The material does not show whether that class exists at android-security-15.0.0_r17.
- The user-ID check compares against UserHandle.myUserId() rather than a caller-specified target user, so cross-profile preselection URIs are dropped.
Behavior changes
- Preselection URIs are now silently ignored (Log.d) if they have a non-content scheme, an authority other than MediaStore.AUTHORITY, a path that does not match the picker / picker_get_content item patterns, or a user ID different from the running user. Such URIs no longer contribute to QUERY_LOCAL_ID_SELECTION / QUERY_CLOUD_ID_SELECTION.
- Preselection of media from another user profile (if any app relied on it) is no longer honored.
- New public static API PickerUriResolver.isValidPickerUri(Uri).
Per major
- Android 14: Not affected (the bulletin does not list Android 14). No fix commit is referenced for 14. For context, 6/8 lines of the patched region are present at android-security-14.0.0_r29.
- Android 15: Resolved by commit 1b032be59978 in android-security-15.0.0_r17 (RESTRICT AUTOMERGE cherry-pick, Change-Id If872e5ee84f18abde0551fb52ca025a9d3808cfa). It touches only PickerUriResolver.java (isValidPickerUri accepting PICKER_ID / PICKER_GET_CONTENT_ID, plus the user-ID check) and PickerUriResolverTest.java. 8/8 patched lines present.
- Android 16: Adapted fix 32217e55e510 in android-security-16.0.0_r8. It makes the same PickerUriResolver changes and also accepts PICKER_TRANSCODED_ID and makes getUserId public. It adds the same validate / user-ID / permission sequence to photopicker/v2/model/MediaQueryForPreSelection.java, and adds PickerDataLayerV2Test cases for cross-user, malformed, fake-authority and invalid-segment URIs. 7/8 patched lines present.
- Android 17: Adapted fix 50d220c204df in android-security-17.0.0_r1, with the same content as the Android 16 commit (PickerUriResolver + MediaQueryForPreSelection + tests). 7/8 patched lines present.
Unknowns
- Whether photopicker/v2/model/MediaQueryForPreSelection.java (patched on 16/17) exists at android-security-15.0.0_r17 and, if so, why the 15 commit leaves it out.
- The exact disclosure outcome for a mismatched user ID is not shown. The commit only describes it as a data mismatch during database queries.
- Which exceptions the surrounding try/catch in processUrisForSelection handles (not shown in the diff context).
- The implementation of getUserId on the 15 branch (shown only in the 16/17 diffs).