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

Commit bd278015 authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Do not verify APKs out of updated APEXs

For APK-in-APEX the system is not aware of the pre-installed APKs. Hence
the currently installed APK always shows up as "factory-installed APK".

For factory installed APKs we enforce that all privilidged perissions
are manually whitelisted.

If an APK-in-APEX gets updated the app might request additional
privilidged permissions. We now explicity allow this.

This change leaves all apex specific logic inside of ApexMgr. E.g.
- how to figure out if a pkg is a apk-in-apex
- how apexPkgs are marked as factory/updated

Fixes: 148853593
Test: Built a new APK-In-APEX that contained new priv permission,
      installed it and rebooted -> no crash, but permission was not granted
Change-Id: I254e5189909efdafe3dc0ca8a5ab5a520457c585
parent 9541b091
Loading
Loading
Loading
Loading
+69 −16
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@@ -74,7 +75,7 @@ public abstract class ApexManager {

    private static final String TAG = "ApexManager";

    static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
    public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
    static final int MATCH_FACTORY_PACKAGE = 1 << 1;

    private static final Singleton<ApexManager> sApexManagerSingleton =
@@ -163,7 +164,7 @@ public abstract class ApexManager {
     *         is not found.
     */
    @Nullable
    abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
    public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);

    /**
     * Retrieves information about all active APEX packages.
@@ -197,6 +198,27 @@ public abstract class ApexManager {
     */
    abstract boolean isApexPackage(String packageName);

    /**
     * Whether the APEX package is pre-installed or not.
     *
     * @param packageInfo the package to check
     * @return {@code true} if this package is pre-installed, {@code false} otherwise.
     */
    public static boolean isFactory(@NonNull PackageInfo packageInfo) {
        return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
    }

    /**
     * Returns the active apex package's name that contains the (apk) package.
     *
     * @param containedPackage The (apk) package that might be in a apex
     * @return the apex package's name of {@code null} if the {@code containedPackage} is not inside
     *         any apex.
     */
    @Nullable
    public abstract String getActiveApexPackageNameContainingPackage(
            @NonNull AndroidPackage containedPackage);

    /**
     * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
     * track the different states of a session.
@@ -351,7 +373,7 @@ public abstract class ApexManager {
         * difference between {@code packageName} and {@code apexModuleName}.
         */
        @GuardedBy("mLock")
        private Map<String, List<String>> mApksInApex = new ArrayMap<>();
        private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>();

        @GuardedBy("mLock")
        private List<PackageInfo> mAllPackagesCache;
@@ -366,7 +388,7 @@ public abstract class ApexManager {
         * the apk container to {@code apexModuleName} of the apex-payload inside.
         */
        @GuardedBy("mLock")
        private Map<String, String> mPackageNameToApexModuleName;
        private ArrayMap<String, String> mPackageNameToApexModuleName;

        ApexManagerImpl(IApexService apexService) {
            mApexService = apexService;
@@ -382,16 +404,6 @@ public abstract class ApexManager {
            return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
        }

        /**
         * Whether the APEX package is pre-installed or not.
         *
         * @param packageInfo the package to check
         * @return {@code true} if this package is pre-installed, {@code false} otherwise.
         */
        private static boolean isFactory(PackageInfo packageInfo) {
            return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
        }

        @Override
        public List<ActiveApexInfo> getActiveApexInfos() {
            final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
@@ -503,7 +515,9 @@ public abstract class ApexManager {
        }

        @Override
        @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
        @Nullable
        public PackageInfo getPackageInfo(String packageName,
                @PackageInfoFlags int flags) {
            Preconditions.checkState(mAllPackagesCache != null,
                    "APEX packages have not been scanned");
            boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
@@ -563,6 +577,36 @@ public abstract class ApexManager {
            return false;
        }

        @Override
        @Nullable
        public String getActiveApexPackageNameContainingPackage(
                @NonNull AndroidPackage containedPackage) {
            Preconditions.checkState(mPackageNameToApexModuleName != null,
                    "APEX packages have not been scanned");

            Objects.requireNonNull(containedPackage);

            synchronized (mLock) {
                int numApksInApex = mApksInApex.size();
                for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) {
                    if (mApksInApex.valueAt(apkInApexNum).contains(
                            containedPackage.getPackageName())) {
                        String apexModuleName = mApksInApex.keyAt(apkInApexNum);

                        int numApexPkgs = mPackageNameToApexModuleName.size();
                        for (int apexPkgNum = 0; apexPkgNum < numApexPkgs; apexPkgNum++) {
                            if (mPackageNameToApexModuleName.valueAt(apexPkgNum).equals(
                                    apexModuleName)) {
                                return mPackageNameToApexModuleName.keyAt(apexPkgNum);
                            }
                        }
                    }
                }
            }

            return null;
        }

        @Override
        @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
            try {
@@ -893,7 +937,7 @@ public abstract class ApexManager {
        }

        @Override
        PackageInfo getPackageInfo(String packageName, int flags) {
        public PackageInfo getPackageInfo(String packageName, int flags) {
            return null;
        }

@@ -917,6 +961,15 @@ public abstract class ApexManager {
            return false;
        }

        @Override
        @Nullable
        public String getActiveApexPackageNameContainingPackage(
                @NonNull AndroidPackage containedPackage) {
            Objects.requireNonNull(containedPackage);

            return null;
        }

        @Override
        ApexSessionInfo getStagedSessionInfo(int sessionId) {
            throw new UnsupportedOperationException();
+12 −2
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;

import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE;
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
@@ -128,6 +129,7 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
import com.android.server.pm.ApexManager;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting;
import com.android.server.pm.SharedUserSetting;
@@ -3321,8 +3323,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged()
                && !platformPackage && platformPermission) {
            if (!hasPrivappWhitelistEntry(perm, pkg)) {
                // Only report violations for apps on system image
                if (!mSystemReady && !pkgSetting.getPkgState().isUpdatedSystemApp()) {
                ApexManager apexMgr = ApexManager.getInstance();
                String apexContainingPkg = apexMgr.getActiveApexPackageNameContainingPackage(pkg);

                // Only enforce whitelist this on boot
                if (!mSystemReady
                        // Updated system apps do not need to be whitelisted
                        && !pkgSetting.getPkgState().isUpdatedSystemApp()
                        // Apps that are in updated apexs' do not need to be whitelisted
                        && (apexContainingPkg == null || apexMgr.isFactory(
                        apexMgr.getPackageInfo(apexContainingPkg, MATCH_ACTIVE_PACKAGE)))) {
                    // it's only a reportable violation if the permission isn't explicitly denied
                    ArraySet<String> deniedPermissions = null;
                    if (pkg.isVendor()) {