Resolve cross account user ringtone validation.

Resolves a vulnerability found with the lack of cross account user ringtone
validation in RingtoneFactory. The reporter found that a ringtone file owned by a different user can be accessed and played by the user who does not own that file.

Bug: 356604577
Flag: EXEMPT Critical CVE bugfix
Test: RingtoneFactoryTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1c7fbd70da65f7b2dd561af8ec9f94b81acf5baa)
Merged-In: Ie28e8d0890086caada561ed27dd660836e6aa6bb
Change-Id: Ie28e8d0890086caada561ed27dd660836e6aa6bb
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index cf52ce9..0399a80 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -3119,7 +3119,8 @@
         return Contacts.getLookupUri(mCallerInfo.getContactId(), mCallerInfo.lookupKey);
     }
 
-    Uri getRingtone() {
+    @VisibleForTesting
+    public Uri getRingtone() {
         return mCallerInfo == null ? null : mCallerInfo.contactRingtoneUri;
     }
 
diff --git a/src/com/android/server/telecom/RingtoneFactory.java b/src/com/android/server/telecom/RingtoneFactory.java
index 6bcfb4c..1caa005 100644
--- a/src/com/android/server/telecom/RingtoneFactory.java
+++ b/src/com/android/server/telecom/RingtoneFactory.java
@@ -80,12 +80,18 @@
         Ringtone ringtone = null;
 
         if (ringtoneUri != null && userContext != null) {
-            // Ringtone URI is explicitly specified. First, try to create a Ringtone with that.
-            try {
-                ringtone = RingtoneManager.getRingtone(
-                        userContext, ringtoneUri, volumeShaperConfig, audioAttrs);
-            } catch (Exception e) {
-                Log.e(this, e, "getRingtone: exception while getting ringtone.");
+            if (currentUserOwnsRingtone(ringtoneUri, incomingCall)) {
+                // Ringtone URI is explicitly specified and owned by the current user - try to
+                // create a Ringtone with that.
+                try {
+                    ringtone = RingtoneManager.getRingtone(
+                            userContext, ringtoneUri, volumeShaperConfig, audioAttrs);
+                } catch (Exception e) {
+                    Log.e(this, e, "getRingtone: exception while getting ringtone.");
+                }
+            } else {
+                Log.w(this, "getRingtone: Failed to verify that the custom ringtone URI"
+                        + " is owned by the current user. Falling back to the default ringtone.");
             }
         }
         if (ringtone == null) {
@@ -120,6 +126,21 @@
         return ringtone;
     }
 
+    private static boolean currentUserOwnsRingtone(Uri ringtoneUri, Call incomingCall) {
+        if (TextUtils.isEmpty(ringtoneUri.getUserInfo()) ||
+                incomingCall.getAssociatedUser() == null) {
+            return false;
+        }
+
+        UserHandle associatedUser = incomingCall.getAssociatedUser();
+        if (associatedUser == null) {
+            return false;
+        }
+
+        String currentUserId = String.valueOf(associatedUser.getIdentifier());
+        return currentUserId.equals(ringtoneUri.getUserInfo());
+    }
+
     private AudioAttributes getDefaultRingtoneAudioAttributes(boolean hapticChannelsMuted) {
         return new AudioAttributes.Builder()
             .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)