Do not verify APKs out of updated APEXs
For APK-in-APEX the system is not aware of the pre-installed APKs. Hence
the currently installed APK always shows up as "factory-installed APK".
For factory installed APKs we enforce that all privilidged perissions
are manually whitelisted.
If an APK-in-APEX gets updated the app might request additional
privilidged permissions. We now explicity allow this.
This change leaves all apex specific logic inside of ApexMgr. E.g.
- how to figure out if a pkg is a apk-in-apex
- how apexPkgs are marked as factory/updated
Fixes: 148853593
Test: Built a new APK-In-APEX that contained new priv permission,
installed it and rebooted -> no crash, but permission was not granted
Change-Id: I254e5189909efdafe3dc0ca8a5ab5a520457c585
This commit is contained in:
@@ -62,6 +62,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -74,7 +75,7 @@ public abstract class ApexManager {
|
||||
|
||||
private static final String TAG = "ApexManager";
|
||||
|
||||
static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
|
||||
public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
|
||||
static final int MATCH_FACTORY_PACKAGE = 1 << 1;
|
||||
|
||||
private static final Singleton<ApexManager> sApexManagerSingleton =
|
||||
@@ -163,7 +164,7 @@ public abstract class ApexManager {
|
||||
* is not found.
|
||||
*/
|
||||
@Nullable
|
||||
abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
|
||||
public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
|
||||
|
||||
/**
|
||||
* Retrieves information about all active APEX packages.
|
||||
@@ -197,6 +198,27 @@ public abstract class ApexManager {
|
||||
*/
|
||||
abstract boolean isApexPackage(String packageName);
|
||||
|
||||
/**
|
||||
* Whether the APEX package is pre-installed or not.
|
||||
*
|
||||
* @param packageInfo the package to check
|
||||
* @return {@code true} if this package is pre-installed, {@code false} otherwise.
|
||||
*/
|
||||
public static boolean isFactory(@NonNull PackageInfo packageInfo) {
|
||||
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the active apex package's name that contains the (apk) package.
|
||||
*
|
||||
* @param containedPackage The (apk) package that might be in a apex
|
||||
* @return the apex package's name of {@code null} if the {@code containedPackage} is not inside
|
||||
* any apex.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract String getActiveApexPackageNameContainingPackage(
|
||||
@NonNull AndroidPackage containedPackage);
|
||||
|
||||
/**
|
||||
* Retrieves information about an apexd staged session i.e. the internal state used by apexd to
|
||||
* track the different states of a session.
|
||||
@@ -351,7 +373,7 @@ public abstract class ApexManager {
|
||||
* difference between {@code packageName} and {@code apexModuleName}.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private Map<String, List<String>> mApksInApex = new ArrayMap<>();
|
||||
private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private List<PackageInfo> mAllPackagesCache;
|
||||
@@ -366,7 +388,7 @@ public abstract class ApexManager {
|
||||
* the apk container to {@code apexModuleName} of the apex-payload inside.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private Map<String, String> mPackageNameToApexModuleName;
|
||||
private ArrayMap<String, String> mPackageNameToApexModuleName;
|
||||
|
||||
ApexManagerImpl(IApexService apexService) {
|
||||
mApexService = apexService;
|
||||
@@ -382,16 +404,6 @@ public abstract class ApexManager {
|
||||
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the APEX package is pre-installed or not.
|
||||
*
|
||||
* @param packageInfo the package to check
|
||||
* @return {@code true} if this package is pre-installed, {@code false} otherwise.
|
||||
*/
|
||||
private static boolean isFactory(PackageInfo packageInfo) {
|
||||
return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ActiveApexInfo> getActiveApexInfos() {
|
||||
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
|
||||
@@ -503,7 +515,9 @@ public abstract class ApexManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
|
||||
@Nullable
|
||||
public PackageInfo getPackageInfo(String packageName,
|
||||
@PackageInfoFlags int flags) {
|
||||
Preconditions.checkState(mAllPackagesCache != null,
|
||||
"APEX packages have not been scanned");
|
||||
boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
|
||||
@@ -563,6 +577,36 @@ public abstract class ApexManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getActiveApexPackageNameContainingPackage(
|
||||
@NonNull AndroidPackage containedPackage) {
|
||||
Preconditions.checkState(mPackageNameToApexModuleName != null,
|
||||
"APEX packages have not been scanned");
|
||||
|
||||
Objects.requireNonNull(containedPackage);
|
||||
|
||||
synchronized (mLock) {
|
||||
int numApksInApex = mApksInApex.size();
|
||||
for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) {
|
||||
if (mApksInApex.valueAt(apkInApexNum).contains(
|
||||
containedPackage.getPackageName())) {
|
||||
String apexModuleName = mApksInApex.keyAt(apkInApexNum);
|
||||
|
||||
int numApexPkgs = mPackageNameToApexModuleName.size();
|
||||
for (int apexPkgNum = 0; apexPkgNum < numApexPkgs; apexPkgNum++) {
|
||||
if (mPackageNameToApexModuleName.valueAt(apexPkgNum).equals(
|
||||
apexModuleName)) {
|
||||
return mPackageNameToApexModuleName.keyAt(apexPkgNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
|
||||
try {
|
||||
@@ -893,7 +937,7 @@ public abstract class ApexManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
PackageInfo getPackageInfo(String packageName, int flags) {
|
||||
public PackageInfo getPackageInfo(String packageName, int flags) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -917,6 +961,15 @@ public abstract class ApexManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getActiveApexPackageNameContainingPackage(
|
||||
@NonNull AndroidPackage containedPackage) {
|
||||
Objects.requireNonNull(containedPackage);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
ApexSessionInfo getStagedSessionInfo(int sessionId) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
@@ -40,6 +40,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
|
||||
import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
|
||||
import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
|
||||
|
||||
import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE;
|
||||
import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
|
||||
import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
|
||||
import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
|
||||
@@ -128,6 +129,7 @@ import com.android.server.LocalServices;
|
||||
import com.android.server.ServiceThread;
|
||||
import com.android.server.SystemConfig;
|
||||
import com.android.server.Watchdog;
|
||||
import com.android.server.pm.ApexManager;
|
||||
import com.android.server.pm.PackageManagerServiceUtils;
|
||||
import com.android.server.pm.PackageSetting;
|
||||
import com.android.server.pm.SharedUserSetting;
|
||||
@@ -3321,8 +3323,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|
||||
if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged()
|
||||
&& !platformPackage && platformPermission) {
|
||||
if (!hasPrivappWhitelistEntry(perm, pkg)) {
|
||||
// Only report violations for apps on system image
|
||||
if (!mSystemReady && !pkgSetting.getPkgState().isUpdatedSystemApp()) {
|
||||
ApexManager apexMgr = ApexManager.getInstance();
|
||||
String apexContainingPkg = apexMgr.getActiveApexPackageNameContainingPackage(pkg);
|
||||
|
||||
// Only enforce whitelist this on boot
|
||||
if (!mSystemReady
|
||||
// Updated system apps do not need to be whitelisted
|
||||
&& !pkgSetting.getPkgState().isUpdatedSystemApp()
|
||||
// Apps that are in updated apexs' do not need to be whitelisted
|
||||
&& (apexContainingPkg == null || apexMgr.isFactory(
|
||||
apexMgr.getPackageInfo(apexContainingPkg, MATCH_ACTIVE_PACKAGE)))) {
|
||||
// it's only a reportable violation if the permission isn't explicitly denied
|
||||
ArraySet<String> deniedPermissions = null;
|
||||
if (pkg.isVendor()) {
|
||||
|
||||
Reference in New Issue
Block a user