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

Commit d7a2c1c2 authored by Todd Kennedy's avatar Todd Kennedy
Browse files

Filter instant <--> full app

Last in the series for protecting full apps from instant apps. Still
need to make another pass at the opposite direction.

Bug: 35871369
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.EphemeralTest
Test: Manual; install instant app and ensure it runs
Change-Id: I3734cb154e7b952f3a9cf7c5415dffcd4de02aba
parent 7210f130
Loading
Loading
Loading
Loading
+159 −57
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCES
import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -300,6 +301,8 @@ import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.security.DigestInputStream;
import java.security.MessageDigest;
@@ -438,6 +441,21 @@ public class PackageManagerService extends IPackageManager.Stub
    private static final int[] EMPTY_INT_ARRAY = new int[0];
    private static final int TYPE_UNKNOWN = 0;
    private static final int TYPE_ACTIVITY = 1;
    private static final int TYPE_RECEIVER = 2;
    private static final int TYPE_SERVICE = 3;
    private static final int TYPE_PROVIDER = 4;
    @IntDef(prefix = { "TYPE_" }, value = {
            TYPE_UNKNOWN,
            TYPE_ACTIVITY,
            TYPE_RECEIVER,
            TYPE_SERVICE,
            TYPE_PROVIDER,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ComponentType {}
    /**
     * Timeout (in milliseconds) after which the watchdog should declare that
     * our handler thread is wedged.  The usual default for such things is one
@@ -3527,26 +3545,9 @@ public class PackageManagerService extends IPackageManager.Stub
        //     and 2) ephemeral apps that have explicitly interacted with it
        //   * Ephemeral apps can only see their own data and exposed installed apps
        //   * Holding a signature permission allows seeing instant apps
        if (!canAccessInstantApps(callingUid)) {
            final String instantAppPackageName = getInstantAppPackageName(callingUid);
            if (instantAppPackageName != null) {
                // ephemeral apps can only get information on themselves or
                // installed apps that are exposed.
                if (!instantAppPackageName.equals(p.packageName)
                        && (ps.getInstantApp(userId) || !p.visibleToInstantApps)) {
                    return null;
                }
            } else {
                if (ps.getInstantApp(userId)) {
                    // only get access to the ephemeral app if we've been granted access
                    final int callingAppId = UserHandle.getAppId(callingUid);
                    if (!mInstantAppRegistry.isInstantAccessGranted(
                            userId, callingAppId, ps.appId)) {
        if (filterAppAccessLPr(ps, callingUid, userId)) {
            return null;
        }
                }
            }
        }
        final PermissionsState permissionsState = ps.getPermissionsState();
@@ -3705,6 +3706,47 @@ public class PackageManagerService extends IPackageManager.Stub
        return null;
    }
    private boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
        if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) {
            return true;
        }
        if (isComponentVisibleToInstantApp(component, TYPE_SERVICE)) {
            return true;
        }
        if (isComponentVisibleToInstantApp(component, TYPE_PROVIDER)) {
            return true;
        }
        return false;
    }
    private boolean isComponentVisibleToInstantApp(
            @Nullable ComponentName component, @ComponentType int type) {
        if (type == TYPE_ACTIVITY) {
            final PackageParser.Activity activity = mActivities.mActivities.get(component);
            return activity != null
                    ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
                    : false;
        } else if (type == TYPE_RECEIVER) {
            final PackageParser.Activity activity = mReceivers.mActivities.get(component);
            return activity != null
                    ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
                    : false;
        } else if (type == TYPE_SERVICE) {
            final PackageParser.Service service = mServices.mServices.get(component);
            return service != null
                    ? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
                    : false;
        } else if (type == TYPE_PROVIDER) {
            final PackageParser.Provider provider = mProviders.mProviders.get(component);
            return provider != null
                    ? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
                    : false;
        } else if (type == TYPE_UNKNOWN) {
            return isComponentVisibleToInstantApp(component);
        }
        return false;
    }
    /**
     * Returns whether or not access to the application should be filtered.
     * <p>
@@ -3714,7 +3756,7 @@ public class PackageManagerService extends IPackageManager.Stub
     * @see #canAccessInstantApps(int)
     */
    private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid,
            @Nullable ComponentName component, boolean componentVisibleToInstantApp, int userId) {
            @Nullable ComponentName component, @ComponentType int componentType, int userId) {
        // if we're in an isolated process, get the real calling UID
        if (Process.isIsolated(callingUid)) {
            callingUid = mIsolatedOwners.get(callingUid);
@@ -3735,10 +3777,10 @@ public class PackageManagerService extends IPackageManager.Stub
        if (callerIsInstantApp) {
            // request for a specific component; if it hasn't been explicitly exposed, filter
            if (component != null) {
                return !componentVisibleToInstantApp;
                return !isComponentVisibleToInstantApp(component, componentType);
            }
            // request for application; if no components have been explicitly exposed, filter
            return !ps.pkg.visibleToInstantApps;
            return ps.getInstantApp(userId) || !ps.pkg.visibleToInstantApps;
        }
        if (ps.getInstantApp(userId)) {
            // caller can see all components of all instant applications, don't filter
@@ -3760,7 +3802,7 @@ public class PackageManagerService extends IPackageManager.Stub
     * @see #filterAppAccessLPr(PackageSetting, int, ComponentName, boolean, int)
     */
    private boolean filterAppAccessLPr(@Nullable PackageSetting ps, int callingUid, int userId) {
        return filterAppAccessLPr(ps, callingUid, null, false, userId);
        return filterAppAccessLPr(ps, callingUid, null, TYPE_UNKNOWN, userId);
    }
    private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
@@ -4412,9 +4454,7 @@ public class PackageManagerService extends IPackageManager.Stub
            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                if (ps == null) return null;
                final boolean visibleToInstantApp =
                        (a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
                if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
                if (filterAppAccessLPr(ps, callingUid, component, TYPE_ACTIVITY, userId)) {
                    return null;
                }
                return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
@@ -4445,9 +4485,7 @@ public class PackageManagerService extends IPackageManager.Stub
            if (ps == null) {
                return false;
            }
            final boolean visibleToInstantApp =
                    (a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
            if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, callingUserId)) {
            if (filterAppAccessLPr(ps, callingUid, component, TYPE_ACTIVITY, callingUserId)) {
                return false;
            }
            for (int i=0; i<a.intents.size(); i++) {
@@ -4463,8 +4501,9 @@ public class PackageManagerService extends IPackageManager.Stub
    @Override
    public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
        if (!sUserManager.exists(userId)) return null;
        final int callingUid = Binder.getCallingUid();
        flags = updateFlagsForComponent(flags, userId, component);
        enforceCrossUserPermission(Binder.getCallingUid(), userId,
        enforceCrossUserPermission(callingUid, userId,
                false /* requireFullPermission */, false /* checkShell */, "get receiver info");
        synchronized (mPackages) {
            PackageParser.Activity a = mReceivers.mActivities.get(component);
@@ -4473,6 +4512,9 @@ public class PackageManagerService extends IPackageManager.Stub
            if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                if (ps == null) return null;
                if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) {
                    return null;
                }
                return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
            }
        }
@@ -4606,9 +4648,7 @@ public class PackageManagerService extends IPackageManager.Stub
            if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                if (ps == null) return null;
                final boolean visibleToInstantApp =
                        (s.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
                if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
                if (filterAppAccessLPr(ps, callingUid, component, TYPE_SERVICE, userId)) {
                    return null;
                }
                ServiceInfo si = PackageParser.generateServiceInfo(s, flags,
@@ -4636,9 +4676,7 @@ public class PackageManagerService extends IPackageManager.Stub
            if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                if (ps == null) return null;
                final boolean visibleToInstantApp =
                        (p.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
                if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
                if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
                    return null;
                }
                ProviderInfo pi = PackageParser.generateProviderInfo(p, flags,
@@ -7553,6 +7591,7 @@ public class PackageManagerService extends IPackageManager.Stub
            String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        final int callingUid = Binder.getCallingUid();
        final String instantAppPkgName = getInstantAppPackageName(callingUid);
        flags = updateFlagsForResolve(flags, userId, intent, callingUid,
                false /*includeInstantApps*/);
        ComponentName comp = intent.getComponent();
@@ -7563,26 +7602,61 @@ public class PackageManagerService extends IPackageManager.Stub
            }
        }
        if (comp != null) {
            List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
            ActivityInfo ai = getReceiverInfo(comp, flags, userId);
            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
            final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
            if (ai != null) {
                // When specifying an explicit component, we prevent the activity from being
                // used when either 1) the calling package is normal and the activity is within
                // an instant application or 2) the calling package is ephemeral and the
                // activity is not visible to instant applications.
                final boolean matchInstantApp =
                        (flags & PackageManager.MATCH_INSTANT) != 0;
                final boolean matchVisibleToInstantAppOnly =
                        (flags & PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY) != 0;
                final boolean matchExplicitlyVisibleOnly =
                        (flags & PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY) != 0;
                final boolean isCallerInstantApp =
                        instantAppPkgName != null;
                final boolean isTargetSameInstantApp =
                        comp.getPackageName().equals(instantAppPkgName);
                final boolean isTargetInstantApp =
                        (ai.applicationInfo.privateFlags
                                & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0;
                final boolean isTargetVisibleToInstantApp =
                        (ai.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
                final boolean isTargetExplicitlyVisibleToInstantApp =
                        isTargetVisibleToInstantApp
                        && (ai.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
                final boolean isTargetHiddenFromInstantApp =
                        !isTargetVisibleToInstantApp
                        || (matchExplicitlyVisibleOnly && !isTargetExplicitlyVisibleToInstantApp);
                final boolean blockResolution =
                        !isTargetSameInstantApp
                        && ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
                                || (matchVisibleToInstantAppOnly && isCallerInstantApp
                                        && isTargetHiddenFromInstantApp));
                if (!blockResolution) {
                    ResolveInfo ri = new ResolveInfo();
                    ri.activityInfo = ai;
                    list.add(ri);
                }
            return list;
            }
            return applyPostResolutionFilter(list, instantAppPkgName);
        }
        // reader
        synchronized (mPackages) {
            String pkgName = intent.getPackage();
            if (pkgName == null) {
                return mReceivers.queryIntent(intent, resolvedType, flags, userId);
                final List<ResolveInfo> result =
                        mReceivers.queryIntent(intent, resolvedType, flags, userId);
                return applyPostResolutionFilter(result, instantAppPkgName);
            }
            final PackageParser.Package pkg = mPackages.get(pkgName);
            if (pkg != null) {
                return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
                        userId);
                final List<ResolveInfo> result = mReceivers.queryIntentForPackage(
                        intent, resolvedType, flags, pkg.receivers, userId);
                return applyPostResolutionFilter(result, instantAppPkgName);
            }
            return Collections.emptyList();
        }
@@ -8263,11 +8337,11 @@ public class PackageManagerService extends IPackageManager.Stub
    @Override
    public @NonNull ParceledListSlice<ProviderInfo> queryContentProviders(String processName,
            int uid, int flags, String metaDataKey) {
        final int callingUid = Binder.getCallingUid();
        final int userId = processName != null ? UserHandle.getUserId(uid)
                : UserHandle.getCallingUserId();
        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
        flags = updateFlagsForComponent(flags, userId, processName);
        ArrayList<ProviderInfo> finalList = null;
        // reader
        synchronized (mPackages) {
@@ -8287,7 +8361,11 @@ public class PackageManagerService extends IPackageManager.Stub
                            && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) {
                        continue;
                    }
                    final ComponentName component =
                            new ComponentName(p.info.packageName, p.info.name);
                    if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
                        continue;
                    }
                    if (finalList == null) {
                        finalList = new ArrayList<ProviderInfo>(3);
                    }
@@ -8309,10 +8387,17 @@ public class PackageManagerService extends IPackageManager.Stub
    }
    @Override
    public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) {
    public InstrumentationInfo getInstrumentationInfo(ComponentName component, int flags) {
        // reader
        synchronized (mPackages) {
            final PackageParser.Instrumentation i = mInstrumentation.get(name);
            final int callingUid = Binder.getCallingUid();
            final int callingUserId = UserHandle.getUserId(callingUid);
            final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
            if (ps == null) return null;
            if (filterAppAccessLPr(ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) {
                return null;
            }
            final PackageParser.Instrumentation i = mInstrumentation.get(component);
            return PackageParser.generateInstrumentationInfo(i, flags);
        }
    }
@@ -8320,6 +8405,12 @@ public class PackageManagerService extends IPackageManager.Stub
    @Override
    public @NonNull ParceledListSlice<InstrumentationInfo> queryInstrumentation(
            String targetPackage, int flags) {
        final int callingUid = Binder.getCallingUid();
        final int callingUserId = UserHandle.getUserId(callingUid);
        final PackageSetting ps = mSettings.mPackages.get(targetPackage);
        if (filterAppAccessLPr(ps, callingUid, callingUserId)) {
            return ParceledListSlice.emptyList();
        }
        return new ParceledListSlice<>(queryInstrumentationInternal(targetPackage, flags));
    }
@@ -9106,9 +9197,17 @@ public class PackageManagerService extends IPackageManager.Stub
    @Override
    public void notifyPackageUse(String packageName, int reason) {
        synchronized (mPackages) {
            if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
            final int callingUid = Binder.getCallingUid();
            final int callingUserId = UserHandle.getUserId(callingUid);
            if (getInstantAppPackageName(callingUid) != null) {
                if (!isCallerSameApp(packageName, callingUid)) {
                    return;
                }
            } else {
                if (isInstantApp(packageName, callingUserId)) {
                    return;
                }
            }
            final PackageParser.Package p = mPackages.get(packageName);
            if (p == null) {
                return;
@@ -20993,14 +21092,17 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
    }
    @Override
    public int getComponentEnabledSetting(ComponentName componentName, int userId) {
    public int getComponentEnabledSetting(ComponentName component, int userId) {
        if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
        int uid = Binder.getCallingUid();
        enforceCrossUserPermission(uid, userId,
                false /* requireFullPermission */, false /* checkShell */, "get component enabled");
        // reader
        int callingUid = Binder.getCallingUid();
        enforceCrossUserPermission(callingUid, userId,
                false /*requireFullPermission*/, false /*checkShell*/, "getComponentEnabled");
        synchronized (mPackages) {
            return mSettings.getComponentEnabledSettingLPr(componentName, userId);
            if (filterAppAccessLPr(mSettings.getPackageLPr(component.getPackageName()), callingUid,
                    component, TYPE_UNKNOWN, userId)) {
                return COMPONENT_ENABLED_STATE_DISABLED;
            }
            return mSettings.getComponentEnabledSettingLPr(component, userId);
        }
    }