summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andrei Onea <andreionea@google.com> 2021-07-14 17:38:45 +0100
committer Andrei Onea <andreionea@google.com> 2021-12-03 18:19:00 +0000
commit95ecac506dba532636f0a2f8f56b64a9914b0d6a (patch)
tree6fccbb8f03dd8c6fefc07c00af46c82c9c70e0b2
parent8d221843b767e18c04c82bb972c8bbdfd459742b (diff)
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
-rw-r--r--core/java/com/android/server/SystemConfig.java74
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java15
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java39
3 files changed, 115 insertions, 13 deletions
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index b0cf5dcbbfd5..ae9d71610aaa 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -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;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1aa80a953d6c..5b4084e9b229 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -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);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7b12709e4efd..f733a2e0bb3f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -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());
}