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

Commit 5df72432 authored by Leland Miller's avatar Leland Miller
Browse files

Check permissions in RcsMessageStoreController

Test: atest CtsRcsTestCases
Change-Id: If5f9ce6c6a9f1117b8709ea745a0c78566601bb2
parent 1cca3682
Loading
Loading
Loading
Loading
+550 −388

File changed.

Preview size limit exceeded, changes collapsed.

+61 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony.ims;

import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.os.Binder;

class RcsPermissions {
    static void checkReadPermissions(Context context, String callingPackage) {
        int pid = Binder.getCallingPid();
        int uid = Binder.getCallingUid();

        context.enforcePermission(Manifest.permission.READ_SMS, pid, uid, null);

        checkOp(context, uid, callingPackage, AppOpsManager.OP_READ_SMS);
    }

    static void checkWritePermissions(Context context, String callingPackage) {
        int uid = Binder.getCallingUid();

        checkOp(context, uid, callingPackage, AppOpsManager.OP_WRITE_SMS);
    }

    /**
     * Notes the provided op, but throws even if the op mode is {@link AppOpsManager.MODE_IGNORED}.
     * <p>
     * {@link AppOpsManager.OP_WRITE_SMS} defaults to {@link AppOpsManager.MODE_IGNORED} to avoid
     * crashing applications written before the app op was introduced. Since this is a new API,
     * consumers should be aware of the permission requirements, and we should be safe to throw a
     * {@link SecurityException} instead of providing a dummy value (which could cause unexpected
     * application behavior and possible loss of user data). {@link AppOpsManager.OP_READ_SMS} is
     * not normally in {@link AppOpsManager.MODE_IGNORED}, but we maintain the same behavior for
     * consistency with handling of write permissions.
     */
    private static void checkOp(Context context, int uid, String callingPackage, int op) {
        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);

        int mode = appOps.noteOp(op, uid, callingPackage);

        if (mode != AppOpsManager.MODE_ALLOWED) {
            throw new SecurityException(
                    AppOpsManager.opToName(op) + " not allowed for " + callingPackage);
        }
    }
}
+21 −16
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import static org.mockito.Mockito.doReturn;
import android.content.ContentValues;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.Telephony;
import android.provider.Telephony.RcsColumns.RcsParticipantColumns;
import android.telephony.ims.RcsParticipant;
@@ -65,7 +64,7 @@ public class RcsMessageStoreControllerTest extends TelephonyTest {
        mContentResolver = (MockContentResolver) mContext.getContentResolver();
        mContentResolver.addProvider("rcs", mFakeRcsProvider);

        mRcsMessageStoreController = new RcsMessageStoreController(mContentResolver);
        mRcsMessageStoreController = new RcsMessageStoreController(mContext);
    }

    @After
@@ -85,14 +84,14 @@ public class RcsMessageStoreControllerTest extends TelephonyTest {
                Uri.parse("content://rcs/thread"), null, null, null, null, null));

        try {
            mRcsMessageStoreController.getRcsThreads(queryParameters);
        } catch (RemoteException e) {
            mRcsMessageStoreController.getRcsThreads(queryParameters, getPackageName());
        } catch (RuntimeException e) {
            // eat the exception as there is no provider - we care about the expected update assert
        }
    }

    @Test
    public void testCreateRcsParticipant() throws RemoteException {
    public void testCreateRcsParticipant() {
        String canonicalAddress = "+5551234567";

        // verify the first query to canonical addresses
@@ -118,7 +117,8 @@ public class RcsMessageStoreControllerTest extends TelephonyTest {
                Uri.parse("content://rcs/participant/1001")));

        int participantId =
                mRcsMessageStoreController.createRcsParticipant(canonicalAddress, "alias");
                mRcsMessageStoreController.createRcsParticipant(canonicalAddress, "alias",
                        getPackageName());

        assertThat(participantId).isEqualTo(1001);
    }
@@ -131,8 +131,8 @@ public class RcsMessageStoreControllerTest extends TelephonyTest {
                Uri.parse("content://rcs/participant/551"), null, null, contentValues, 0));

        try {
            mRcsMessageStoreController.setRcsParticipantAlias(551, "New Alias");
        } catch (RemoteException e) {
            mRcsMessageStoreController.setRcsParticipantAlias(551, "New Alias", getPackageName());
        } catch (RuntimeException e) {
            // eat the exception as there is no provider - we care about the expected update assert
        }
    }
@@ -144,8 +144,8 @@ public class RcsMessageStoreControllerTest extends TelephonyTest {
        mFakeRcsProvider.addExpectedOperation(new ExpectedUpdate(
                Uri.parse("content://rcs/p2p_thread/123"), null, null, contentValues, 0));
        try {
            mRcsMessageStoreController.set1To1ThreadFallbackThreadId(123, 456L);
        } catch (RemoteException e) {
            mRcsMessageStoreController.set1To1ThreadFallbackThreadId(123, 456L, getPackageName());
        } catch (RuntimeException e) {
            // eat the exception as there is no provider - we care about the expected update assert
        }
    }
@@ -158,8 +158,8 @@ public class RcsMessageStoreControllerTest extends TelephonyTest {
                Uri.parse("content://rcs/group_thread/345"), null, null, contentValues, 0));

        try {
            mRcsMessageStoreController.setGroupThreadName(345, "new name");
        } catch (RemoteException e) {
            mRcsMessageStoreController.setGroupThreadName(345, "new name", getPackageName());
        } catch (RuntimeException e) {
            // eat the exception as there is no provider - we care about the expected update assert
        }
    }
@@ -172,8 +172,9 @@ public class RcsMessageStoreControllerTest extends TelephonyTest {
                Uri.parse("content://rcs/group_thread/345"), null, null, contentValues, 0));

        try {
            mRcsMessageStoreController.setGroupThreadIcon(345, Uri.parse("newIcon"));
        } catch (RemoteException e) {
            mRcsMessageStoreController.setGroupThreadIcon(345, Uri.parse("newIcon"),
                    getPackageName());
        } catch (RuntimeException e) {
            // eat the exception as there is no provider - we care about the expected update assert
        }
    }
@@ -186,9 +187,13 @@ public class RcsMessageStoreControllerTest extends TelephonyTest {
                Uri.parse("content://rcs/group_thread/454"), null, null, contentValues, 0));

        try {
            mRcsMessageStoreController.setGroupThreadOwner(454, 9);
        } catch (RemoteException e) {
            mRcsMessageStoreController.setGroupThreadOwner(454, 9, getPackageName());
        } catch (RuntimeException e) {
            // eat the exception as there is no provider - we care about the expected update assert
        }
    }

    private String getPackageName() {
        return mContext.getOpPackageName();
    }
}