Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ede83e6 authored by Alex Buynytskyy's avatar Alex Buynytskyy
Browse files

Fix for security logging of missing packages.

Better error cases handling.
Using internal handler to process digests to not overcommit
PackageManager's.

Fixes: 170777013
Test: atest OrgOwnedProfileOwnerTest#testSecurityLogging
Change-Id: I741c10ef3ceeec01e5436f92caa6a52d0c6b6003
parent 6544279f
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -1126,4 +1126,16 @@ public abstract class PackageManagerInternal {
     * Notifies that a package has crashed or ANR'd.
     */
    public abstract void notifyPackageCrashOrAnr(String packageName);

    /**
     * Requesting the checksums for APKs within a package.
     * See {@link PackageManager#requestChecksums} for details.
     *
     * @param executor to use for digest calculations.
     * @param handler to use for postponed calculations.
     */
    public abstract void requestChecksums(@NonNull String packageName, boolean includeSplits,
            @Checksum.Type int optional, @Checksum.Type int required,
            @Nullable List trustedInstallers, @NonNull IntentSender statusReceiver, int userId,
            @NonNull Executor executor, @NonNull Handler handler);
}
+24 −4
Original line number Diff line number Diff line
@@ -2535,8 +2535,20 @@ public class PackageManagerService extends IPackageManager.Stub
            @Checksum.Type int optional,
            @Checksum.Type int required, @Nullable List trustedInstallers,
            @NonNull IntentSender statusReceiver, int userId) {
        requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers,
                statusReceiver, userId, mInjector.getBackgroundExecutor(),
                mInjector.getBackgroundHandler());
    }
    private void requestChecksumsInternal(@NonNull String packageName, boolean includeSplits,
            @Checksum.Type int optional,
            @Checksum.Type int required, @Nullable List trustedInstallers,
            @NonNull IntentSender statusReceiver, int userId, @NonNull Executor executor,
            @NonNull Handler handler) {
        Objects.requireNonNull(packageName);
        Objects.requireNonNull(statusReceiver);
        Objects.requireNonNull(executor);
        Objects.requireNonNull(handler);
        final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
                Binder.getCallingUid(), userId);
@@ -2560,10 +2572,10 @@ public class PackageManagerService extends IPackageManager.Stub
        final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates(
                trustedInstallers) : null;
        mInjector.getBackgroundExecutor().execute(() -> {
        executor.execute(() -> {
            ApkChecksums.Injector injector = new ApkChecksums.Injector(
                    () -> mContext,
                    () -> mInjector.getBackgroundHandler(),
                    () -> handler,
                    () -> mInjector.getIncrementalManager());
            ApkChecksums.getChecksums(filesToChecksum, optional, required, trustedCerts,
                    statusReceiver, injector);
@@ -25911,6 +25923,14 @@ public class PackageManagerService extends IPackageManager.Stub
            }
            ps.setStatesOnCrashOrAnr();
        }
        public void requestChecksums(@NonNull String packageName, boolean includeSplits,
                @Checksum.Type int optional, @Checksum.Type int required,
                @Nullable List trustedInstallers, @NonNull IntentSender statusReceiver, int userId,
                @NonNull Executor executor, @NonNull Handler handler) {
            requestChecksumsInternal(packageName, includeSplits, optional, required,
                    trustedInstallers, statusReceiver, userId, executor, handler);
        }
    }
@@ -26060,8 +26080,8 @@ public class PackageManagerService extends IPackageManager.Stub
        if (!SecurityLog.isLoggingEnabled()) {
            return;
        }
        mProcessLoggingHandler.logAppProcessStart(mContext, this, apkFile, packageName, processName,
                uid, seinfo, pid);
        mProcessLoggingHandler.logAppProcessStart(mContext, mPmInternal, apkFile, packageName,
                processName, uid, seinfo, pid);
    }
    public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) {
+35 −39
Original line number Diff line number Diff line
@@ -26,13 +26,12 @@ 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.content.pm.PackageManagerInternal;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
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;
@@ -42,12 +41,11 @@ import com.android.internal.os.BackgroundThread;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;

public final class ProcessLoggingHandler extends Handler {
    private static final String TAG = "ProcessLoggingHandler";

    private static final int LOG_APP_PROCESS_START_MSG = 1;

    private static final int CHECKSUM_TYPE = Checksum.TYPE_WHOLE_SHA256;

    static class LoggingInfo {
@@ -55,6 +53,9 @@ public final class ProcessLoggingHandler extends Handler {
        public List<Bundle> pendingLogEntries = new ArrayList<>();
    }

    // Executor to handle checksum calculations.
    private final Executor mExecutor = new HandlerExecutor(this);

    // Apk path to logging info map.
    private final ArrayMap<String, LoggingInfo> mLoggingInfo = new ArrayMap<>();

@@ -62,25 +63,7 @@ public final class ProcessLoggingHandler extends Handler {
        super(BackgroundThread.getHandler().getLooper());
    }

    @Override
    public void handleMessage(Message msg) {
        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");
                int pid = bundle.getInt("pid");
                String apkHash = bundle.getString("apkHash");
                SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName,
                        startTimestamp, uid, pid, seinfo, apkHash);
                break;
            }
        }
    }

    void logAppProcessStart(Context context, IPackageManager pms, String apkFile,
    void logAppProcessStart(Context context, PackageManagerInternal pmi, String apkFile,
            String packageName, String processName, int uid, String seinfo, int pid) {
        Bundle data = new Bundle();
        data.putLong("startTimestamp", System.currentTimeMillis());
@@ -125,7 +108,7 @@ public final class ProcessLoggingHandler extends Handler {
        // 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,
            pmi.requestChecksums(packageName, false, 0, CHECKSUM_TYPE, null,
                    new IntentSender((IIntentSender) new IIntentSender.Stub() {
                        @Override
                        public void send(int code, Intent intent, String resolvedType,
@@ -133,10 +116,10 @@ public final class ProcessLoggingHandler extends Handler {
                                String requiredPermission, Bundle options) {
                            processChecksums(loggingInfo, intent);
                        }
                    }), context.getUserId());
        } catch (RemoteException e) {
            Slog.e(TAG, "requestChecksums() failed", e);
            processChecksums(loggingInfo, null);
                    }), context.getUserId(), mExecutor, this);
        } catch (Throwable t) {
            Slog.e(TAG, "requestChecksums() failed", t);
            enqueueProcessChecksum(loggingInfo, null);
        }
    }

@@ -148,9 +131,16 @@ public final class ProcessLoggingHandler extends Handler {
        for (ApkChecksum checksum : checksums) {
            if (checksum.getType() == CHECKSUM_TYPE) {
                processChecksum(loggingInfo, checksum.getValue());
                break;
                return;
            }
        }

        Slog.e(TAG, "requestChecksums() failed to return SHA256, see logs for details.");
        processChecksum(loggingInfo, null);
    }

    void enqueueProcessChecksum(final LoggingInfo loggingInfo, final byte[] hash) {
        this.post(() -> processChecksum(loggingInfo, null));
    }

    void processChecksum(final LoggingInfo loggingInfo, final byte[] hash) {
@@ -178,17 +168,9 @@ public final class ProcessLoggingHandler extends Handler {

        if (pendingLogEntries != null) {
            for (Bundle data : pendingLogEntries) {
                enqueueSecurityLogEvent(data, apkHash);
            }
                logSecurityLogEvent(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);
    }

    void invalidateBaseApkHash(String apkFile) {
@@ -196,4 +178,18 @@ public final class ProcessLoggingHandler extends Handler {
            mLoggingInfo.remove(apkFile);
        }
    }

    void enqueueSecurityLogEvent(Bundle data, String apkHash) {
        this.post(() -> logSecurityLogEvent(data, apkHash));
    }

    void logSecurityLogEvent(Bundle bundle, String apkHash) {
        long startTimestamp = bundle.getLong("startTimestamp");
        String processName = bundle.getString("processName");
        int uid = bundle.getInt("uid");
        String seinfo = bundle.getString("seinfo");
        int pid = bundle.getInt("pid");
        SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName,
                startTimestamp, uid, pid, seinfo, apkHash);
    }
}