Protect TelecomManager#getPhoneAccount with necessary permission.
Apps targeting API version 31+ should have READ_PHONE_NUMBERS to call
method getPhoneAccount.
Bug: 183407956
Test: UnitTest, CTS test
Change-Id: I60c37687d8ee0b04129f0393a19e0fd4961990e5
(cherry picked from commit 11a19742d03d766567f281dcf31e4efa5b4d636b)
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 9a683ad..6fb2897 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -317,9 +317,21 @@
}
@Override
- public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle) {
+ public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle,
+ String callingPackage) {
synchronized (mLock) {
final UserHandle callingUserHandle = Binder.getCallingUserHandle();
+ if (CompatChanges.isChangeEnabled(
+ TelecomManager.ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION,
+ callingPackage, Binder.getCallingUserHandle())) {
+ if (Binder.getCallingUid() != Process.SHELL_UID &&
+ !canGetPhoneAccount(callingPackage, accountHandle)) {
+ SecurityException e = new SecurityException("getPhoneAccount API requires" +
+ "READ_PHONE_NUMBERS");
+ Log.e(this, e, "getPhoneAccount %s", accountHandle);
+ throw e;
+ }
+ }
long token = Binder.clearCallingIdentity();
try {
Log.startSession("TSI.gPA");
@@ -329,7 +341,7 @@
// profile's phone account handle.
return mPhoneAccountRegistrar
.getPhoneAccount(accountHandle, callingUserHandle,
- /* acrossProfiles */ true);
+ /* acrossProfiles */ true);
} catch (Exception e) {
Log.e(this, e, "getPhoneAccount %s", accountHandle);
throw e;
@@ -2422,6 +2434,28 @@
== AppOpsManager.MODE_ALLOWED;
}
+ private boolean canGetPhoneAccount(String callingPackage, PhoneAccountHandle accountHandle) {
+ // Allow default dialer, system dialer and sim call manager to be able to do this without
+ // extra permission
+ try {
+ if (isPrivilegedDialerCalling(callingPackage) || isCallerSimCallManager(
+ accountHandle)) {
+ return true;
+ }
+ } catch (SecurityException e) {
+ // ignore
+ }
+
+ try {
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, null);
+ return true;
+ } catch (SecurityException e) {
+ // Accessing phone state is gated by a special permission.
+ mContext.enforceCallingOrSelfPermission(READ_PHONE_NUMBERS, null);
+ return true;
+ }
+ }
+
private boolean isCallerSimCallManager(PhoneAccountHandle targetPhoneAccount) {
long token = Binder.clearCallingIdentity();
PhoneAccountHandle accountHandle = null;
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index caaf4d6..60d38af 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -39,6 +39,10 @@
<!-- Used to access Projection State APIs -->
<uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
+ <!-- Used to access PlatformCompat APIs -->
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+
<application android:label="@string/app_name"
android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index fa8ab10..3cec50b 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -460,10 +460,10 @@
@Test
public void testGetPhoneAccount() throws RemoteException {
makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
- assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16)
- .getAccountHandle());
- assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17)
- .getAccountHandle());
+ assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16,
+ mContext.getPackageName()).getAccountHandle());
+ assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17,
+ mContext.getPackageName()).getAccountHandle());
}
@SmallTest