From 68daa312bf4e17b2d1a6fd27bad340f76522e30f Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Fri, 11 Aug 2023 20:12:24 +0200 Subject: [PATCH] Fix app not blocked after reinstallation The package name to UID mapping was not updated after reinstallation, causing UID matching to fail and subsequent failure to block it. Now the UID mapping is automatically updated whenever an app is installed or uninstalled. Fixes #338 --- .../remote_capture/CaptureService.java | 8 +-- .../emanuelef/remote_capture/PCAPdroid.java | 54 +++++++++++++++++++ .../remote_capture/model/MatchList.java | 41 +++++++++++++- 3 files changed, 98 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java index b44bf8a6..91e3a1b9 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -509,17 +509,19 @@ public void onReceive(Context context, Intent intent) { if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { boolean newInstall = !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); String packageName = intent.getData().getSchemeSpecificPart(); - Log.i(TAG, "ACTION_PACKAGE_ADDED [new=" + newInstall + "]: " + packageName); if(newInstall && Prefs.blockNewApps(mPrefs)) { - Log.i(TAG, "Blocking newly installed app: " + packageName); - mBlocklist.addApp(packageName); + if(!mBlocklist.addApp(packageName)) + return; + mBlocklist.save(); reloadBlocklist(); AppDescriptor app = AppsResolver.resolveInstalledApp(getPackageManager(), packageName, 0); String label = (app != null) ? app.getName() : packageName; + Log.i(TAG, "Blocking newly installed app: " + packageName + ((app != null) ? " - " + app.getUid() : "")); + PendingIntent pi = PendingIntent.getActivity(CaptureService.this, 0, new Intent(CaptureService.this, FirewallActivity.class), Utils.getIntentFlags(0)); diff --git a/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java b/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java index aff633b9..f98cef00 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java +++ b/app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java @@ -20,7 +20,10 @@ package com.emanuelef.remote_capture; import android.app.Application; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import androidx.annotation.NonNull; @@ -92,6 +95,32 @@ public void onCreate() { theme = "system"; } Utils.setAppTheme(theme); + + // Listen to package events + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addDataScheme("package"); + registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { + boolean newInstall = !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + String packageName = intent.getData().getSchemeSpecificPart(); + Log.d(TAG, "ACTION_PACKAGE_ADDED [new=" + newInstall + "]: " + packageName); + + if(newInstall) + checkUidMapping(packageName); + } else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { + boolean isUpdate = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + String packageName = intent.getData().getSchemeSpecificPart(); + Log.d(TAG, "ACTION_PACKAGE_REMOVED [update=" + isUpdate + "]: " + packageName); + + if(!isUpdate) + checkUidMapping(packageName); + } + } + }, filter); } public static @NonNull PCAPdroid getInstance() { @@ -141,6 +170,31 @@ private void initFirewallWhitelist() { mFirewallWhitelist.save(); } + private void checkUidMapping(String pkg) { + if(mVisMask != null) + mVisMask.uidMappingChanged(pkg); + + // When an app is installed/uninstalled, recheck the UID mappings. + // In particular: + // - On app uninstall, invalidate any package_name -> UID mapping + // - On app install, add the new package_name -> UID mapping + if((mMalwareWhitelist != null) && mMalwareWhitelist.uidMappingChanged(pkg)) + CaptureService.reloadMalwareWhitelist(); + + if((mFirewallWhitelist != null) && mFirewallWhitelist.uidMappingChanged(pkg)) { + if(CaptureService.isServiceActive()) + CaptureService.requireInstance().reloadFirewallWhitelist(); + } + + if((mDecryptionList != null) && mDecryptionList.uidMappingChanged(pkg)) + CaptureService.reloadDecryptionList(); + + if((mBlocklist != null) && mBlocklist.uidMappingChanged(pkg)) { + if(CaptureService.isServiceActive()) + CaptureService.requireInstance().reloadBlocklist(); + } + } + public MatchList getFirewallWhitelist() { if(mFirewallWhitelist == null) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); diff --git a/app/src/main/java/com/emanuelef/remote_capture/model/MatchList.java b/app/src/main/java/com/emanuelef/remote_capture/model/MatchList.java index fe7a1c79..24bada23 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/model/MatchList.java +++ b/app/src/main/java/com/emanuelef/remote_capture/model/MatchList.java @@ -60,6 +60,7 @@ public class MatchList { private final ArrayList mRules = new ArrayList<>(); private final ArrayMap mMatches = new ArrayMap<>(); private final ArraySet mUids = new ArraySet<>(); + private final ArrayMap mPackageToUid = new ArrayMap<>(); private final AppsResolver mResolver; private boolean mMigration = false; @@ -314,6 +315,7 @@ private boolean addRule(Rule rule, boolean notify) { if(uid == Utils.UID_NO_FILTER) return false; + mPackageToUid.put(value, uid); mUids.add(uid); } @@ -352,9 +354,10 @@ public void removeRule(Rule rule) { if(rule.getType() == RuleType.APP) { int uid = mResolver.getUid(val); - if(uid != Utils.UID_NO_FILTER) + if(uid != Utils.UID_NO_FILTER) { + mPackageToUid.remove(val); mUids.remove(uid); - else + } else Log.w(TAG, "removeRule: no uid found for package " + val); } @@ -417,6 +420,7 @@ public void clear(boolean notify) { boolean hasRules = mRules.size() > 0; mRules.clear(); mMatches.clear(); + mPackageToUid.clear(); mUids.clear(); if(notify && hasRules) @@ -510,4 +514,37 @@ private void notifyListeners() { for(ListChangeListener listener: mListeners) listener.onListChanged(); } + + /* Call this whenever a package name -> uid mapping may have changed. + * True is returned when the mapping has been updated. In such a case, + * the caller must reload any native rules based on this MatchList. */ + public boolean uidMappingChanged(String pkg) { + if(!mMatches.containsKey(matchKey(RuleType.APP, pkg))) + return false; + + boolean changed = false; + Integer old_uid = mPackageToUid.get(pkg); + AppDescriptor app = mResolver.getAppByPackage(pkg, 0); + + if((old_uid != null) && ((app == null) || (app.getUid() != old_uid))) { + Log.i(TAG, "Remove old UID mapping of " + pkg + ": " + old_uid); + + mPackageToUid.remove(pkg); + mUids.remove(old_uid); + changed = true; + + old_uid = null; // possibly add the new UID mapping below + } + + if((old_uid == null) && (app != null)) { + int new_uid = app.getUid(); + Log.i(TAG, "Add UID mapping of " + pkg + ": " + new_uid); + + mPackageToUid.put(pkg, new_uid); + mUids.add(new_uid); + changed = true; + } + + return changed; + } }