diff options
| author | 2020-10-08 23:13:13 +0000 | |
|---|---|---|
| committer | 2020-10-08 23:13:13 +0000 | |
| commit | 36a56888f54fc1232210191b377e5a54058e3ddb (patch) | |
| tree | 2fe62a73febcecaa34fd8bf89d8da89ee59fce0e | |
| parent | cf23aae2f671e8a0c5d214ff22f159d6d374a097 (diff) | |
| parent | 458f53551a500af0251834e0a53c1bbc97512585 (diff) | |
Merge "Using new API to obtain apk checksum."
4 files changed, 145 insertions, 76 deletions
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 79e3eead1234..30f3325cc11c 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -379,8 +379,7 @@ interface IPackageManager { /** * Logs process start information (including APK hash) to the security log. */ - void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile, - int pid); + void logAppProcessStartIfNeeded(String packageName, String processName, int uid, String seinfo, String apkFile, int pid); /** * As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}. diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index bad03c1530bc..cf0223bac289 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2540,8 +2540,8 @@ public final class ProcessList { app.hostingRecord.getName() != null ? app.hostingRecord.getName() : ""); try { - AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid, - app.seInfo, app.info.sourceDir, pid); + AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.info.packageName, + app.processName, app.uid, app.seInfo, app.info.sourceDir, pid); } catch (RemoteException ex) { // Ignore } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index e9f8729e0a72..9caa91b63dee 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2232,8 +2232,7 @@ public class PackageManagerService extends IPackageManager.Stub // Send installed broadcasts if the package is not a static shared lib. if (res.pkg.getStaticSharedLibName() == null) { - mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash( - res.pkg.getBaseApkPath()); + mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath()); // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps @@ -2497,13 +2496,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - for (int i = 0, size = filesToChecksum.size(); i < size; ++i) { - final File file = filesToChecksum.get(i).second; - if (!file.exists()) { - throw new IllegalStateException("File not found: " + file.getPath()); - } - } - final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates( trustedInstallers) : null; @@ -25806,25 +25798,16 @@ public class PackageManagerService extends IPackageManager.Stub * @hide */ @Override - public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, - String apkFile, int pid) { + public void logAppProcessStartIfNeeded(String packageName, String processName, int uid, + String seinfo, String apkFile, int pid) { if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return; } if (!SecurityLog.isLoggingEnabled()) { return; } - Bundle data = new Bundle(); - data.putLong("startTimestamp", System.currentTimeMillis()); - data.putString("processName", processName); - data.putInt("uid", uid); - data.putString("seinfo", seinfo); - data.putString("apkFile", apkFile); - data.putInt("pid", pid); - Message msg = mProcessLoggingHandler.obtainMessage( - ProcessLoggingHandler.LOG_APP_PROCESS_START_MSG); - msg.setData(data); - mProcessLoggingHandler.sendMessage(msg); + mProcessLoggingHandler.logAppProcessStart(mContext, this, apkFile, packageName, processName, + uid, seinfo, pid); } public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) { diff --git a/services/core/java/com/android/server/pm/ProcessLoggingHandler.java b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java index c47dda4681f9..7fb34951d356 100644 --- a/services/core/java/com/android/server/pm/ProcessLoggingHandler.java +++ b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java @@ -16,29 +16,47 @@ package com.android.server.pm; +import static android.content.pm.PackageManager.EXTRA_CHECKSUMS; + import android.app.admin.SecurityLog; +import android.content.Context; +import android.content.IIntentReceiver; +import android.content.IIntentSender; import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.ApkChecksum; +import android.content.pm.Checksum; +import android.content.pm.IPackageManager; import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Message; +import android.os.Parcelable; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Slog; import com.android.internal.os.BackgroundThread; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import android.util.Slog; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; public final class ProcessLoggingHandler extends Handler { - private static final String TAG = "ProcessLoggingHandler"; - static final int LOG_APP_PROCESS_START_MSG = 1; - static final int INVALIDATE_BASE_APK_HASH_MSG = 2; - private final HashMap<String, String> mProcessLoggingBaseApkHashes = new HashMap(); + private static final int LOG_APP_PROCESS_START_MSG = 1; + + private static final int CHECKSUM_TYPE = Checksum.TYPE_WHOLE_SHA256; + + static class LoggingInfo { + public String apkHash = null; + public List<Bundle> pendingLogEntries = new ArrayList<>(); + } + + // Apk path to logging info map. + private final ArrayMap<String, LoggingInfo> mLoggingInfo = new ArrayMap<>(); ProcessLoggingHandler() { super(BackgroundThread.getHandler().getLooper()); @@ -49,64 +67,133 @@ public final class ProcessLoggingHandler extends Handler { switch (msg.what) { case LOG_APP_PROCESS_START_MSG: { Bundle bundle = msg.getData(); + long startTimestamp = bundle.getLong("startTimestamp"); String processName = bundle.getString("processName"); int uid = bundle.getInt("uid"); String seinfo = bundle.getString("seinfo"); - String apkFile = bundle.getString("apkFile"); int pid = bundle.getInt("pid"); - long startTimestamp = bundle.getLong("startTimestamp"); - String apkHash = computeStringHashOfApk(apkFile); + String apkHash = bundle.getString("apkHash"); SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName, startTimestamp, uid, pid, seinfo, apkHash); break; } - case INVALIDATE_BASE_APK_HASH_MSG: { - Bundle bundle = msg.getData(); - mProcessLoggingBaseApkHashes.remove(bundle.getString("apkFile")); - break; - } } } - void invalidateProcessLoggingBaseApkHash(String apkPath) { + void logAppProcessStart(Context context, IPackageManager pms, String apkFile, + String packageName, String processName, int uid, String seinfo, int pid) { Bundle data = new Bundle(); - data.putString("apkFile", apkPath); - Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG); - msg.setData(data); - sendMessage(msg); - } + data.putLong("startTimestamp", System.currentTimeMillis()); + data.putString("processName", processName); + data.putInt("uid", uid); + data.putString("seinfo", seinfo); + data.putInt("pid", pid); - private String computeStringHashOfApk(String apkFile) { if (apkFile == null) { - return "No APK"; + enqueueSecurityLogEvent(data, "No APK"); + return; } - String apkHash = mProcessLoggingBaseApkHashes.get(apkFile); - if (apkHash == null) { - try { - byte[] hash = computeHashOfApkFile(apkFile); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < hash.length; i++) { - sb.append(String.format("%02x", hash[i])); - } - apkHash = sb.toString(); - mProcessLoggingBaseApkHashes.put(apkFile, apkHash); - } catch (IOException | NoSuchAlgorithmException e) { - Slog.w(TAG, "computeStringHashOfApk() failed", e); + + // Check cached apk hash. + boolean requestChecksums; + final LoggingInfo loggingInfo; + synchronized (mLoggingInfo) { + LoggingInfo cached = mLoggingInfo.get(apkFile); + requestChecksums = cached == null; + if (requestChecksums) { + // Create a new pending cache entry. + cached = new LoggingInfo(); + mLoggingInfo.put(apkFile, cached); } + loggingInfo = cached; } - return apkHash != null ? apkHash : "Failed to count APK hash"; + + synchronized (loggingInfo) { + // Still pending? + if (!TextUtils.isEmpty(loggingInfo.apkHash)) { + enqueueSecurityLogEvent(data, loggingInfo.apkHash); + return; + } + + loggingInfo.pendingLogEntries.add(data); + } + + if (!requestChecksums) { + return; + } + + // Request base checksums when first added entry. + // Capturing local loggingInfo to still log even if hash was invalidated. + try { + pms.requestChecksums(packageName, false, 0, CHECKSUM_TYPE, null, + new IntentSender((IIntentSender) new IIntentSender.Stub() { + @Override + public void send(int code, Intent intent, String resolvedType, + IBinder allowlistToken, IIntentReceiver finishedReceiver, + String requiredPermission, Bundle options) { + processChecksums(loggingInfo, intent); + } + }), context.getUserId()); + } catch (RemoteException e) { + Slog.e(TAG, "requestChecksums() failed", e); + processChecksums(loggingInfo, null); + } + } + + void processChecksums(final LoggingInfo loggingInfo, Intent intent) { + Parcelable[] parcelables = intent.getParcelableArrayExtra(EXTRA_CHECKSUMS); + ApkChecksum[] checksums = Arrays.copyOf(parcelables, parcelables.length, + ApkChecksum[].class); + + for (ApkChecksum checksum : checksums) { + if (checksum.getType() == CHECKSUM_TYPE) { + processChecksum(loggingInfo, checksum.getValue()); + break; + } + } + } + + void processChecksum(final LoggingInfo loggingInfo, final byte[] hash) { + final String apkHash; + if (hash != null) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < hash.length; i++) { + sb.append(String.format("%02x", hash[i])); + } + apkHash = sb.toString(); + } else { + apkHash = "Failed to count APK hash"; + } + + List<Bundle> pendingLogEntries; + synchronized (loggingInfo) { + if (!TextUtils.isEmpty(loggingInfo.apkHash)) { + return; + } + loggingInfo.apkHash = apkHash; + + pendingLogEntries = loggingInfo.pendingLogEntries; + loggingInfo.pendingLogEntries = null; + } + + if (pendingLogEntries != null) { + for (Bundle data : pendingLogEntries) { + enqueueSecurityLogEvent(data, apkHash); + } + } + } + + void enqueueSecurityLogEvent(Bundle data, String apkHash) { + data.putString("apkHash", apkHash); + + Message msg = this.obtainMessage(LOG_APP_PROCESS_START_MSG); + msg.setData(data); + this.sendMessage(msg); } - private byte[] computeHashOfApkFile(String packageArchiveLocation) - throws IOException, NoSuchAlgorithmException { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - FileInputStream input = new FileInputStream(new File(packageArchiveLocation)); - byte[] buffer = new byte[65536]; - int size; - while ((size = input.read(buffer)) > 0) { - md.update(buffer, 0, size); + void invalidateBaseApkHash(String apkFile) { + synchronized (mLoggingInfo) { + mLoggingInfo.remove(apkFile); } - input.close(); - return md.digest(); } } |