CVE-2025-48604 AI-generated analysis
platform/packages/services/Mms, MmsService download path (DownloadRequest / RequestManager.writePduToContentUri)
MmsService now records the calling user for each MMS download request and refuses to write the downloaded PDU to the caller-supplied content URI when the URI's embedded user ID does not match the calling user.
Root cause
In the MmsService download handler, the caller supplies a contentUri, and the downloaded MMS PDU is written to it. DownloadRequest did not keep the calling user. MmsService.writePduToContentUri(Uri, byte[]) checked only for null arguments and never compared the URI's user component with the user of the app that requested the download, so a content URI carrying a different user's ID was not rejected. In the code context, the sibling read path (RequestManager.readPduFromContentUri) already takes a callingUser parameter. Before this fix, the write path used for downloads did not.
How the fix works
- src/com/android/mms/service/MmsService.java (download handler that builds DownloadRequest): passes the existing callingUser variable into the DownloadRequest constructor, as a new argument placed before callingPkg.
- src/com/android/mms/service/DownloadRequest.java: adds a final field mCallingUser, set from the new constructor parameter. DownloadRequest.transferResponse now calls mRequestManager.writePduToContentUri(mContentUri, response, mCallingUser).
- src/com/android/mms/service/MmsRequest.java:RequestManager.writePduToContentUri: the interface signature gains an int callingUser parameter.
- src/com/android/mms/service/MmsService.java:writePduToContentUri: after the existing null checks, computes contentUriUserID = ContentProvider.getUserIdFromUri(contentUri, UserHandle.myUserId()). If callingUser != contentUriUserID, it logs with LogUtil.e and returns false. Only when the IDs match does it go on to the existing copyDownloadedPduToOutput callable.
- The Android 15 and 16 commits also update tests/robotests/src/com/android/mms/service/MmsRequestRoboTest.java (downloadRequest_noSatellite_downloadSuccessful) to pass CALLING_USER to the new constructor. The Android 14 commit has no test change.
Completeness
- Covers the download write path. The only caller of RequestManager.writePduToContentUri visible in the diff is DownloadRequest.transferResponse, and that call now enforces calling user == URI user. Per index search, no other callers were found, but that search may be incomplete.
- A URI with no explicit user component resolves to UserHandle.myUserId() (the user MmsService runs as). Such a URI is accepted when the calling user equals that user. A URI with an explicit, different user is rejected.
- The check runs in transferResponse/writePduToContentUri. The request is still created and enqueued (addSimRequest). The diff does not change the carrier-app path (request.tryDownloadingByCarrierApp), and the material does not show whether that path reaches transferResponse.
- In the code context, the read path readPduFromContentUri already takes a callingUser parameter. Its body is not in the material, so it cannot be confirmed whether it performs an equivalent check.
Behavior changes
- writePduToContentUri returns false, so the download fails at transferResponse, when the content URI's user ID differs from the calling user. It also logs an error line starting 'Uri belongs to a different user'.
- The DownloadRequest constructor and RequestManager.writePduToContentUri signatures change (new int callingUser parameter). This affects every implementer or test double of RequestManager.
Per major
- Android 14: same fix: ed4355456181 in android-security-14.0.0_r24 (cherry-pick of 0b8c94aa0a37), touching three source files with no test change. 7/8 lines of the patched region are present at android-security-14.0.0_r29.
- Android 15: same fix, adapted: ad9bf77e4577 in android-security-15.0.0_r12. Same logic; the DownloadRequest constructor here also has a trailing TelephonyManager parameter, and the commit updates MmsRequestRoboTest. 7/8 lines are present at android-security-15.0.0_r17.
- Android 16: same fix, adapted: c60a828b9fa1 in android-security-16.0.0_r3, the same change as Android 15 including the robotest update. 7/8 lines are present at android-security-16.0.0_r8.
- Android 17: not affected (not listed by the bulletin). 5/8 lines of the patched region are present at android-security-17.0.0_r1, and the material provides no commit for this branch.
Unknowns
- The name of the MmsService download handler method, and how callingUser is derived in it (not shown in the diff or context).
- Whether the carrier-app download path (tryDownloadingByCarrierApp) ends in transferResponse and so gets the check.
- The order of doHttp and transferResponse in the request flow.
- The body of readPduFromContentUri and whether it performs an equivalent user check.
- What the copyDownloadedPduToOutput callable does when opening the URI (which identity it uses).
- Why only 5/8 patched lines are present at android-security-17.0.0_r1.