Merge "Do not allow to install S+ apps with cross cert permissions"

This commit is contained in:
TreeHugger Robot
2020-10-22 00:14:32 +00:00
committed by Android (Google) Code Review
4 changed files with 164 additions and 43 deletions

View File

@@ -1574,6 +1574,26 @@ public abstract class PackageManager {
*/
public static final int INSTALL_PARSE_FAILED_SKIPPED = -125;
/**
* Installation failed return code: this is passed in the
* {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the system failed to install the package
* because it is attempting to define a permission group that is already defined by some
* existing package.
*
* @hide
*/
public static final int INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP = -126;
/**
* Installation failed return code: this is passed in the
* {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the system failed to install the package
* because it is attempting to define a permission in a group that does not exists or that is
* defined by an packages with an incompatible certificate.
*
* @hide
*/
public static final int INSTALL_FAILED_BAD_PERMISSION_GROUP = -127;
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,

View File

@@ -16,6 +16,8 @@
package android.permission;
import static android.os.Build.VERSION_CODES.S;
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.IntRange;
@@ -29,6 +31,8 @@ import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.IActivityManager;
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -68,6 +72,17 @@ public final class PermissionManager {
public static final String KILL_APP_REASON_GIDS_CHANGED =
"permission grant or revoke changed gids";
/**
* Refuse to install package if groups of permissions are bad
* - Permission groups should only be shared between apps sharing a certificate
* - If a permission belongs to a group that group should be defined
*
* @hide
*/
@ChangeId
@EnabledAfter(targetSdkVersion = S)
public static final long CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS = 146211400;
private final @NonNull Context mContext;
private final IPackageManager mPackageManager;

View File

@@ -17,17 +17,14 @@
package="com.android.frameworks.coretests.install_decl_perm">
<permission android:name="com.android.frameworks.coretests.NORMAL"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="normal"
android:label="test normal perm" />
<permission android:name="com.android.frameworks.coretests.DANGEROUS"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="dangerous"
android:label="test dangerous perm" />
<permission android:name="com.android.frameworks.coretests.SIGNATURE"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="signature"
android:label="test signature perm" />

View File

@@ -1,6 +1,5 @@
/*
* Copyright (C) 2006 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
@@ -47,8 +46,10 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER;
import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
@@ -233,6 +234,7 @@ import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.parsing.component.ParsedProcess;
import android.content.pm.parsing.component.ParsedProvider;
import android.content.pm.parsing.component.ParsedService;
@@ -17617,6 +17619,49 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
private boolean doesSignatureMatchForPermissions(@NonNull String sourcePackageName,
@NonNull ParsedPackage parsedPackage, int scanFlags) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final PackageSetting sourcePackageSetting;
synchronized (mLock) {
sourcePackageSetting = mSettings.getPackageLPr(sourcePackageName);
}
final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (sourcePackageName.equals(parsedPackage.getPackageName())
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, scanFlags))) {
return ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
} else {
// in the event of signing certificate rotation, we need to see if the
// package's certificate has rotated from the current one, or if it is an
// older certificate with which the current is ok with sharing permissions
if (sourceSigningDetails.checkCapability(
parsedPackage.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
return true;
} else if (parsedPackage.getSigningDetails().checkCapability(
sourceSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
// the scanned package checks out, has signing certificate rotation
// history, and is newer; bring it over
synchronized (mLock) {
sourcePackageSetting.signatures.mSigningDetails =
parsedPackage.getSigningDetails();
}
return true;
} else {
return false;
}
}
}
@GuardedBy("mInstallLock")
private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
throws PrepareFailure {
@@ -17775,6 +17820,15 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
/*
* Cannot properly check CANNOT_INSTALL_WITH_BAD_PERMISSION_GROUPS using CompatChanges
* as this only works for packages that are installed
*
* TODO: Move logic for permission group compatibility into PermissionManagerService
*/
boolean cannotInstallWithBadPermissionGroups =
parsedPackage.getTargetSdkVersion() >= Build.VERSION_CODES.S;
PackageSetting ps = mSettings.mPackages.get(pkgName);
if (ps != null) {
if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
@@ -17826,8 +17880,33 @@ public class PackageManagerService extends IPackageManager.Stub
res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
}
final int numGroups = ArrayUtils.size(parsedPackage.getPermissionGroups());
for (int groupNum = 0; groupNum < numGroups; groupNum++) {
final ParsedPermissionGroup group =
parsedPackage.getPermissionGroups().get(groupNum);
final PermissionGroupInfo sourceGroup = getPermissionGroupInfo(group.getName(), 0);
int N = ArrayUtils.size(parsedPackage.getPermissions());
if (sourceGroup != null && cannotInstallWithBadPermissionGroups) {
final String sourcePackageName = sourceGroup.packageName;
if ((replace || !parsedPackage.getPackageName().equals(sourcePackageName))
&& !doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
scanFlags)) {
EventLog.writeEvent(0x534e4554, "146211400", -1,
parsedPackage.getPackageName());
throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP,
"Package "
+ parsedPackage.getPackageName()
+ " attempting to redeclare permission group "
+ group.getName() + " already owned by "
+ sourcePackageName);
}
}
}
// TODO: Move logic for checking permission compatibility into PermissionManagerService
final int N = ArrayUtils.size(parsedPackage.getPermissions());
for (int i = N - 1; i >= 0; i--) {
final ParsedPermission perm = parsedPackage.getPermissions().get(i);
final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName());
@@ -17843,46 +17922,10 @@ public class PackageManagerService extends IPackageManager.Stub
// Check whether the newly-scanned package wants to define an already-defined perm
if (bp != null) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
// "updating same package" could also involve key-rotation.
final boolean sigsOk;
final String sourcePackageName = bp.getPackageName();
final PackageSetting sourcePackageSetting;
synchronized (mLock) {
sourcePackageSetting = mSettings.getPackageLPr(sourcePackageName);
}
final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (sourcePackageName.equals(parsedPackage.getPackageName())
&& (ksms.shouldCheckUpgradeKeySetLocked(
sourcePackageSetting, scanFlags))) {
sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage);
} else {
// in the event of signing certificate rotation, we need to see if the
// package's certificate has rotated from the current one, or if it is an
// older certificate with which the current is ok with sharing permissions
if (sourceSigningDetails.checkCapability(
parsedPackage.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
sigsOk = true;
} else if (parsedPackage.getSigningDetails().checkCapability(
sourceSigningDetails,
PackageParser.SigningDetails.CertCapabilities.PERMISSION)) {
// the scanned package checks out, has signing certificate rotation
// history, and is newer; bring it over
synchronized (mLock) {
sourcePackageSetting.signatures.mSigningDetails =
parsedPackage.getSigningDetails();
}
sigsOk = true;
} else {
sigsOk = false;
}
}
if (!sigsOk) {
if (!doesSignatureMatchForPermissions(sourcePackageName, parsedPackage,
scanFlags)) {
// If the owning package is the system itself, we log but allow
// install to proceed; we fail the install on all other permission
// redefinitions.
@@ -17917,6 +17960,52 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
}
if (perm.getGroup() != null && cannotInstallWithBadPermissionGroups) {
boolean isPermGroupDefinedByPackage = false;
for (int groupNum = 0; groupNum < numGroups; groupNum++) {
if (parsedPackage.getPermissionGroups().get(groupNum).getName()
.equals(perm.getGroup())) {
isPermGroupDefinedByPackage = true;
break;
}
}
if (!isPermGroupDefinedByPackage) {
final PermissionGroupInfo sourceGroup =
getPermissionGroupInfo(perm.getGroup(), 0);
if (sourceGroup == null) {
EventLog.writeEvent(0x534e4554, "146211400", -1,
parsedPackage.getPackageName());
throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
"Package "
+ parsedPackage.getPackageName()
+ " attempting to declare permission "
+ perm.getName() + " in non-existing group "
+ perm.getGroup());
} else {
String groupSourcePackageName = sourceGroup.packageName;
if (!PLATFORM_PACKAGE_NAME.equals(groupSourcePackageName)
&& !doesSignatureMatchForPermissions(groupSourcePackageName,
parsedPackage, scanFlags)) {
EventLog.writeEvent(0x534e4554, "146211400", -1,
parsedPackage.getPackageName());
throw new PrepareFailure(INSTALL_FAILED_BAD_PERMISSION_GROUP,
"Package "
+ parsedPackage.getPackageName()
+ " attempting to declare permission "
+ perm.getName() + " in group "
+ perm.getGroup() + " owned by package "
+ groupSourcePackageName
+ " with incompatible certificate");
}
}
}
}
}
}