diff options
19 files changed, 292 insertions, 142 deletions
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 @@ -6267,6 +6267,11 @@ public class PackageParser { } /** @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 @@ -144,6 +144,15 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { public static final int PROTECTION_FLAG_OEM = 0x4000; /** + * Additional flag for {${link #protectionLevel}, corresponding + * to the <code>vendorPrivileged</code> 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. */ public static final int PROTECTION_MASK_BASE = 0xf; @@ -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<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>(); final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>(); + final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>(); public static SystemConfig getInstance() { @@ -229,6 +232,14 @@ public class SystemConfig { return mPrivAppDenyPermissions.get(packageName); } + public ArraySet<String> getVendorPrivAppPermissions(String packageName) { + return mVendorPrivAppPermissions.get(packageName); + } + + public ArraySet<String> getVendorPrivAppDenyPermissions(String packageName) { + return mVendorPrivAppDenyPermissions.get(packageName); + } + public Map<String, Boolean> getOemPermissions(String packageName) { final Map<String, Boolean> 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<String, ArraySet<String>> grantMap, + ArrayMap<String, ArraySet<String>> denyMap) + throws IOException, XmlPullParserException { String packageName = parser.getAttributeValue(null, "package"); if (TextUtils.isEmpty(packageName)) { Slog.w(TAG, "package is required for <privapp-permissions> in " @@ -682,11 +708,11 @@ public class SystemConfig { return; } - ArraySet<String> permissions = mPrivAppPermissions.get(packageName); + ArraySet<String> permissions = grantMap.get(packageName); if (permissions == null) { permissions = new ArraySet<>(); } - ArraySet<String> denyPermissions = mPrivAppDenyPermissions.get(packageName); + ArraySet<String> 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. --> <flag name="oem" value="0x4000" /> + <!-- Additional flag from base permission type: this permission can be granted to + privileged apps in vendor partition. --> + <flag name="vendorPrivileged" value="0x8000" /> </attr> <!-- Flags indicating more context for a permission group. --> 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<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg); + + ArraySet<String> 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<String> privAppDenyPermissions = - SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); - getOutPrintWriter().println(privAppDenyPermissions == null - ? "{}" : privAppDenyPermissions.toString()); + + ArraySet<String> 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)); * <p>This handles parent/child apps. */ private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) { - ArraySet<String> wlPermissions = SystemConfig.getInstance() - .getPrivAppPermissions(pkg.packageName); + ArraySet<String> 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<String> deniedPermissions = SystemConfig.getInstance() - .getPrivAppDenyPermissions(pkg.packageName); + final ArraySet<String> 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(); - } - - /** - * <p>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<PackageInfo> 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<String> 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-<category>.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 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2017 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.framework.permission.privapp.tests.system"> + + <!-- MANAGE_USB is signature|privileged --> + <uses-permission android:name="android.permission.MANAGE_USB"/> +</manifest> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<permissions> + <privapp-permissions package="com.android.framework.permission.privapp.tests.system"> + <permission name="android.permission.MANAGE_USB"/> + </privapp-permissions> +</permissions> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2017 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.framework.permission.privapp.tests.vendor"> + + <!-- BIND_IMS_SERVICE is signature|privileged|vendorPrivileged --> + <uses-permission android:name="android.permission.BIND_IMS_SERVICE"/> + <!-- MANAGE_USB is signature|privileged and thus cannot be granted to this app --> + <uses-permission android:name="android.permission.MANAGE_USB"/> +</manifest> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<permissions> + <privapp-permissions package="com.android.framework.permission.privapp.tests.vendor"> + <permission name="android.permission.BIND_IMS_SERVICE"/> + <permission name="android.permission.MANAGE_USB"/> + </privapp-permissions> +</permissions> |