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
This commit is contained in:
emanuele-f 2023-08-11 20:12:24 +02:00
parent e2c5b81d4f
commit 68daa312bf
3 changed files with 98 additions and 5 deletions

View File

@ -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));

View File

@ -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);

View File

@ -60,6 +60,7 @@ public class MatchList {
private final ArrayList<Rule> mRules = new ArrayList<>();
private final ArrayMap<String, Rule> mMatches = new ArrayMap<>();
private final ArraySet<Integer> mUids = new ArraySet<>();
private final ArrayMap<String, Integer> 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;
}
}