Allow privapp permission allowlist in apex
Read priv-app permission allowlists from APEX file and warn if they're in the /system partition instead. Test: boots Bug: 190375768 Change-Id: I37d6deb60f0dffb75dd634075cd95bcf7ddf9684 Merged-In: I37d6deb60f0dffb75dd634075cd95bcf7ddf9684
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -3443,10 +3443,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
|
||||
@@ -3463,9 +3468,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));
|
||||
@@ -3489,7 +3491,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()) {
|
||||
@@ -3498,6 +3500,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());
|
||||
}
|
||||
@@ -3505,7 +3527,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()) {
|
||||
@@ -3514,6 +3536,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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user