CVE-2025-48654 AI-generated analysis
platform/frameworks/base, CompanionDeviceManager service (services/companion)
CompanionDeviceManagerService now disassociates every association that the AssociationStore reports as revoked during service start-up, so revoked associations no longer survive a reboot.
Root cause
In CompanionDeviceManagerService start-up, after mAssociationStore.refreshCache() initialised the association store, the start-up path did not process associations that were already in the revoked state. A revoked association could therefore stay in the store across a reboot instead of being fully disassociated, which left stale association state in place. The REASON_REVOKED disassociation reason and AssociationStore.getRevokedAssociations() already existed, because the diff uses them without adding them; the boot path did not act on them.
How the fix works
- services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java (service start-up, directly after mAssociationStore.refreshCache()): adds a loop over mAssociationStore.getRevokedAssociations() that calls mDisassociationProcessor.disassociate(ai.getId(), REASON_REVOKED) for each AssociationInfo. The normal disassociation path therefore runs for every revoked association as soon as the cache is loaded.
- Adds the static import of DisassociationProcessor.REASON_REVOKED. The commit changes no other files.
Completeness
- Covers only the boot-time path: revoked associations present in the store when the service starts are now removed through the standard DisassociationProcessor.disassociate path.
- The fix relies on the existing DisassociationProcessor.disassociate behaviour for the actual cleanup. The material does not show what that method removes.
- The fix does not change how an association enters the revoked state or how it is handled while the system is running. Those paths are not in the diff.
- The loop runs once at start-up and does not reference a user. Whether getRevokedAssociations() is user-scoped or global is not shown.
Behavior changes
- At service start, each revoked association is disassociated with reason REASON_REVOKED. Any side effects of DisassociationProcessor.disassociate now happen at boot instead of the entries being left in place.
- No API surface, return value or permission change is visible in the diff.
Per major
- Android 14: Not affected (not listed by the bulletin). At android-security-14.0.0_r29, 1/8 lines of the patched region are present. Google applied no fix.
- Android 15: Not affected (not listed by the bulletin). At android-security-15.0.0_r17, 6/8 lines of the patched region are present. Google applied no fix.
- Android 16: Same fix: commit 924df83d73d9 in android-security-16.0.0_r4 (cherry-pick, Change-Id I94b96d98608d6702e1d3a9581e135280149bf7e1). 8/8 lines are present at android-security-16.0.0_r8.
- Android 17: Not affected (not listed by the bulletin). 8/8 lines of the patched region are present at android-security-17.0.0_r1.
Unknowns
- How an association enters the revoked state and why it could persist across a reboot (the code that sets the revoked state is not in the material).
- What DisassociationProcessor.disassociate cleans up, and therefore what privileges a stale revoked association kept (the bulletin only states EoP, High).
- Whether getRevokedAssociations() is scoped to the current user or covers all users.
- Why Android 15 is not listed as affected even though it has most of the patched region, and which lines are present there.
- Whether Android 14 has the APIs the patch depends on.