From ee536b9dcfb81ae78db71ef9c5210695d98f6e29 Mon Sep 17 00:00:00 2001 From: Nick Kovacs Date: Mon, 21 Nov 2022 19:30:02 +0000 Subject: [PATCH] Enforce min installable target sdk version This change will block the installation (but not the execution) of apps that do not meet the minimum target sdk version. The intention is to improve security and privacy by blocking low target sdk apps as malware can target older sdk versions to avoid the enforcement of new API behavior. This change is fenced off by a feature flag. The plan is to progressively ramp up the min_installable_target_sdk version up to version 23 for Android U. Bug: 237321649 Test: adb shell device_config put package_manager_service MinInstallableTargetSdk__install_block_enabled true Test: adb shell device_config put package_manager_service MinInstallableTargetSdk__min_installable_target_sdk 5 Test: adb install com.senecacreeksoftware.simpletip-3.apk (this app uses target sdk 4) Test: adb shell device_config put package_manager_service MinInstallableTargetSdk__min_installable_target_sdk 6 Test: adb install com.senecacreeksoftware.simpletip-3.apk Test: adb shell device_config put package_manager_service MinInstallableTargetSdk__min_installable_target_sdk 23 Test: Attempted side load install via files app Test: Attempted install from Play Store of low target sdk app Change-Id: Id86c65d088b62b0a9b36734c14fbf919fa458e32 --- .../android/content/pm/PackageManager.java | 10 ++++++++ .../server/pm/InstallPackageHelper.java | 24 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 485d04db82d5a..88b5e021882af 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1958,6 +1958,14 @@ public abstract class PackageManager { */ public static final int INSTALL_FAILED_MISSING_SPLIT = -28; + /** + * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS} + * if the new package targets a deprecated SDK version. + * + * @hide + */ + public static final int INSTALL_FAILED_DEPRECATED_SDK_VERSION = -29; + /** * Installation parse return code: this is passed in the * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser was given a path that is not a @@ -9618,6 +9626,7 @@ public abstract class PackageManager { case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED"; case INSTALL_FAILED_BAD_DEX_METADATA: return "INSTALL_FAILED_BAD_DEX_METADATA"; case INSTALL_FAILED_MISSING_SPLIT: return "INSTALL_FAILED_MISSING_SPLIT"; + case INSTALL_FAILED_DEPRECATED_SDK_VERSION: return "INSTALL_FAILED_DEPRECATED_SDK_VERSION"; case INSTALL_FAILED_BAD_SIGNATURE: return "INSTALL_FAILED_BAD_SIGNATURE"; case INSTALL_FAILED_WRONG_INSTALLED_VERSION: return "INSTALL_FAILED_WRONG_INSTALLED_VERSION"; case INSTALL_FAILED_PROCESS_NOT_DEFINED: return "INSTALL_FAILED_PROCESS_NOT_DEFINED"; @@ -9675,6 +9684,7 @@ public abstract class PackageManager { case INSTALL_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED; case INSTALL_FAILED_MISSING_SPLIT: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; case INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE: return PackageInstaller.STATUS_FAILURE_BLOCKED; + case INSTALL_FAILED_DEPRECATED_SDK_VERSION: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE; default: return PackageInstaller.STATUS_FAILURE; } } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 5dd5d81cfbb64..e8db10d792bea 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 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_DEPRECATED_SDK_VERSION; 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; @@ -136,6 +137,7 @@ import android.os.incremental.IncrementalManager; import android.os.incremental.IncrementalStorage; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; +import android.provider.DeviceConfig; import android.stats.storage.StorageEnums; import android.system.ErrnoException; import android.system.Os; @@ -1017,6 +1019,28 @@ final class InstallPackageHelper { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } + // If the minimum installable SDK version enforcement is enabled, block the install + // of apps using a lower target SDK version than required. This helps improve security + // and privacy as malware can target older SDK versions to avoid enforcement of new API + // behavior. + if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, + "MinInstallableTargetSdk__install_block_enabled", + false)) { + int minInstallableTargetSdk = + DeviceConfig.getInt(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, + "MinInstallableTargetSdk__min_installable_target_sdk", + 0); + if (parsedPackage.getTargetSdkVersion() < minInstallableTargetSdk) { + Slog.w(TAG, "App " + parsedPackage.getPackageName() + + " targets deprecated sdk version"); + throw new PrepareFailure(INSTALL_FAILED_DEPRECATED_SDK_VERSION, + "App package must target at least version " + + minInstallableTargetSdk); + } + } else { + Slog.i(TAG, "Minimum installable target sdk enforcement not enabled"); + } + // Instant apps have several additional install-time checks. if (instantApp) { if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {