Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4986acd0 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

RingtonePlayer: preventative cleanup before a SecurityException

Before throwing a SecurityException, also stop any client trying
to access a URI they don't have access to.
This has also the intended side effect of removing that Client
instance from the mClients HashMap.

Bug: 406744501
Bug: 400434060
Test: atest com.android.systemui.ringtone.RingtonePlayerTest
Flag: android.media.audio.ringtone_user_uri_check
Change-Id: If338948c915e808f8ae0d7dc0ddd4cabaf329a7c
parent fe9528bc
Loading
Loading
Loading
Loading
+37 −23
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ public class RingtonePlayer implements CoreStartable {
                throws RemoteException {
            playWithVolumeShaping(token, uri, aa, volume, looping, null);
        }

        @Override
        public void playWithVolumeShaping(IBinder token, Uri uri, AudioAttributes aa, float volume,
                boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig)
@@ -127,7 +128,7 @@ public class RingtonePlayer implements CoreStartable {
                Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
                        + Binder.getCallingUid() + ")");
            }
            enforceUriUserId(uri);
            enforceUriUserId(uri, token);

            Client client;
            synchronized (mClients) {
@@ -210,7 +211,7 @@ public class RingtonePlayer implements CoreStartable {

        @Override
        public String getTitle(Uri uri) {
            enforceUriUserId(uri);
            enforceUriUserId(uri, null /*clientToken*/);
            final UserHandle user = Binder.getCallingUserHandle();
            return Ringtone.getTitle(getContextForUser(user), uri,
                    false /*followSettingsUri*/, false /*allowRemote*/);
@@ -218,7 +219,7 @@ public class RingtonePlayer implements CoreStartable {

        @Override
        public ParcelFileDescriptor openRingtone(Uri uri) {
            enforceUriUserId(uri);
            enforceUriUserId(uri, null /*clientToken*/);
            final UserHandle user = Binder.getCallingUserHandle();
            final ContentResolver resolver = getContextForUser(user).getContentResolver();

@@ -244,29 +245,42 @@ public class RingtonePlayer implements CoreStartable {
            }
            throw new SecurityException("Uri is not ringtone, alarm, or notification: " + uri);
        }
    };

        /**
         * Must be called from the Binder calling thread.
         * Ensures caller is from the same userId as the content they're trying to access.
         *
         * @param uri         the URI to check
     * @throws SecurityException when in a non-system call and userId in uri differs from the
         * @param clientToken the Client token used for the current query, null if not available
         *                    in the query (expected from calls other than the play* methods)
         * @throws SecurityException when in a non-system call and userId in uri differs
         *                           from the
         *                           caller's userId
         */
    private void enforceUriUserId(Uri uri) throws SecurityException {
        private void enforceUriUserId(Uri uri, @Nullable IBinder clientToken)
                throws SecurityException {
            final int uriUserId = ContentProvider.getUserIdFromUri(uri, UserHandle.myUserId());
            // for a non-system call, verify the URI to play belongs to the same user as the caller
        if (UserHandle.isApp(Binder.getCallingUid()) && (UserHandle.myUserId() != uriUserId)) {
            final String errorMessage = "Illegal access to uri=" + uri
            final int uid = Binder.getCallingUid();
            final int pid = Binder.getCallingPid();
            if (UserHandle.isApp(uid) && (UserHandle.myUserId() != uriUserId)) {
                final String errorMessage = "Illegal access by uid:" + uid + " pid:" + pid
                        + " to uri=" + uri
                        + " content associated with user=" + uriUserId
                    + ", current userID: " + UserHandle.myUserId();
                        + ", current userID=" + UserHandle.myUserId();
                if (android.media.audio.Flags.ringtoneUserUriCheck()) {
                    if (clientToken != null) {
                        // this client is accessing URIs it shouldn't access, stop it (which also
                        // removes it from mClients in the outer class)
                        stop(clientToken);
                    }
                    throw new SecurityException(errorMessage);
                } else {
                    Log.e(TAG, errorMessage, new Exception());
                }
            }
        }
    };

    private Context getContextForUser(UserHandle user) {
        try {