diff options
| author | 2017-02-13 20:50:31 +0900 | |
|---|---|---|
| committer | 2017-11-30 14:41:55 +0900 | |
| commit | 002fdbdb950ebbf40331a27de33b80db33e40d30 (patch) | |
| tree | 5053b4826099514b98cd49c259cc61c6d6e49aa0 | |
| parent | 304494b61d0da759cfc3e613f9d0bafb615cd175 (diff) | |
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
<privapp-permissions> 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
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> |