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; + } }