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

Commit 9f370ba4 authored by Andrei-Valentin Onea's avatar Andrei-Valentin Onea Committed by Automerger Merge Worker
Browse files

Merge "Allow privapp permission allowlist in apex" am: e978ec5b am: 1c565d5b

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1766011

Change-Id: If9cc15759bead022245f08b02ffd3475160bee78
parents 218b1d80 1c565d5b
Loading
Loading
Loading
Loading
+68 −6
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -95,6 +96,9 @@ public class SystemConfig {
    // property for runtime configuration differentiation in vendor
    private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";

    private static final ArrayMap<String, ArraySet<String>> EMPTY_PERMISSIONS =
            new ArrayMap<>();

    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
    int[] mGlobalGids = EmptyArray.INT;

@@ -224,6 +228,11 @@ public class SystemConfig {
    final ArrayMap<String, ArraySet<String>> mSystemExtPrivAppPermissions = new ArrayMap<>();
    final ArrayMap<String, ArraySet<String>> mSystemExtPrivAppDenyPermissions = new ArrayMap<>();

    final ArrayMap<String, ArrayMap<String, ArraySet<String>>> mApexPrivAppPermissions =
            new ArrayMap<>();
    final ArrayMap<String, ArrayMap<String, ArraySet<String>>> mApexPrivAppDenyPermissions =
            new ArrayMap<>();

    final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();

    // Allowed associations between applications.  If there are any entries
@@ -360,6 +369,18 @@ public class SystemConfig {
        return mPrivAppDenyPermissions.get(packageName);
    }

    /** Get privapp permission allowlist for an apk-in-apex. */
    public ArraySet<String> getApexPrivAppPermissions(String module, String packageName) {
        return mApexPrivAppPermissions.getOrDefault(module, EMPTY_PERMISSIONS)
                .get(packageName);
    }

    /** Get privapp permissions denylist for an apk-in-apex. */
    public ArraySet<String> getApexPrivAppDenyPermissions(String module, String packageName) {
        return mApexPrivAppDenyPermissions.getOrDefault(module, EMPTY_PERMISSIONS)
                .get(packageName);
    }

    public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
        return mVendorPrivAppPermissions.get(packageName);
    }
@@ -573,8 +594,8 @@ public class SystemConfig {
        if (!isSystemProcess()) {
            return;
        }
        // Read configuration of features and libs from apex module.
        int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES;
        // Read configuration of features, libs and priv-app permissions from apex module.
        int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
        // TODO: Use a solid way to filter apex module folders?
        for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
            if (f.isFile() || f.getPath().contains("@")) {
@@ -1040,10 +1061,10 @@ public class SystemConfig {
                    } break;
                    case "privapp-permissions": {
                        if (allowPrivappPermissions) {
                            // privapp permissions from system, vendor, product and system_ext
                            // partitions are stored separately. This is to prevent xml files in
                            // the vendor partition from granting permissions to priv apps in the
                            // system partition and vice versa.
                            // privapp permissions from system, apex, vendor, product and
                            // system_ext partitions are stored separately. This is to
                            // prevent xml files in the vendor partition from granting
                            // permissions to priv apps in the system partition and vice versa.
                            boolean vendor = permFile.toPath().startsWith(
                                    Environment.getVendorDirectory().toPath() + "/")
                                    || permFile.toPath().startsWith(
@@ -1052,6 +1073,8 @@ public class SystemConfig {
                                    Environment.getProductDirectory().toPath() + "/");
                            boolean systemExt = permFile.toPath().startsWith(
                                    Environment.getSystemExtDirectory().toPath() + "/");
                            boolean apex = permFile.toPath().startsWith(
                                    Environment.getApexDirectory().toPath() + "/");
                            if (vendor) {
                                readPrivAppPermissions(parser, mVendorPrivAppPermissions,
                                        mVendorPrivAppDenyPermissions);
@@ -1061,6 +1084,8 @@ public class SystemConfig {
                            } else if (systemExt) {
                                readPrivAppPermissions(parser, mSystemExtPrivAppPermissions,
                                        mSystemExtPrivAppDenyPermissions);
                            } else if (apex) {
                                readApexPrivAppPermissions(parser, permFile);
                            } else {
                                readPrivAppPermissions(parser, mPrivAppPermissions,
                                        mPrivAppDenyPermissions);
@@ -1616,6 +1641,43 @@ public class SystemConfig {
        }
    }


    /**
     * Returns the module name for a file in the apex module's partition.
     */
    private String getApexModuleNameFromFilePath(Path path) {
        final Path apexDirectoryPath = Environment.getApexDirectory().toPath();
        if (!path.startsWith(apexDirectoryPath)) {
            throw new IllegalArgumentException("File " + path + " is not part of an APEX.");
        }
        // File must be in <apex_directory>/<module_name>/[extra_paths/]<xml_file>
        if (path.getNameCount() <= (apexDirectoryPath.getNameCount() + 1)) {
            throw new IllegalArgumentException("File " + path + " is in the APEX partition,"
                                                + " but not inside a module.");
        }
        return path.getName(apexDirectoryPath.getNameCount()).toString();
    }

    private void readApexPrivAppPermissions(XmlPullParser parser, File permFile)
            throws IOException, XmlPullParserException {
        final String moduleName = getApexModuleNameFromFilePath(permFile.toPath());
        final ArrayMap<String, ArraySet<String>> privAppPermissions;
        if (mApexPrivAppPermissions.containsKey(moduleName)) {
            privAppPermissions = mApexPrivAppPermissions.get(moduleName);
        } else {
            privAppPermissions = new ArrayMap<>();
            mApexPrivAppPermissions.put(moduleName, privAppPermissions);
        }
        final ArrayMap<String, ArraySet<String>> privAppDenyPermissions;
        if (mApexPrivAppDenyPermissions.containsKey(moduleName)) {
            privAppDenyPermissions = mApexPrivAppDenyPermissions.get(moduleName);
        } else {
            privAppDenyPermissions = new ArrayMap<>();
            mApexPrivAppDenyPermissions.put(moduleName, privAppDenyPermissions);
        }
        readPrivAppPermissions(parser, privAppPermissions, privAppDenyPermissions);
    }

    private static boolean isSystemProcess() {
        return Process.myUid() == Process.SYSTEM_UID;
    }
+15 −0
Original line number Diff line number Diff line
@@ -2438,6 +2438,15 @@ class PackageManagerShellCommand extends ShellCommand {
        }
    }

    private String getApexPackageNameContainingPackage(String pkg) {
        ApexManager apexManager = ApexManager.getInstance();
        return apexManager.getActiveApexPackageNameContainingPackage(pkg);
    }

    private boolean isApexApp(String pkg) {
        return getApexPackageNameContainingPackage(pkg) != null;
    }

    private int runGetPrivappPermissions() {
        final String pkg = getNextArg();
        if (pkg == null) {
@@ -2453,6 +2462,9 @@ class PackageManagerShellCommand extends ShellCommand {
        } else if (isSystemExtApp(pkg)) {
            privAppPermissions = SystemConfig.getInstance()
                    .getSystemExtPrivAppPermissions(pkg);
        } else if (isApexApp(pkg)) {
            privAppPermissions = SystemConfig.getInstance()
                    .getApexPrivAppPermissions(getApexPackageNameContainingPackage(pkg), pkg);
        } else {
            privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
        }
@@ -2477,6 +2489,9 @@ class PackageManagerShellCommand extends ShellCommand {
        } else if (isSystemExtApp(pkg)) {
            privAppPermissions = SystemConfig.getInstance()
                    .getSystemExtPrivAppDenyPermissions(pkg);
        } else if (isApexApp(pkg)) {
            privAppPermissions = SystemConfig.getInstance()
                    .getApexPrivAppDenyPermissions(getApexPackageNameContainingPackage(pkg), pkg);
        } else {
            privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
        }
+32 −7
Original line number Diff line number Diff line
@@ -3454,10 +3454,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            return true;
        }
        final String permissionName = permission.getName();
        if (isInSystemConfigPrivAppPermissions(pkg, permissionName)) {
        final ApexManager apexManager = ApexManager.getInstance();
        final String containingApexPackageName =
                apexManager.getActiveApexPackageNameContainingPackage(packageName);
        if (isInSystemConfigPrivAppPermissions(pkg, permissionName,
                containingApexPackageName)) {
            return true;
        }
        if (isInSystemConfigPrivAppDenyPermissions(pkg, permissionName)) {
        if (isInSystemConfigPrivAppDenyPermissions(pkg, permissionName,
                containingApexPackageName)) {
            return false;
        }
        // Updated system apps do not need to be allowlisted
@@ -3474,9 +3479,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
        }
        // Only enforce the allowlist on boot
        if (!mSystemReady) {
            final ApexManager apexManager = ApexManager.getInstance();
            final String containingApexPackageName =
                    apexManager.getActiveApexPackageNameContainingPackage(packageName);
            final boolean isInUpdatedApex = containingApexPackageName != null
                    && !apexManager.isFactory(apexManager.getPackageInfo(containingApexPackageName,
                    MATCH_ACTIVE_PACKAGE));
@@ -3500,7 +3502,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
    }

    private boolean isInSystemConfigPrivAppPermissions(@NonNull AndroidPackage pkg,
            @NonNull String permission) {
            @NonNull String permission, String containingApexPackageName) {
        final SystemConfig systemConfig = SystemConfig.getInstance();
        final Set<String> permissions;
        if (pkg.isVendor()) {
@@ -3509,6 +3511,26 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            permissions = systemConfig.getProductPrivAppPermissions(pkg.getPackageName());
        } else if (pkg.isSystemExt()) {
            permissions = systemConfig.getSystemExtPrivAppPermissions(pkg.getPackageName());
        } else if (containingApexPackageName != null) {
            final Set<String> privAppPermissions = systemConfig.getPrivAppPermissions(
                    pkg.getPackageName());
            final Set<String> apexPermissions = systemConfig.getApexPrivAppPermissions(
                    containingApexPackageName, pkg.getPackageName());
            if (privAppPermissions != null) {
                // TODO(andreionea): Remove check as soon as all apk-in-apex
                // permission allowlists are migrated.
                Slog.w(TAG, "Package " + pkg.getPackageName() + " is an APK in APEX,"
                        + " but has permission allowlist on the system image. Please bundle the"
                        + " allowlist in the " + containingApexPackageName + " APEX instead.");
                if (apexPermissions != null) {
                    permissions = new ArraySet<>(privAppPermissions);
                    permissions.addAll(apexPermissions);
                } else {
                    permissions = privAppPermissions;
                }
            } else {
                permissions = apexPermissions;
            }
        } else {
            permissions = systemConfig.getPrivAppPermissions(pkg.getPackageName());
        }
@@ -3516,7 +3538,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
    }

    private boolean isInSystemConfigPrivAppDenyPermissions(@NonNull AndroidPackage pkg,
            @NonNull String permission) {
            @NonNull String permission, String containingApexPackageName) {
        final SystemConfig systemConfig = SystemConfig.getInstance();
        final Set<String> permissions;
        if (pkg.isVendor()) {
@@ -3525,6 +3547,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
            permissions = systemConfig.getProductPrivAppDenyPermissions(pkg.getPackageName());
        } else if (pkg.isSystemExt()) {
            permissions = systemConfig.getSystemExtPrivAppDenyPermissions(pkg.getPackageName());
        } else if (containingApexPackageName != null) {
            permissions = systemConfig.getApexPrivAppDenyPermissions(containingApexPackageName,
                    pkg.getPackageName());
        } else {
            permissions = systemConfig.getPrivAppDenyPermissions(pkg.getPackageName());
        }