From 002fdbdb950ebbf40331a27de33b80db33e40d30 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 13 Feb 2017 20:50:31 +0900 Subject: Support privileged vendor apps Privileged apps can now be located in the vendor partition. This is mainly to move SoC-dependent apks to the vendor partition so that the system partition becomes more generic. Like existing privileged apps in the system partition, the list of privileged apps in the vendor partition and the permissions they are using must be white-listed. The whitelist can be specified via tags in one of /vendor/etc/permissions/*.xml files. Note: vendors can only white-list the apps in vendor partition, but not the apps in system partition. This change also introduces a new flag 'vendor-privileged' to the permission protection level. It is used to expose platform-defined permissions to the privileged vendor apps. If a platform permission does not have this flag, it is not granted to vendor apps even when the app is privileged and white-listed. Bug: 35301609 Test: `mm` under frameworks/base/tests/privapp-permissions adb sync && adb reboot adb shell cmd package \ com.android.framework.permission.privapp.tests.vendor shows that the app is installed. android.permission.BIND_IMS_SERVICE is in the installed permissions list android.permission.MANAGE_USE is not in the installed permissions list, but is in the requested permissions list. Change-Id: I196375aaaa9ea3a2ba15686ef08cf3f70ade7046 --- core/java/android/app/LoadedApk.java | 3 +- core/java/android/content/pm/ApplicationInfo.java | 13 +++ core/java/android/content/pm/PackageParser.java | 5 + core/java/android/content/pm/PermissionInfo.java | 18 ++++ core/java/com/android/server/SystemConfig.java | 40 +++++-- core/res/res/values/attrs_manifest.xml | 3 + .../android/server/pm/PackageManagerService.java | 84 +++++++++++++-- .../server/pm/PackageManagerShellCommand.java | 26 ++++- .../java/com/android/server/pm/PackageSetting.java | 4 + .../java/com/android/server/pm/SettingBase.java | 1 + .../core/java/com/android/server/pm/Settings.java | 3 + .../server/pm/permission/BasePermission.java | 3 + .../pm/permission/PermissionManagerService.java | 24 ++++- .../server/pm/PackageManagerPresubmitTest.java | 115 --------------------- tests/privapp-permissions/Android.mk | 31 ++++++ .../privapp-permissions/system/AndroidManifest.xml | 23 +++++ .../system/privapp-permissions-test.xml | 6 ++ .../privapp-permissions/vendor/AndroidManifest.xml | 25 +++++ .../vendor/privapp-permissions-test.xml | 7 ++ 19 files changed, 292 insertions(+), 142 deletions(-) delete mode 100644 services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java create mode 100644 tests/privapp-permissions/Android.mk create mode 100644 tests/privapp-permissions/system/AndroidManifest.xml create mode 100644 tests/privapp-permissions/system/privapp-permissions-test.xml create mode 100644 tests/privapp-permissions/vendor/AndroidManifest.xml create mode 100644 tests/privapp-permissions/vendor/privapp-permissions-test.xml diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index f6d9710dae69..de6230cf825a 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -638,8 +638,7 @@ public final class LoadedApk { final String defaultSearchPaths = System.getProperty("java.library.path"); final boolean treatVendorApkAsUnbundled = !defaultSearchPaths.contains("/vendor/lib"); if (mApplicationInfo.getCodePath() != null - && mApplicationInfo.getCodePath().startsWith("/vendor/") - && treatVendorApkAsUnbundled) { + && mApplicationInfo.isVendor() && treatVendorApkAsUnbundled) { isBundledApp = false; } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index edb27cd4ecf1..5298f57b4ef2 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -594,6 +594,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_OEM = 1 << 17; + /** + * Value for {@linl #privateFlags}: whether this app is pre-installed on the + * vendor partition of the system image. + * @hide + */ + public static final int PRIVATE_FLAG_VENDOR = 1 << 18; + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -613,6 +620,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_PRIVILEGED, PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, PRIVATE_FLAG_STATIC_SHARED_LIBRARY, + PRIVATE_FLAG_VENDOR, PRIVATE_FLAG_VIRTUAL_PRELOAD, }) @Retention(RetentionPolicy.SOURCE) @@ -1569,6 +1577,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } + /** @hide */ + public boolean isVendor() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + } + /** * Returns whether or not this application was installed as a virtual preload. */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index ebeaad78ea6a..98c824dbf8f6 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -6266,6 +6266,11 @@ public class PackageParser { return applicationInfo.isOem(); } + /** @hide */ + public boolean isVendor() { + return applicationInfo.isVendor(); + } + /** @hide */ public boolean isPrivileged() { return applicationInfo.isPrivilegedApp(); diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index 75887624eef3..551d53b631cd 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -143,6 +143,15 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { @SystemApi public static final int PROTECTION_FLAG_OEM = 0x4000; + /** + * Additional flag for {${link #protectionLevel}, corresponding + * to the vendorPrivileged value of + * {@link android.R.attr#protectionLevel}. + * + * @hide + */ + public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 0x8000; + /** * Mask for {@link #protectionLevel}: the basic protection type. */ @@ -231,6 +240,12 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { if (level == PROTECTION_SIGNATURE_OR_SYSTEM) { level = PROTECTION_SIGNATURE | PROTECTION_FLAG_PRIVILEGED; } + if ((level & PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0 + && (level & PROTECTION_FLAG_PRIVILEGED) == 0) { + // 'vendorPrivileged' must be 'privileged'. If not, + // drop the vendorPrivileged. + level = level & ~PROTECTION_FLAG_VENDOR_PRIVILEGED; + } return level; } @@ -284,6 +299,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { if ((level & PermissionInfo.PROTECTION_FLAG_OEM) != 0) { protLevel += "|oem"; } + if ((level & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0) { + protLevel += "|vendorPrivileged"; + } return protLevel; } diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index b5031f23918f..b7a67192f01f 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -146,6 +146,9 @@ public class SystemConfig { final ArrayMap> mPrivAppPermissions = new ArrayMap<>(); final ArrayMap> mPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap> mVendorPrivAppPermissions = new ArrayMap<>(); + final ArrayMap> mVendorPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap> mOemPermissions = new ArrayMap<>(); public static SystemConfig getInstance() { @@ -229,6 +232,14 @@ public class SystemConfig { return mPrivAppDenyPermissions.get(packageName); } + public ArraySet getVendorPrivAppPermissions(String packageName) { + return mVendorPrivAppPermissions.get(packageName); + } + + public ArraySet getVendorPrivAppDenyPermissions(String packageName) { + return mVendorPrivAppDenyPermissions.get(packageName); + } + public Map getOemPermissions(String packageName) { final Map oemPermissions = mOemPermissions.get(packageName); if (oemPermissions != null) { @@ -248,7 +259,7 @@ public class SystemConfig { // Allow Vendor to customize system configs around libs, features, permissions and apps int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS | - ALLOW_APP_CONFIGS; + ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS; readPermissions(Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag); readPermissions(Environment.buildPath( @@ -587,7 +598,19 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) { - readPrivAppPermissions(parser); + // privapp permissions from system and vendor 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()); + if (vendor) { + readPrivAppPermissions(parser, mVendorPrivAppPermissions, + mVendorPrivAppDenyPermissions); + } else { + readPrivAppPermissions(parser, mPrivAppPermissions, + mPrivAppDenyPermissions); + } } else if ("oem-permissions".equals(name) && allowOemPermissions) { readOemPermissions(parser); } else { @@ -674,7 +697,10 @@ public class SystemConfig { } } - void readPrivAppPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { + private void readPrivAppPermissions(XmlPullParser parser, + ArrayMap> grantMap, + ArrayMap> denyMap) + throws IOException, XmlPullParserException { String packageName = parser.getAttributeValue(null, "package"); if (TextUtils.isEmpty(packageName)) { Slog.w(TAG, "package is required for in " @@ -682,11 +708,11 @@ public class SystemConfig { return; } - ArraySet permissions = mPrivAppPermissions.get(packageName); + ArraySet permissions = grantMap.get(packageName); if (permissions == null) { permissions = new ArraySet<>(); } - ArraySet denyPermissions = mPrivAppDenyPermissions.get(packageName); + ArraySet denyPermissions = denyMap.get(packageName); int depth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, depth)) { String name = parser.getName(); @@ -711,9 +737,9 @@ public class SystemConfig { denyPermissions.add(permName); } } - mPrivAppPermissions.put(packageName, permissions); + grantMap.put(packageName, permissions); if (denyPermissions != null) { - mPrivAppDenyPermissions.put(packageName, denyPermissions); + denyMap.put(packageName, denyPermissions); } } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 4d410e5447de..4d67494be21d 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -262,6 +262,9 @@ and the OEM has white-listed the app to receive this permission by the OEM. --> + + diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2d5f7c7124c4..b34de7140b6b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -467,6 +467,7 @@ public class PackageManagerService extends IPackageManager.Stub static final int SCAN_AS_SYSTEM = 1<<17; static final int SCAN_AS_PRIVILEGED = 1<<18; static final int SCAN_AS_OEM = 1<<19; + static final int SCAN_AS_VENDOR = 1<<20; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -2574,8 +2575,25 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM, 0); - // Collect all vendor packages. - File vendorAppDir = new File("/vendor/app"); + // Collected privileged vendor packages. + File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), + "priv-app"); + try { + privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(privilegedVendorAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_VENDOR + | SCAN_AS_PRIVILEGED, + 0); + + // Collect ordinary vendor packages. + File vendorAppDir = new File(Environment.getVendorDirectory(), "app"); try { vendorAppDir = vendorAppDir.getCanonicalFile(); } catch (IOException e) { @@ -2585,7 +2603,8 @@ public class PackageManagerService extends IPackageManager.Stub mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags - | SCAN_AS_SYSTEM, + | SCAN_AS_SYSTEM + | SCAN_AS_VENDOR, 0); // Collect all OEM packages. @@ -2770,13 +2789,23 @@ public class PackageManagerService extends IPackageManager.Stub rescanFlags = scanFlags | SCAN_AS_SYSTEM; + } else if (FileUtils.contains(privilegedVendorAppDir, scanFile)) { + reparseFlags = + mDefParseFlags | + PackageParser.PARSE_IS_SYSTEM_DIR; + rescanFlags = + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_VENDOR + | SCAN_AS_PRIVILEGED; } else if (FileUtils.contains(vendorAppDir, scanFile)) { reparseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR; rescanFlags = scanFlags - | SCAN_AS_SYSTEM; + | SCAN_AS_SYSTEM + | SCAN_AS_VENDOR; } else if (FileUtils.contains(oemAppDir, scanFile)) { reparseFlags = mDefParseFlags | @@ -8335,6 +8364,13 @@ public class PackageManagerService extends IPackageManager.Stub } else { updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_OEM; } + // If new package is not located in "/vendor" (e.g. due to an OTA), + // it needs to drop FLAG_VENDOR. + if (locationIsVendor(pkg.codePath)) { + updatedPs.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR; + } else { + updatedPs.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VENDOR; + } if (ps != null && !ps.codePathString.equals(pkg.codePath)) { // The path has changed from what was last scanned... check the @@ -8455,11 +8491,17 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags |= SCAN_AS_PRIVILEGED; } - // An updated OEM app will not have the PARSE_IS_OEM + // An updated OEM app will not have the SCAN_AS_OEM // flag set initially if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0) { scanFlags |= SCAN_AS_OEM; } + + // An updated vendor app will not have the SCAN_AS_VENDOR + // flag set initially + if ((updatedPs.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) { + scanFlags |= SCAN_AS_VENDOR; + } } // Verify certificates against what was last scanned @@ -10208,6 +10250,10 @@ public class PackageManagerService extends IPackageManager.Stub pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM; } + if ((scanFlags & SCAN_AS_VENDOR) != 0) { + pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR; + } + if (!isSystemApp(pkg)) { // Only system apps can use these features. pkg.mOriginalPackages = null; @@ -15574,18 +15620,22 @@ public class PackageManagerService extends IPackageManager.Stub boolean sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { - // Set the system/privileged/oem flags as needed + // Set the system/privileged/oem/vendor flags as needed final boolean privileged = (oldPackage.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; final boolean oem = (oldPackage.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; + final boolean vendor = + (oldPackage.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; final @ParseFlags int systemParseFlags = parseFlags; final @ScanFlags int systemScanFlags = scanFlags | SCAN_AS_SYSTEM | (privileged ? SCAN_AS_PRIVILEGED : 0) - | (oem ? SCAN_AS_OEM : 0); + | (oem ? SCAN_AS_OEM : 0) + | (vendor ? SCAN_AS_VENDOR : 0); replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags, user, allUsers, installerPackageName, res, installReason); @@ -16759,6 +16809,10 @@ public class PackageManagerService extends IPackageManager.Stub return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; } + private static boolean isVendorApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + } + private static boolean hasDomainURLs(PackageParser.Package pkg) { return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; } @@ -17493,7 +17547,9 @@ public class PackageManagerService extends IPackageManager.Stub static boolean locationIsPrivileged(String path) { try { final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); - return path.startsWith(privilegedAppDir.getCanonicalPath()); + final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); + return path.startsWith(privilegedAppDir.getCanonicalPath()) + || path.startsWith(privilegedVendorAppDir.getCanonicalPath()); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); } @@ -17509,6 +17565,15 @@ public class PackageManagerService extends IPackageManager.Stub return false; } + static boolean locationIsVendor(String path) { + try { + return path.startsWith(Environment.getVendorDirectory().getCanonicalPath()); + } catch (IOException e) { + Slog.e(TAG, "Unable to access code path " + path); + } + return false; + } + /* * Tries to delete system package. */ @@ -17630,6 +17695,9 @@ public class PackageManagerService extends IPackageManager.Stub if (locationIsOem(codePathString)) { scanFlags |= SCAN_AS_OEM; } + if (locationIsVendor(codePathString)) { + scanFlags |= SCAN_AS_VENDOR; + } final File codePath = new File(codePathString); final PackageParser.Package pkg = diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 44f36d1734c8..45b94a468514 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1538,13 +1538,26 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } + private boolean isVendorApp(String pkg) { + try { + final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM); + return info != null && info.applicationInfo.isVendor(); + } catch (RemoteException e) { + return false; + } + } + private int runGetPrivappPermissions() { final String pkg = getNextArg(); if (pkg == null) { getErrPrintWriter().println("Error: no package specified."); return 1; } - ArraySet privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg); + + ArraySet privAppPermissions = isVendorApp(pkg) ? + SystemConfig.getInstance().getVendorPrivAppPermissions(pkg) + : SystemConfig.getInstance().getPrivAppPermissions(pkg); + getOutPrintWriter().println(privAppPermissions == null ? "{}" : privAppPermissions.toString()); return 0; @@ -1556,10 +1569,13 @@ class PackageManagerShellCommand extends ShellCommand { getErrPrintWriter().println("Error: no package specified."); return 1; } - ArraySet privAppDenyPermissions = - SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); - getOutPrintWriter().println(privAppDenyPermissions == null - ? "{}" : privAppDenyPermissions.toString()); + + ArraySet privAppPermissions = isVendorApp(pkg) ? + SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg) + : SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); + + getOutPrintWriter().println(privAppPermissions == null + ? "{}" : privAppPermissions.toString()); return 0; } diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 3b414e9a0dc5..258dd4d4dcb3 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -140,6 +140,10 @@ public final class PackageSetting extends PackageSettingBase { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; } + public boolean isVendor() { + return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + } + public boolean isForwardLocked() { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; } diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index c97f5e5443a3..46ba0060d93e 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -61,6 +61,7 @@ abstract class SettingBase { this.pkgPrivateFlags = pkgPrivateFlags & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED | ApplicationInfo.PRIVATE_FLAG_OEM + | ApplicationInfo.PRIVATE_FLAG_VENDOR | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index ddad6774871d..af1a4d148856 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -847,6 +847,8 @@ public final class Settings { pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM; + pkgSetting.pkgPrivateFlags |= + pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR; pkgSetting.primaryCpuAbiString = primaryCpuAbi; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; if (childPkgNames != null) { @@ -4421,6 +4423,7 @@ public final class Settings { ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED", ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER", ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY", + ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR", ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD", }; diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index 8c86db64471d..75a61064c1c9 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -225,6 +225,9 @@ public final class BasePermission { public boolean isVerifier() { return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0; } + public boolean isVendorPrivileged() { + return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VENDOR_PRIVILEGED) != 0; + } public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) { if (!origPackageName.equals(sourcePackageName)) { 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 7d8e20696aff..90ac4ab7dd42 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -959,8 +959,9 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); *

This handles parent/child apps. */ private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) { - ArraySet wlPermissions = SystemConfig.getInstance() - .getPrivAppPermissions(pkg.packageName); + ArraySet wlPermissions = pkg.isVendor() ? + SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName) + : SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName); // Let's check if this package is whitelisted... boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm); // If it's not, we'll also tail-recurse to the parent. @@ -971,7 +972,8 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); private boolean grantSignaturePermission(String perm, PackageParser.Package pkg, BasePermission bp, PermissionsState origPermissions) { boolean oemPermission = bp.isOEM(); - boolean privilegedPermission = bp.isPrivileged(); + boolean vendorPrivilegedPermission = bp.isVendorPrivileged(); + boolean privilegedPermission = bp.isPrivileged() || bp.isVendorPrivileged(); boolean privappPermissionsDisable = RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE; boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName()); @@ -982,8 +984,11 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); // Only report violations for apps on system image if (!mSystemReady && !pkg.isUpdatedSystemApp()) { // it's only a reportable violation if the permission isn't explicitly denied - final ArraySet deniedPermissions = SystemConfig.getInstance() - .getPrivAppDenyPermissions(pkg.packageName); + final ArraySet deniedPermissions = pkg.isVendor() ? + SystemConfig.getInstance() + .getVendorPrivAppDenyPermissions(pkg.packageName) + : SystemConfig.getInstance() + .getPrivAppDenyPermissions(pkg.packageName); final boolean permissionViolation = deniedPermissions == null || !deniedPermissions.contains(perm); if (permissionViolation) { @@ -1086,6 +1091,15 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); || (oemPermission && pkg.isOem() && canGrantOemPermission(ps, perm)); } + // In any case, don't grant a privileged permission to privileged vendor apps, if + // the permission's protectionLevel does not have the extra 'vendorPrivileged' + // flag. + if (allowed && privilegedPermission && + !vendorPrivilegedPermission && pkg.isVendor()) { + Slog.w(TAG, "Permission " + perm + " cannot be granted to privileged vendor apk " + + pkg.packageName + " because it isn't a 'vendorPrivileged' permission."); + allowed = false; + } } } if (!allowed) { diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java deleted file mode 100644 index e6b4540f73c9..000000000000 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.pm; - -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PermissionInfo; -import android.platform.test.annotations.GlobalPresubmit; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.util.ArraySet; - -import com.android.internal.os.RoSystemProperties; -import com.android.internal.util.ArrayUtils; -import com.android.server.SystemConfig; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.List; - -import static android.content.pm.PackageManager.GET_PERMISSIONS; -import static junit.framework.Assert.assertTrue; - - -/** - * Presubmit tests for {@link PackageManager}. - */ -@RunWith(AndroidJUnit4.class) -public class PackageManagerPresubmitTest { - - private Context mContext; - - private PackageManager mPackageManager; - - @Before - public void setUp() { - mContext = InstrumentationRegistry.getContext(); - mPackageManager = mContext.getPackageManager(); - } - - /** - *

This test ensures that all signature|privileged permissions are granted to priv-apps. - * If CONTROL_PRIVAPP_PERMISSIONS_ENFORCE is set, the test also verifies that - * granted permissions are whitelisted in {@link SystemConfig} - */ - @Test - @SmallTest - @GlobalPresubmit - public void testPrivAppPermissions() throws PackageManager.NameNotFoundException { - List installedPackages = mPackageManager - .getInstalledPackages(PackageManager.MATCH_UNINSTALLED_PACKAGES | GET_PERMISSIONS); - for (PackageInfo packageInfo : installedPackages) { - if (!packageInfo.applicationInfo.isPrivilegedApp() - || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(packageInfo.packageName)) { - continue; - } - testPackagePrivAppPermission(packageInfo); - } - - } - - private void testPackagePrivAppPermission(PackageInfo packageInfo) - throws PackageManager.NameNotFoundException { - String packageName = packageInfo.packageName; - ArraySet privAppPermissions = SystemConfig.getInstance() - .getPrivAppPermissions(packageName); - if (ArrayUtils.isEmpty(packageInfo.requestedPermissions)) { - return; - } - for (int i = 0; i < packageInfo.requestedPermissions.length; i++) { - String pName = packageInfo.requestedPermissions[i]; - int protectionLevel; - boolean platformPermission; - try { - PermissionInfo permissionInfo = mPackageManager.getPermissionInfo(pName, 0); - platformPermission = PackageManagerService.PLATFORM_PACKAGE_NAME.equals( - permissionInfo.packageName); - protectionLevel = permissionInfo.protectionLevel; - } catch (PackageManager.NameNotFoundException e) { - continue; - } - if ((protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0) { - boolean granted = (packageInfo.requestedPermissionsFlags[i] - & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0; - // if privapp permissions are enforced, platform permissions must be whitelisted - // in SystemConfig - if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) { - assertTrue("Permission " + pName + " should be declared in " - + "privapp-permissions-.xml file for package " - + packageName, - privAppPermissions != null && privAppPermissions.contains(pName)); - } - assertTrue("Permission " + pName + " should be granted to " + packageName, granted); - } - } - } -} diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk new file mode 100644 index 000000000000..b001c8c466a9 --- /dev/null +++ b/tests/privapp-permissions/Android.mk @@ -0,0 +1,31 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_PACKAGE_NAME := PrivAppPermissionTest +LOCAL_PRIVILEGED_MODULE := true +LOCAL_MANIFEST_FILE := system/AndroidManifest.xml +LOCAL_REQUIRED_MODULES := privapp-permissions-test.xml +include $(BUILD_PACKAGE) + +include $(CLEAR_VARS) +LOCAL_MODULE := privapp-permissions-test.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions +LOCAL_SRC_FILES:= system/privapp-permissions-test.xml +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_PACKAGE_NAME := VendorPrivAppPermissionTest +LOCAL_PRIVILEGED_MODULE := true +LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml +LOCAL_VENDOR_MODULE := true +LOCAL_REQUIRED_MODULES := vendorprivapp-permissions-test.xml +include $(BUILD_PACKAGE) + +include $(CLEAR_VARS) +LOCAL_MODULE := vendorprivapp-permissions-test.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/permissions +LOCAL_SRC_FILES:= vendor/privapp-permissions-test.xml +include $(BUILD_PREBUILT) + diff --git a/tests/privapp-permissions/system/AndroidManifest.xml b/tests/privapp-permissions/system/AndroidManifest.xml new file mode 100644 index 000000000000..2099e31bd2c1 --- /dev/null +++ b/tests/privapp-permissions/system/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/tests/privapp-permissions/system/privapp-permissions-test.xml b/tests/privapp-permissions/system/privapp-permissions-test.xml new file mode 100644 index 000000000000..a0cb6bc74195 --- /dev/null +++ b/tests/privapp-permissions/system/privapp-permissions-test.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/privapp-permissions/vendor/AndroidManifest.xml b/tests/privapp-permissions/vendor/AndroidManifest.xml new file mode 100644 index 000000000000..78dedc5f199b --- /dev/null +++ b/tests/privapp-permissions/vendor/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/tests/privapp-permissions/vendor/privapp-permissions-test.xml b/tests/privapp-permissions/vendor/privapp-permissions-test.xml new file mode 100644 index 000000000000..51c588f0dea7 --- /dev/null +++ b/tests/privapp-permissions/vendor/privapp-permissions-test.xml @@ -0,0 +1,7 @@ + + + + + + + -- cgit v1.2.3-59-g8ed1b