diff options
10 files changed, 386 insertions, 253 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ad6d85f2712b..7228b5ab7feb 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11558,6 +11558,12 @@ public final class Settings { @Readable public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout"; + /** Timeout for package verification during streaming installations. + * @hide */ + @Readable + public static final String PACKAGE_STREAMING_VERIFIER_TIMEOUT = + "streaming_verifier_timeout"; + /** Timeout for app integrity verification. * @hide */ @Readable diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index fb8ffbd476a6..0dfad172ec5b 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -396,6 +396,7 @@ public class SettingsBackupTest { Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, Settings.Global.OVERLAY_DISPLAY_DEVICES, Settings.Global.PAC_CHANGE_DELAY, + Settings.Global.PACKAGE_STREAMING_VERIFIER_TIMEOUT, Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE, Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE, diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java index 4ddf2ff51dd1..d24435e12593 100644 --- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java +++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java @@ -76,7 +76,7 @@ public final class DomainVerificationConnection implements DomainVerificationSer @Override public long getPowerSaveTempWhitelistAppDuration() { - return VerificationUtils.getVerificationTimeout(mPm.mContext); + return VerificationUtils.getDefaultVerificationTimeout(mPm.mContext); } @Override diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 24052532dfa3..c8594eba69a6 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -56,7 +56,6 @@ import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION; 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_REMOVE; -import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY; import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import static com.android.server.pm.PackageManagerService.POST_INSTALL; @@ -90,7 +89,6 @@ import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.AppOpsManager; import android.app.ApplicationPackageManager; import android.app.backup.IBackupManager; import android.content.ContentResolver; @@ -190,11 +188,6 @@ import java.util.Set; import java.util.concurrent.ExecutorService; final class InstallPackageHelper { - /** - * Whether verification is enabled by default. - */ - private static final boolean DEFAULT_VERIFY_ENABLE = true; - private final PackageManagerService mPm; private final AppDataHelper mAppDataHelper; private final PackageManagerServiceInjector mInjector; @@ -2835,56 +2828,6 @@ final class InstallPackageHelper { } } - /** - * Check whether or not package verification has been enabled. - * - * @return true if verification should be performed - */ - boolean isVerificationEnabled(PackageInfoLite pkgInfoLite, int userId, int installFlags, - int installerUid) { - if (!DEFAULT_VERIFY_ENABLE) { - return false; - } - - // Check if installing from ADB - if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) { - if (mPm.isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) { - return true; - } - // Check if the developer wants to skip verification for ADB installs - if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) { - synchronized (mPm.mLock) { - if (mPm.mSettings.getPackageLPr(pkgInfoLite.packageName) == null) { - // Always verify fresh install - return true; - } - } - // Only skip when apk is debuggable - return !pkgInfoLite.debuggable; - } - return android.provider.Settings.Global.getInt(mPm.mContext.getContentResolver(), - android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0; - } - - // only when not installed from ADB, skip verification for instant apps when - // the installer and verifier are the same. - if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) { - if (mPm.mInstantAppInstallerActivity != null - && mPm.mInstantAppInstallerActivity.packageName.equals( - mPm.mRequiredVerifierPackage)) { - try { - mPm.mInjector.getSystemService(AppOpsManager.class) - .checkPackage(installerUid, mPm.mRequiredVerifierPackage); - if (DEBUG_VERIFY) { - Slog.i(TAG, "disable verification for instant app"); - } - return false; - } catch (SecurityException ignore) { } - } - } - return true; - } - public void sendPendingBroadcasts() { String[] packages; ArrayList<String>[] components; diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java index 1a9c7a994fea..217bc2397f29 100644 --- a/services/core/java/com/android/server/pm/PackageHandler.java +++ b/services/core/java/com/android/server/pm/PackageHandler.java @@ -22,7 +22,6 @@ import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRIT import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD; -import static com.android.server.pm.PackageManagerService.DEFAULT_VERIFICATION_RESPONSE; import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_INSTALL_OBSERVER; import static com.android.server.pm.PackageManagerService.DEFERRED_NO_KILL_POST_DELETE; import static com.android.server.pm.PackageManagerService.DOMAIN_VERIFICATION; @@ -47,14 +46,12 @@ import android.content.pm.InstantAppRequest; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.net.Uri; -import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.Trace; import android.os.UserHandle; -import android.os.UserManager; import android.provider.Settings; import android.util.Log; import android.util.Slog; @@ -154,45 +151,50 @@ final class PackageHandler extends Handler { } break; case CHECK_PENDING_VERIFICATION: { final int verificationId = msg.arg1; + final boolean streaming = msg.arg2 != 0; final PackageVerificationState state = mPm.mPendingVerification.get(verificationId); - if ((state != null) && !state.isVerificationComplete() - && !state.timeoutExtended()) { - final VerificationParams params = state.getVerificationParams(); - final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile); + if (state == null || state.isVerificationComplete()) { + // Not found or complete. + break; + } + if (!streaming && state.timeoutExtended()) { + // Timeout extended. + break; + } - String errorMsg = "Verification timed out for " + originUri; - Slog.i(TAG, errorMsg); + final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj; - final UserHandle user = params.getUser(); - if (getDefaultVerificationResponse(user) - == PackageManager.VERIFICATION_ALLOW) { - Slog.i(TAG, "Continuing with installation of " + originUri); - state.setVerifierResponse(Binder.getCallingUid(), - PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT); - VerificationUtils.broadcastPackageVerified(verificationId, originUri, - PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType, - user, mPm.mContext); - } else { - VerificationUtils.broadcastPackageVerified(verificationId, originUri, - PackageManager.VERIFICATION_REJECT, null, - params.mDataLoaderType, user, mPm.mContext); - params.setReturnCode( - PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg); - state.setVerifierResponse(Binder.getCallingUid(), - PackageManager.VERIFICATION_REJECT); - } + final VerificationParams params = state.getVerificationParams(); + final Uri originUri = Uri.fromFile(params.mOriginInfo.mResolvedFile); - if (state.areAllVerificationsComplete()) { - mPm.mPendingVerification.remove(verificationId); - } + String errorMsg = "Verification timed out for " + originUri; + Slog.i(TAG, errorMsg); - Trace.asyncTraceEnd( - TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId); - - params.handleVerificationFinished(); + final UserHandle user = params.getUser(); + if (response.code != PackageManager.VERIFICATION_REJECT) { + Slog.i(TAG, "Continuing with installation of " + originUri); + state.setVerifierResponse(response.callerUid, response.code); + VerificationUtils.broadcastPackageVerified(verificationId, originUri, + PackageManager.VERIFICATION_ALLOW, null, params.mDataLoaderType, + user, mPm.mContext); + } else { + VerificationUtils.broadcastPackageVerified(verificationId, originUri, + PackageManager.VERIFICATION_REJECT, null, + params.mDataLoaderType, user, mPm.mContext); + params.setReturnCode( + PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg); + state.setVerifierResponse(response.callerUid, response.code); + } + if (state.areAllVerificationsComplete()) { + mPm.mPendingVerification.remove(verificationId); } + + Trace.asyncTraceEnd( + TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId); + + params.handleVerificationFinished(); break; } case CHECK_PENDING_INTEGRITY_VERIFICATION: { @@ -241,9 +243,12 @@ final class PackageHandler extends Handler { + " It may be invalid or overridden by integrity verification"); break; } + if (state.isVerificationComplete()) { + Slog.w(TAG, "Verification with id " + verificationId + " already complete."); + break; + } final PackageVerificationResponse response = (PackageVerificationResponse) msg.obj; - state.setVerifierResponse(response.callerUid, response.code); if (state.isVerificationComplete()) { @@ -397,21 +402,6 @@ final class PackageHandler extends Handler { } /** - * Get the default verification agent response code. - * - * @return default verification response code - */ - private int getDefaultVerificationResponse(UserHandle user) { - if (mPm.mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, - user.getIdentifier())) { - return PackageManager.VERIFICATION_REJECT; - } - return android.provider.Settings.Global.getInt(mPm.mContext.getContentResolver(), - android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE, - DEFAULT_VERIFICATION_RESPONSE); - } - - /** * Get the default integrity verification response code. */ private int getDefaultIntegrityVerificationResponse() { diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 356d6c93ae84..f4740448b8a9 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -916,10 +916,26 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } + private boolean checkOpenSessionAccess(final PackageInstallerSession session) { + if (session == null) { + return false; + } + if (isCallingUidOwner(session)) { + return true; + } + // Package verifiers have access to openSession for sealed sessions. + if (session.isSealed() && mContext.checkCallingOrSelfPermission( + android.Manifest.permission.PACKAGE_VERIFICATION_AGENT) + == PackageManager.PERMISSION_GRANTED) { + return true; + } + return false; + } + private IPackageInstallerSession openSessionInternal(int sessionId) throws IOException { synchronized (mSessions) { final PackageInstallerSession session = mSessions.get(sessionId); - if (session == null || !isCallingUidOwner(session)) { + if (!checkOpenSessionAccess(session)) { throw new SecurityException("Caller has no access to session " + sessionId); } session.open(); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 28204eadd394..a94985c226ea 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1303,22 +1303,30 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public String[] getNames() { - assertCallerIsOwnerOrRoot(); + assertCallerIsOwnerRootOrVerifier(); synchronized (mLock) { - assertPreparedAndNotCommittedOrDestroyedLocked("getNames"); + assertPreparedAndNotDestroyedLocked("getNames"); + if (!mCommitted.get()) { + return getNamesLocked(); + } else { + return getStageDirContentsLocked(); + } + } + } - return getNamesLocked(); + @GuardedBy("mLock") + private String[] getStageDirContentsLocked() { + String[] result = stageDir.list(); + if (result == null) { + result = EmptyArray.STRING; } + return result; } @GuardedBy("mLock") private String[] getNamesLocked() { if (!isDataLoaderInstallation()) { - String[] result = stageDir.list(); - if (result == null) { - result = EmptyArray.STRING; - } - return result; + return getStageDirContentsLocked(); } InstallationFile[] files = getInstallationFilesLocked(); @@ -1403,6 +1411,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { public void requestChecksums(@NonNull String name, @Checksum.TypeMask int optional, @Checksum.TypeMask int required, @Nullable List trustedInstallers, @NonNull IOnChecksumsReadyListener onChecksumsReadyListener) { + assertCallerIsOwnerRootOrVerifier(); final File file = new File(stageDir, name); final String installerPackageName = getInstallSource().initiatingPackageName; try { @@ -1670,6 +1679,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } /** + * Check if the caller is the owner of this session or a verifier. + * Otherwise throw a {@link SecurityException}. + */ + private void assertCallerIsOwnerRootOrVerifier() { + final int callingUid = Binder.getCallingUid(); + if (callingUid == Process.ROOT_UID || callingUid == mInstallerUid) { + return; + } + if (isSealed() && mContext.checkCallingOrSelfPermission( + android.Manifest.permission.PACKAGE_VERIFICATION_AGENT) + == PackageManager.PERMISSION_GRANTED) { + return; + } + throw new SecurityException("Session does not belong to uid " + callingUid); + } + + /** * Check if the caller is the owner of this session. Otherwise throw a * {@link SecurityException}. */ diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 7ceae61f8726..8f6ac0744574 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1289,9 +1289,6 @@ public class PackageManagerService extends IPackageManager.Stub if (!file.exists()) { throw new FileNotFoundException(file.getAbsolutePath()); } - if (TextUtils.isEmpty(installerPackageName)) { - throw new FileNotFoundException(file.getAbsolutePath()); - } final Executor executor = mInjector.getBackgroundExecutor(); final Handler handler = mInjector.getBackgroundHandler(); @@ -5223,10 +5220,11 @@ public class PackageManagerService extends IPackageManager.Stub mContext.enforceCallingOrSelfPermission( android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, "Only package verification agents can verify applications"); + final int callingUid = Binder.getCallingUid(); final Message msg = mHandler.obtainMessage(PACKAGE_VERIFIED); final PackageVerificationResponse response = new PackageVerificationResponse( - verificationCode, Binder.getCallingUid()); + verificationCode, callingUid); msg.arg1 = id; msg.obj = response; mHandler.sendMessage(msg); @@ -5238,11 +5236,12 @@ public class PackageManagerService extends IPackageManager.Stub mContext.enforceCallingOrSelfPermission( android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, "Only package verification agents can extend verification timeouts"); + final int callingUid = Binder.getCallingUid(); mHandler.post(() -> { final PackageVerificationState state = mPendingVerification.get(id); final PackageVerificationResponse response = new PackageVerificationResponse( - verificationCodeAtTimeout, Binder.getCallingUid()); + verificationCodeAtTimeout, callingUid); long delay = millisecondsToDelay; if (delay > PackageManager.MAXIMUM_VERIFICATION_TIMEOUT) { diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java index 6d681399460e..e1442dd080f5 100644 --- a/services/core/java/com/android/server/pm/VerificationParams.java +++ b/services/core/java/com/android/server/pm/VerificationParams.java @@ -30,6 +30,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION; import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION; import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY; +import static com.android.server.pm.PackageManagerService.DEFAULT_VERIFICATION_RESPONSE; import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT; import static com.android.server.pm.PackageManagerService.PACKAGE_MIME_TYPE; import static com.android.server.pm.PackageManagerService.TAG; @@ -59,10 +60,13 @@ import android.os.Bundle; import android.os.Message; import android.os.Process; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.os.UserManager; import android.provider.DeviceConfig; import android.provider.Settings; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Pair; import android.util.Slog; @@ -76,6 +80,11 @@ import java.util.Set; final class VerificationParams extends HandlerParams { /** + * Whether verification is enabled by default. + */ + private static final boolean DEFAULT_VERIFY_ENABLE = true; + + /** * Whether integrity verification is enabled by default. */ private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true; @@ -333,157 +342,273 @@ final class VerificationParams extends HandlerParams { if (verifierUser == UserHandle.ALL) { verifierUser = UserHandle.SYSTEM; } + final int verifierUserId = verifierUser.getIdentifier(); + + String requiredVerifierPackage = mPm.mRequiredVerifierPackage; + boolean requiredVerifierPackageOverridden = false; + + // Allow verifier override for ADB installations which could already be unverified using + // PackageManager.INSTALL_DISABLE_VERIFICATION flag. + if ((mInstallFlags & PackageManager.INSTALL_FROM_ADB) != 0 + && (mInstallFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) == 0) { + final String adbVerifierOverridePackage = SystemProperties.get( + "debug.pm.adb_verifier_override_package", ""); + // Check if the package installed. + if (!TextUtils.isEmpty(adbVerifierOverridePackage) + && packageExists(adbVerifierOverridePackage)) { + // Pretend we requested to disable verification from command line. + boolean requestedDisableVerification = true; + // If this returns false then the caller can already skip verification, so we are + // not adding a new way to disable verifications. + if (!isAdbVerificationEnabled(pkgLite, verifierUserId, + requestedDisableVerification)) { + requiredVerifierPackage = adbVerifierOverridePackage; + requiredVerifierPackageOverridden = true; + } + } + } /* * Determine if we have any installed package verifiers. If we * do, then we'll defer to them to verify the packages. */ - final int requiredUid = mPm.mRequiredVerifierPackage == null ? -1 - : mPm.getPackageUid(mPm.mRequiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING, - verifierUser.getIdentifier()); + final int requiredUid = requiredVerifierPackage == null ? -1 + : mPm.getPackageUid(requiredVerifierPackage, MATCH_DEBUG_TRIAGED_MISSING, + verifierUserId); verificationState.setRequiredVerifierUid(requiredUid); - final int installerUid = - mVerificationInfo == null ? -1 : mVerificationInfo.mInstallerUid; - final boolean isVerificationEnabled = mInstallPackageHelper.isVerificationEnabled( - pkgLite, verifierUser.getIdentifier(), mInstallFlags, installerUid); - final boolean isV4Signed = - (mSigningDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4); - final boolean isIncrementalInstall = - (mDataLoaderType == DataLoaderType.INCREMENTAL); - // NOTE: We purposefully skip verification for only incremental installs when there's - // a v4 signature block. Otherwise, proceed with verification as usual. - if (!mOriginInfo.mExisting - && isVerificationEnabled - && (!isIncrementalInstall || !isV4Signed)) { - final Intent verification = new Intent( - Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); - verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - verification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)), - PACKAGE_MIME_TYPE); - verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - // Query all live verifiers based on current user state - final ParceledListSlice<ResolveInfo> receivers = mPm.queryIntentReceivers(verification, - PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier()); + final boolean isVerificationEnabled = isVerificationEnabled(pkgLite, + verifierUserId); - if (DEBUG_VERIFY) { - Slog.d(TAG, "Found " + receivers.getList().size() + " verifiers for intent " - + verification.toString() + " with " + pkgLite.verifiers.length - + " optional verifiers"); - } + if (mOriginInfo.mExisting || !isVerificationEnabled) { + verificationState.setVerifierResponse(requiredUid, PackageManager.VERIFICATION_ALLOW); + return; + } - verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId); + final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); + verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + verification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)), + PACKAGE_MIME_TYPE); + verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - verification.putExtra( - PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, mInstallFlags); + // Query all live verifiers based on current user state + final ParceledListSlice<ResolveInfo> receivers = mPm.queryIntentReceivers(verification, + PACKAGE_MIME_TYPE, 0, verifierUserId); - verification.putExtra( - PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName); + if (DEBUG_VERIFY) { + Slog.d(TAG, "Found " + receivers.getList().size() + " verifiers for intent " + + verification.toString() + " with " + pkgLite.verifiers.length + + " optional verifiers"); + } - verification.putExtra( - PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode); + verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId); - verification.putExtra( - PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE, - pkgLite.getLongVersionCode()); + verification.putExtra( + PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, mInstallFlags); - final String baseCodePath = mPackageLite.getBaseApkPath(); - final String[] splitCodePaths = mPackageLite.getSplitApkPaths(); - final String rootHashString = - PackageManagerServiceUtils.buildVerificationRootHashString(baseCodePath, - splitCodePaths); + verification.putExtra( + PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName); - if (rootHashString != null) { - verification.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, rootHashString); - } + verification.putExtra( + PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode); - verification.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, mDataLoaderType); - - verification.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); - - populateInstallerExtras(verification); - - final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite, - receivers.getList(), verificationState); - - DeviceIdleInternal idleController = - mPm.mInjector.getLocalService(DeviceIdleInternal.class); - final long idleDuration = VerificationUtils.getVerificationTimeout(mPm.mContext); - final BroadcastOptions options = BroadcastOptions.makeBasic(); - options.setTemporaryAppAllowlist(idleDuration, - TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, - REASON_PACKAGE_VERIFIER, ""); - - /* - * If any sufficient verifiers were listed in the package - * manifest, attempt to ask them. - */ - if (sufficientVerifiers != null) { - final int n = sufficientVerifiers.size(); - if (n == 0) { - String errorMsg = "Additional verifiers required, but none installed."; - Slog.i(TAG, errorMsg); - setReturnCode(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg); - } else { - for (int i = 0; i < n; i++) { - final ComponentName verifierComponent = sufficientVerifiers.get(i); - idleController.addPowerSaveTempWhitelistApp(Process.myUid(), - verifierComponent.getPackageName(), idleDuration, - verifierUser.getIdentifier(), false, - REASON_PACKAGE_VERIFIER, "package verifier"); - - final Intent sufficientIntent = new Intent(verification); - sufficientIntent.setComponent(verifierComponent); - mPm.mContext.sendBroadcastAsUser(sufficientIntent, verifierUser, - /* receiverPermission= */ null, - options.toBundle()); - } + verification.putExtra( + PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE, + pkgLite.getLongVersionCode()); + + final String baseCodePath = mPackageLite.getBaseApkPath(); + final String[] splitCodePaths = mPackageLite.getSplitApkPaths(); + final String rootHashString = PackageManagerServiceUtils.buildVerificationRootHashString( + baseCodePath, splitCodePaths); + + if (rootHashString != null) { + verification.putExtra(PackageManager.EXTRA_VERIFICATION_ROOT_HASH, rootHashString); + } + + verification.putExtra(PackageInstaller.EXTRA_DATA_LOADER_TYPE, mDataLoaderType); + + verification.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId); + + populateInstallerExtras(verification); + + // Streaming installation timeout schema is enabled only for: + // 1. Incremental installs with v4, + // 2. If device/policy allow unverified app installs by default. + final boolean streaming = (mDataLoaderType == DataLoaderType.INCREMENTAL) + && (mSigningDetails.getSignatureSchemeVersion() == SIGNING_BLOCK_V4) + && (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW); + + final long verificationTimeout = VerificationUtils.getVerificationTimeout(mPm.mContext, + streaming); + + final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite, + receivers.getList(), verificationState); + + DeviceIdleInternal idleController = + mPm.mInjector.getLocalService(DeviceIdleInternal.class); + final BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setTemporaryAppAllowlist(verificationTimeout, + TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, + REASON_PACKAGE_VERIFIER, ""); + + /* + * If any sufficient verifiers were listed in the package + * manifest, attempt to ask them. + */ + if (sufficientVerifiers != null) { + final int n = sufficientVerifiers.size(); + if (n == 0) { + String errorMsg = "Additional verifiers required, but none installed."; + Slog.i(TAG, errorMsg); + setReturnCode(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, errorMsg); + } else { + for (int i = 0; i < n; i++) { + final ComponentName verifierComponent = sufficientVerifiers.get(i); + idleController.addPowerSaveTempWhitelistApp(Process.myUid(), + verifierComponent.getPackageName(), verificationTimeout, + verifierUserId, false, + REASON_PACKAGE_VERIFIER, "package verifier"); + + final Intent sufficientIntent = new Intent(verification); + sufficientIntent.setComponent(verifierComponent); + mPm.mContext.sendBroadcastAsUser(sufficientIntent, verifierUser, + /* receiverPermission= */ null, + options.toBundle()); } } + } - if (mPm.mRequiredVerifierPackage != null) { - final ComponentName requiredVerifierComponent = matchComponentForVerifier( - mPm.mRequiredVerifierPackage, receivers.getList()); - /* - * Send the intent to the required verification agent, - * but only start the verification timeout after the - * target BroadcastReceivers have run. - */ - verification.setComponent(requiredVerifierComponent); - idleController.addPowerSaveTempWhitelistApp(Process.myUid(), - mPm.mRequiredVerifierPackage, idleDuration, - verifierUser.getIdentifier(), false, - REASON_PACKAGE_VERIFIER, "package verifier"); - mPm.mContext.sendOrderedBroadcastAsUser(verification, verifierUser, - android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, - /* appOp= */ AppOpsManager.OP_NONE, - /* options= */ options.toBundle(), - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final Message msg = mPm.mHandler - .obtainMessage(CHECK_PENDING_VERIFICATION); - msg.arg1 = verificationId; - mPm.mHandler.sendMessageDelayed(msg, - VerificationUtils.getVerificationTimeout(mPm.mContext)); - } - }, null, 0, null, null); - - Trace.asyncTraceBegin( - TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId); - - /* - * We don't want the copy to proceed until verification - * succeeds. - */ - mWaitForVerificationToComplete = true; - } + if (requiredVerifierPackage == null) { + Slog.e(TAG, "Required verifier is null"); + return; + } + + final int verificationCodeAtTimeout; + if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) { + verificationCodeAtTimeout = PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT; + } else { + verificationCodeAtTimeout = PackageManager.VERIFICATION_REJECT; + } + final PackageVerificationResponse response = new PackageVerificationResponse( + verificationCodeAtTimeout, requiredUid); + + /* + * Send the intent to the required verification agent, + * but only start the verification timeout after the + * target BroadcastReceivers have run. + */ + if (!requiredVerifierPackageOverridden) { + final ComponentName requiredVerifierComponent = matchComponentForVerifier( + requiredVerifierPackage, receivers.getList()); + verification.setComponent(requiredVerifierComponent); } else { - verificationState.setVerifierResponse( - requiredUid, PackageManager.VERIFICATION_ALLOW); + verification.setPackage(requiredVerifierPackage); } + idleController.addPowerSaveTempWhitelistApp(Process.myUid(), + requiredVerifierPackage, verificationTimeout, + verifierUserId, false, + REASON_PACKAGE_VERIFIER, "package verifier"); + mPm.mContext.sendOrderedBroadcastAsUser(verification, verifierUser, + android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, + /* appOp= */ AppOpsManager.OP_NONE, + /* options= */ options.toBundle(), + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final Message msg = mPm.mHandler + .obtainMessage(CHECK_PENDING_VERIFICATION); + msg.arg1 = verificationId; + msg.arg2 = streaming ? 1 : 0; + msg.obj = response; + mPm.mHandler.sendMessageDelayed(msg, verificationTimeout); + } + }, null, 0, null, null); + + Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId); + + /* + * We don't want the copy to proceed until verification + * succeeds. + */ + mWaitForVerificationToComplete = true; } + /** + * Get the default verification agent response code. + * + * @return default verification response code + */ + int getDefaultVerificationResponse() { + if (mPm.mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS, + getUser().getIdentifier())) { + return PackageManager.VERIFICATION_REJECT; + } + return android.provider.Settings.Global.getInt(mPm.mContext.getContentResolver(), + android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE, + DEFAULT_VERIFICATION_RESPONSE); + } + + private boolean packageExists(String packageName) { + synchronized (mPm.mLock) { + return mPm.mSettings.getPackageLPr(packageName) != null; + } + } + + private boolean isAdbVerificationEnabled(PackageInfoLite pkgInfoLite, int userId, + boolean requestedDisableVerification) { + if (mPm.isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) { + return true; + } + // Check if the developer wants to skip verification for ADB installs + if (requestedDisableVerification) { + if (!packageExists(pkgInfoLite.packageName)) { + // Always verify fresh install + return true; + } + // Only skip when apk is debuggable + return !pkgInfoLite.debuggable; + } + return android.provider.Settings.Global.getInt(mPm.mContext.getContentResolver(), + android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0; + } + + /** + * Check whether package verification has been enabled. + * + * @return true if verification should be performed + */ + private boolean isVerificationEnabled(PackageInfoLite pkgInfoLite, int userId) { + if (!DEFAULT_VERIFY_ENABLE) { + return false; + } + + final int installerUid = mVerificationInfo == null ? -1 : mVerificationInfo.mInstallerUid; + final int installFlags = mInstallFlags; + + // Check if installing from ADB + if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) { + boolean requestedDisableVerification = + (mInstallFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0; + return isAdbVerificationEnabled(pkgInfoLite, userId, requestedDisableVerification); + } + + // only when not installed from ADB, skip verification for instant apps when + // the installer and verifier are the same. + if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) { + if (mPm.mInstantAppInstallerActivity != null + && mPm.mInstantAppInstallerActivity.packageName.equals( + mPm.mRequiredVerifierPackage)) { + try { + mPm.mInjector.getSystemService(AppOpsManager.class) + .checkPackage(installerUid, mPm.mRequiredVerifierPackage); + if (DEBUG_VERIFY) { + Slog.i(TAG, "disable verification for instant app"); + } + return false; + } catch (SecurityException ignore) { } + } + } + return true; + } private List<ComponentName> matchVerifiers(PackageInfoLite pkgInfo, List<ResolveInfo> receivers, final PackageVerificationState verificationState) { diff --git a/services/core/java/com/android/server/pm/VerificationUtils.java b/services/core/java/com/android/server/pm/VerificationUtils.java index 4392b4720fcb..c132028a4dae 100644 --- a/services/core/java/com/android/server/pm/VerificationUtils.java +++ b/services/core/java/com/android/server/pm/VerificationUtils.java @@ -35,12 +35,25 @@ final class VerificationUtils { private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000; /** - * Get the verification agent timeout. Used for both the APK verifier and the + * The default maximum time to wait for the verification agent to return in + * milliseconds. + */ + private static final long DEFAULT_STREAMING_VERIFICATION_TIMEOUT = 3 * 1000; + + public static long getVerificationTimeout(Context context, boolean streaming) { + if (streaming) { + return getDefaultStreamingVerificationTimeout(context); + } + return getDefaultVerificationTimeout(context); + } + + /** + * Get the default verification agent timeout. Used for both the APK verifier and the * intent filter verifier. * * @return verification timeout in milliseconds */ - public static long getVerificationTimeout(Context context) { + public static long getDefaultVerificationTimeout(Context context) { long timeout = Settings.Global.getLong(context.getContentResolver(), Settings.Global.PACKAGE_VERIFIER_TIMEOUT, DEFAULT_VERIFICATION_TIMEOUT); // The setting can be used to increase the timeout but not decrease it, since that is @@ -48,6 +61,20 @@ final class VerificationUtils { return Math.max(timeout, DEFAULT_VERIFICATION_TIMEOUT); } + /** + * Get the default verification agent timeout for streaming installations. + * + * @return verification timeout in milliseconds + */ + public static long getDefaultStreamingVerificationTimeout(Context context) { + long timeout = Settings.Global.getLong(context.getContentResolver(), + Settings.Global.PACKAGE_STREAMING_VERIFIER_TIMEOUT, + DEFAULT_STREAMING_VERIFICATION_TIMEOUT); + // The setting can be used to increase the timeout but not decrease it, since that is + // equivalent to disabling the verifier. + return Math.max(timeout, DEFAULT_STREAMING_VERIFICATION_TIMEOUT); + } + public static void broadcastPackageVerified(int verificationId, Uri packageUri, int verificationCode, @Nullable String rootHashString, int dataLoaderType, UserHandle user, Context context) { |