From 7c9923680a21fe9092ca63ebf0c5582a528c90d9 Mon Sep 17 00:00:00 2001 From: Jon Boekenoogen Date: Thu, 31 Mar 2022 21:50:27 -0700 Subject: [PATCH] Installer package can call performDexOptMode Test: PlayStore installing itself can trigger dexopt manually PlayStore with null installerPackageName cannot trigger PlayStore with other installer package name cannot trigger Change-Id: I9d10951bac84a7c53b9efd89da458982135d3659 --- .../com/android/server/pm/DexOptHelper.java | 23 +++++++++++++++++-- .../server/pm/IPackageManagerBase.java | 5 ++-- .../server/pm/PackageManagerServiceUtils.java | 11 +++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java index bb2ba5cc498d1..bd323d1923817 100644 --- a/services/core/java/com/android/server/pm/DexOptHelper.java +++ b/services/core/java/com/android/server/pm/DexOptHelper.java @@ -446,10 +446,13 @@ final class DexOptHelper { } } - public boolean performDexOptMode(String packageName, + public boolean performDexOptMode(@NonNull Computer snapshot, String packageName, boolean checkProfiles, String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) { - PackageManagerServiceUtils.enforceSystemOrRootOrShell("performDexOptMode"); + if (!PackageManagerServiceUtils.isSystemOrRootOrShell() + && !isCallerInstallerForPackage(snapshot, packageName)) { + throw new SecurityException("performDexOptMode"); + } int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) | (force ? DexoptOptions.DEXOPT_FORCE : 0) @@ -458,6 +461,22 @@ final class DexOptHelper { targetCompilerFilter, splitName, flags)); } + private boolean isCallerInstallerForPackage(@NonNull Computer snapshot, String packageName) { + final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName); + if (packageState == null) { + return false; + } + final InstallSource installSource = packageState.getInstallSource(); + + final PackageStateInternal installerPackageState = + snapshot.getPackageStateInternal(installSource.installerPackageName); + if (installerPackageState == null) { + return false; + } + final AndroidPackage installerPkg = installerPackageState.getPkg(); + return installerPkg.getUid() == Binder.getCallingUid(); + } + public boolean performDexOptSecondary(String packageName, String compilerFilter, boolean force) { int flags = DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java index ba7309f0283d2..043661302f8f7 100644 --- a/services/core/java/com/android/server/pm/IPackageManagerBase.java +++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java @@ -972,8 +972,9 @@ public abstract class IPackageManagerBase extends IPackageManager.Stub { public final boolean performDexOptMode(String packageName, boolean checkProfiles, String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) { - return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter, - force, bootComplete, splitName); + final Computer snapshot = snapshot(); + return mDexOptHelper.performDexOptMode(snapshot, packageName, checkProfiles, + targetCompilerFilter, force, bootComplete, splitName); } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 2a1a99068d45d..4d11b13510e99 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -1245,12 +1245,19 @@ public class PackageManagerServiceUtils { * @throws SecurityException if the caller is not system or shell */ public static void enforceSystemOrRootOrShell(String message) { - final int uid = Binder.getCallingUid(); - if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID && uid != Process.SHELL_UID) { + if (!isSystemOrRootOrShell()) { throw new SecurityException(message); } } + /** + * Check if the Binder caller is system UID, root's UID, or shell's UID. + */ + public static boolean isSystemOrRootOrShell() { + final int uid = Binder.getCallingUid(); + return uid == Process.SYSTEM_UID || uid == Process.ROOT_UID || uid == Process.SHELL_UID; + } + /** * Check if the Binder caller is system UID or root's UID. */