Allow provisioning package to retrieve subGrp, clear it's own config

This changes the VCN to allow a VCN provisioning package to retrieve
its listing of configured subgroups and clear its own configurations,
regardless of whether it is the active subscription group.

Safety is guaranteed based on the VCN's clearing of packages when app
data is cleared, and when the app is uninstalled. In addition to the
configurations not being retrievable, the clearing of the configs will
ensure that sideloading of an app with the same package name provides
no ability to otherwise impact settings.

Bug: 227248744
Test: atest FrameworksVcnTests
Change-Id: I2c774c00373942f895169a761d4e9a1d5b0b2edb
This commit is contained in:
Benedict Wong
2022-03-29 01:01:03 +00:00
parent 7c37904142
commit 1a8f3e0a14
3 changed files with 228 additions and 53 deletions

View File

@@ -65,6 +65,7 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
import android.net.Uri;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
@@ -114,18 +115,24 @@ import java.util.UUID;
public class VcnManagementServiceTest {
private static final String TEST_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName();
private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2";
private static final String TEST_CB_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName() + ".callback";
private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2));
private static final VcnConfig TEST_VCN_CONFIG;
private static final VcnConfig TEST_VCN_CONFIG_PKG_2;
private static final int TEST_UID = Process.FIRST_APPLICATION_UID;
static {
final Context mockConfigContext = mock(Context.class);
doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext);
doReturn(TEST_PACKAGE_NAME_2).when(mockConfigContext).getOpPackageName();
TEST_VCN_CONFIG_PKG_2 = VcnConfigTest.buildTestConfig(mockConfigContext);
}
private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP =
@@ -246,18 +253,24 @@ public class VcnManagementServiceTest {
eq(android.Manifest.permission.NETWORK_FACTORY), any());
}
private void setupMockedCarrierPrivilege(boolean isPrivileged) {
setupMockedCarrierPrivilege(isPrivileged, TEST_PACKAGE_NAME);
}
private void setupMockedCarrierPrivilege(boolean isPrivileged, String pkg) {
doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
.when(mSubMgr)
.getSubscriptionsInGroup(any());
doReturn(mTelMgr)
.when(mTelMgr)
.createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
doReturn(isPrivileged
? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
: CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
doReturn(
isPrivileged
? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
: CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
.when(mTelMgr)
.checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME));
.checkCarrierPrivilegesForPackage(eq(pkg));
}
@Test
@@ -414,7 +427,13 @@ public class VcnManagementServiceTest {
private BroadcastReceiver getPackageChangeReceiver() {
final ArgumentCaptor<BroadcastReceiver> captor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any());
verify(mMockContext).registerReceiver(captor.capture(), argThat(filter -> {
return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
&& filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
&& filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
&& filter.hasAction(Intent.ACTION_PACKAGE_DATA_CLEARED)
&& filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
}), any(), any());
return captor.getValue();
}
@@ -538,6 +557,44 @@ public class VcnManagementServiceTest {
verify(mSubscriptionTracker).handleSubscriptionsChanged();
}
@Test
public void testPackageChangeListener_packageDataCleared() throws Exception {
triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1);
final BroadcastReceiver receiver = getPackageChangeReceiver();
assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME));
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID));
receiver.onReceive(mMockContext, intent);
mTestLooper.dispatchAll();
verify(vcn).teardownAsynchronously();
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
}
@Test
public void testPackageChangeListener_packageFullyRemoved() throws Exception {
triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1);
final BroadcastReceiver receiver = getPackageChangeReceiver();
assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
final Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED);
intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME));
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID));
receiver.onReceive(mMockContext, intent);
mTestLooper.dispatchAll();
verify(vcn).teardownAsynchronously();
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
}
@Test
public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
@@ -578,7 +635,7 @@ public class VcnManagementServiceTest {
@Test
public void testSetVcnConfigMismatchedPackages() throws Exception {
try {
mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage");
mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME_2);
fail("Expected exception due to mismatched packages in config and method call");
} catch (IllegalArgumentException expected) {
verify(mMockPolicyListener, never()).onPolicyChanged();
@@ -678,11 +735,12 @@ public class VcnManagementServiceTest {
}
@Test
public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception {
public void testClearVcnConfigRequiresCarrierPrivilegesOrProvisioningPackage()
throws Exception {
setupMockedCarrierPrivilege(false);
try {
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
fail("Expected security exception for missing carrier privileges");
} catch (SecurityException expected) {
}
@@ -691,19 +749,31 @@ public class VcnManagementServiceTest {
@Test
public void testClearVcnConfigMismatchedPackages() throws Exception {
try {
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage");
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
fail("Expected security exception due to mismatched packages");
} catch (SecurityException expected) {
}
}
@Test
public void testClearVcnConfig() throws Exception {
public void testClearVcnConfig_callerIsProvisioningPackage() throws Exception {
// Lose carrier privileges to test that provisioning package is sufficient.
setupMockedCarrierPrivilege(false);
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
}
@Test
public void testClearVcnConfig_callerIsCarrierPrivileged() throws Exception {
setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2);
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
}
@Test
public void testClearVcnConfigNotifiesStatusCallback() throws Exception {
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */);
@@ -755,11 +825,12 @@ public class VcnManagementServiceTest {
@Test
public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception {
final String badPackage = "IncorrectPackage";
doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage);
doThrow(new SecurityException())
.when(mAppOpsMgr)
.checkPackage(TEST_UID, TEST_PACKAGE_NAME_2);
try {
mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage);
mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME_2);
fail("Expected security exception due to mismatched packages");
} catch (SecurityException expected) {
}
@@ -767,14 +838,16 @@ public class VcnManagementServiceTest {
@Test
public void testGetConfiguredSubscriptionGroups() throws Exception {
setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2);
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
mVcnMgmtSvc.setVcnConfig(TEST_UUID_3, TEST_VCN_CONFIG_PKG_2, TEST_PACKAGE_NAME_2);
// Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are
// privileged for.
// Assert that if UUIDs 1, 2 and 3 are provisioned, the caller only gets ones that they are
// privileged for, or are the provisioning package of.
triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
final List<ParcelUuid> subGrps =
mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
assertEquals(Collections.singletonList(TEST_UUID_1), subGrps);
assertEquals(Arrays.asList(new ParcelUuid[] {TEST_UUID_1, TEST_UUID_2}), subGrps);
}
@Test