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 class CaptureService extends VpnService implements Runnable { 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 class PCAPdroid extends Application { 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 @@ public class PCAPdroid extends Application { 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 @@ public class MatchList { if(uid == Utils.UID_NO_FILTER) return false; + mPackageToUid.put(value, uid); mUids.add(uid); } @@ -352,9 +354,10 @@ public class MatchList { 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 class MatchList { boolean hasRules = mRules.size() > 0; mRules.clear(); mMatches.clear(); + mPackageToUid.clear(); mUids.clear(); if(notify && hasRules) @@ -510,4 +514,37 @@ public class MatchList { 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; + } }