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

Commit 4bab9e28 authored by Valentin Iftime's avatar Valentin Iftime
Browse files

Check for NLS service intent filter when rebinding services

 Also, after updating packages with NLS components, check
 the approved services and remove from approved list if missing the NLS service intent filter.

Flag: EXEMPT security fix
Test: atest ManagedServicesTest
Bug: 347674739
Change-Id: I6ba585d123fbe88cbff2011b62f02774dd1efda5
parent eb4760c4
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -950,7 +950,7 @@ abstract public class ManagedServices {
                || isPackageOrComponentAllowed(component.getPackageName(), userId))) {
            return false;
        }
        return componentHasBindPermission(component, userId);
        return isValidService(component, userId);
    }

    private boolean componentHasBindPermission(ComponentName component, int userId) {
@@ -1302,11 +1302,12 @@ abstract public class ManagedServices {
                    if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
                        final ComponentName component = ComponentName.unflattenFromString(
                                approvedPackageOrComponent);
                        if (component != null && !componentHasBindPermission(component, userId)) {
                        if (component != null && !isValidService(component, userId)) {
                            approved.removeAt(j);
                            if (DEBUG) {
                                Slog.v(TAG, "Removing " + approvedPackageOrComponent
                                        + " from approved list; no bind permission found "
                                        + " from approved list; no bind permission or "
                                        + "service interface filter found "
                                        + mConfig.bindPermission);
                            }
                        }
@@ -1325,6 +1326,11 @@ abstract public class ManagedServices {
        }
    }

    protected boolean isValidService(ComponentName component, int userId) {
        return componentHasBindPermission(component, userId) && queryPackageForServices(
                component.getPackageName(), userId).contains(component);
    }

    protected boolean isValidEntry(String packageOrComponent, int userId) {
        return hasMatchingServices(packageOrComponent, userId);
    }
+100 −9
Original line number Diff line number Diff line
@@ -888,7 +888,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
            return true;
        });

        mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
        mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
        service.addApprovedList("a", 0, true);

        service.reregisterService(cn, 0);
@@ -919,7 +919,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
            return true;
        });

        mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
        mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
        service.addApprovedList("a", 0, false);

        service.reregisterService(cn, 0);
@@ -950,7 +950,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
            return true;
        });

        mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
        mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
        service.addApprovedList("a/a", 0, true);

        service.reregisterService(cn, 0);
@@ -981,7 +981,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
            return true;
        });

        mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
        mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
        service.addApprovedList("a/a", 0, false);

        service.reregisterService(cn, 0);
@@ -1210,6 +1210,64 @@ public class ManagedServicesTest extends UiServiceTestCase {
        assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
    }

    @Test
    public void testUpgradeAppNoIntentFilterNoRebind() throws Exception {
        Context context = spy(getContext());
        doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());

        ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
                mIpm, APPROVAL_BY_COMPONENT);

        List<String> packages = new ArrayList<>();
        packages.add("package");
        addExpectedServices(service, packages, 0);

        final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
        final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");

        // Both components are approved initially
        mExpectedPrimaryComponentNames.clear();
        mExpectedPrimaryPackages.clear();
        mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
        mExpectedSecondaryComponentNames.clear();
        mExpectedSecondaryPackages.clear();

        loadXml(service);

        //Component package/C1 loses serviceInterface intent filter
        ManagedServices.Config config = service.getConfig();
        when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).
            thenAnswer(new Answer<List<ResolveInfo>>() {
                @Override
                public List<ResolveInfo> answer(InvocationOnMock invocationOnMock)
                    throws Throwable {
                    Object[] args = invocationOnMock.getArguments();
                    Intent invocationIntent = (Intent) args[0];
                    if (invocationIntent != null) {
                        if (invocationIntent.getAction().equals(config.serviceInterface)
                            && packages.contains(invocationIntent.getPackage())) {
                            List<ResolveInfo> dummyServices = new ArrayList<>();
                            ResolveInfo resolveInfo = new ResolveInfo();
                            ServiceInfo serviceInfo = new ServiceInfo();
                            serviceInfo.packageName = invocationIntent.getPackage();
                            serviceInfo.name = approvedComponent.getClassName();
                            serviceInfo.permission = service.getConfig().bindPermission;
                            resolveInfo.serviceInfo = serviceInfo;
                            dummyServices.add(resolveInfo);
                            return dummyServices;
                        }
                    }
                    return new ArrayList<>();
                }
            });

        // Trigger package update
        service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});

        assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent));
        assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
    }

    @Test
    public void testSetPackageOrComponentEnabled() throws Exception {
        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
@@ -1915,7 +1973,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
        metaDataAutobindAllow.putBoolean(META_DATA_DEFAULT_AUTOBIND, true);
        metaDatas.put(cn_allowed, metaDataAutobindAllow);

        mockServiceInfoWithMetaData(componentNames, service, metaDatas);
        mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);

        service.addApprovedList(cn_allowed.flattenToString(), 0, true);
        service.addApprovedList(cn_disallowed.flattenToString(), 0, true);
@@ -1960,7 +2018,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
        metaDataAutobindDisallow.putBoolean(META_DATA_DEFAULT_AUTOBIND, false);
        metaDatas.put(cn_disallowed, metaDataAutobindDisallow);

        mockServiceInfoWithMetaData(componentNames, service, metaDatas);
        mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);

        service.addApprovedList(cn_disallowed.flattenToString(), 0, true);

@@ -1999,7 +2057,7 @@ public class ManagedServicesTest extends UiServiceTestCase {
        metaDataAutobindDisallow.putBoolean(META_DATA_DEFAULT_AUTOBIND, false);
        metaDatas.put(cn_disallowed, metaDataAutobindDisallow);

        mockServiceInfoWithMetaData(componentNames, service, metaDatas);
        mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);

        service.addApprovedList(cn_disallowed.flattenToString(), 0, true);

@@ -2070,8 +2128,8 @@ public class ManagedServicesTest extends UiServiceTestCase {
    }

    private void mockServiceInfoWithMetaData(List<ComponentName> componentNames,
            ManagedServices service, ArrayMap<ComponentName, Bundle> metaDatas)
            throws RemoteException {
            ManagedServices service, PackageManager packageManager,
            ArrayMap<ComponentName, Bundle> metaDatas) throws RemoteException {
        when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
                (Answer<ServiceInfo>) invocation -> {
                    ComponentName invocationCn = invocation.getArgument(0);
@@ -2086,6 +2144,39 @@ public class ManagedServicesTest extends UiServiceTestCase {
                    return null;
                }
        );

        // add components to queryIntentServicesAsUser response
        final List<String> packages = new ArrayList<>();
        for (ComponentName cn: componentNames) {
            packages.add(cn.getPackageName());
        }
        ManagedServices.Config config = service.getConfig();
        when(packageManager.queryIntentServicesAsUser(any(), anyInt(), anyInt())).
                thenAnswer(new Answer<List<ResolveInfo>>() {
                @Override
                public List<ResolveInfo> answer(InvocationOnMock invocationOnMock)
                    throws Throwable {
                    Object[] args = invocationOnMock.getArguments();
                    Intent invocationIntent = (Intent) args[0];
                    if (invocationIntent != null) {
                        if (invocationIntent.getAction().equals(config.serviceInterface)
                            && packages.contains(invocationIntent.getPackage())) {
                            List<ResolveInfo> dummyServices = new ArrayList<>();
                            for (ComponentName cn: componentNames) {
                                ResolveInfo resolveInfo = new ResolveInfo();
                                ServiceInfo serviceInfo = new ServiceInfo();
                                serviceInfo.packageName = invocationIntent.getPackage();
                                serviceInfo.name = cn.getClassName();
                                serviceInfo.permission = service.getConfig().bindPermission;
                                resolveInfo.serviceInfo = serviceInfo;
                                dummyServices.add(resolveInfo);
                            }
                            return dummyServices;
                        }
                    }
                    return new ArrayList<>();
                }
            });
    }

    private void resetComponentsAndPackages() {