summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Mortimer <sam@mortimer.me.uk>2020-05-26 17:56:32 -0700
committerSemavi Ulusoy <doc.divxm@gmail.com>2020-12-10 18:56:15 +0100
commit381b68121525051de6b967f1a07b4a6ae5734ebd (patch)
tree4ae70c51e9608d66698eca2517e5f58fb18961b3
parentf9d17ba6ae3f77ae8bf5c3691694909f247a7cb3 (diff)
fw/b: Add support for per app network isolationr11.0
* Add support for blocking all network access with per uid policy (exposed in wifi/data settings). * When an app is blocked, two things happen: ** Add the uid to a new netd firewall chain fw_isolation which blocks all network access. ** Generate onLost callbacks for ConnectivityManager requests. Move the app network requests to a DetachedNetworks map and remove them from the normal ConnectivityService machinery to ensure no further callbacks are generated. * When an app is unblocked, perform the reverse of the steps above. This includes reattaching the app network requests and triggering onAvailable() callbacks (and others) as though the networks have just come back up. * "Isolation" because the terms blocking and blacklisting are used all over the place already for dozing, powersave and temporary whitelist rules. So be distinct to try to make the code more readable. This includes bellow fix: Author: Oliver Scott <olivercscott@gmail.com> Date: Wed Dec 2 13:38:38 2020 -0500 NetworkPolicyManagerService: Fix network isolation for secondary users * NetworkManager setFirewallUidRule checks that the caller is system uid * Public service entry points are already protected with MANAGE_NETWORK_POLICY permission so simply clear calling identity around NetworkPolicyManagerService setUidFirewallRule() call to resolve crash for secondary users during settings change. Change-Id: Id598264c965aafade8e79b9eeca608711ac49028 Change-Id: Id36308bdb8279879ac456b94704007a392b71b0e
-rw-r--r--core/java/android/net/NetworkPolicyManager.java10
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java177
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java33
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyLogger.java7
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java8
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java76
6 files changed, 307 insertions, 4 deletions
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a3ba180ce46e..661469b03cff 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -79,6 +79,8 @@ public class NetworkPolicyManager {
public static final int POLICY_REJECT_VPN = 0x20000;
/** Reject network usage on wifi network */
public static final int POLICY_REJECT_WIFI = 0x8000;
+ /** Reject network usage on all networks */
+ public static final int POLICY_REJECT_ALL = 0x40000;
/*
* Rules defining whether an uid has access to a network given its type (metered / non-metered).
@@ -128,7 +130,11 @@ public class NetworkPolicyManager {
* @hide
*/
public static final int RULE_REJECT_ALL = 1 << 6;
-
+ /**
+ * Reject traffic on all networks at all times
+ * @hide
+ */
+ public static final int RULE_REJECT_ISOLATED = 1 << 7;
/**
* Mask used to get the {@code RULE_xxx_METERED} rules
* @hide
@@ -150,6 +156,8 @@ public class NetworkPolicyManager {
public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby";
/** @hide */
public static final String FIREWALL_CHAIN_NAME_POWERSAVE = "powersave";
+ /** @hide */
+ public static final String FIREWALL_CHAIN_NAME_ISOLATED = "isolated";
private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1227121f2024..7ac20de9e840 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -175,6 +175,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.Xml;
@@ -667,6 +668,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
final Map<IBinder, ConnectivityDiagnosticsCallbackInfo> mConnectivityDiagnosticsCallbacks =
new HashMap<>();
+ // Tracking for network isolated uids
+ //
+ @GuardedBy("mIsolatedUids")
+ private final SparseBooleanArray mIsolatedUids = new SparseBooleanArray();
+ // Network requests that are still active but will not receive any callbacks
+ // owing to the calling uid beging network isolated. Only accessed on
+ // event handler thread so no locking necessary.
+ private final HashMap<NetworkRequest, NetworkRequestInfo> mDetachedRequests = new HashMap<>();
+
/**
* Implements support for the legacy "one network per network type" model.
*
@@ -1341,6 +1351,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/
private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid,
boolean ignoreBlocked) {
+ // Network isolation should be checked first since it overrides ignore blocked status.
+ if (isUidIsolated(uid)) {
+ return true;
+ }
// Networks aren't blocked when ignoring blocked status
if (ignoreBlocked) {
return false;
@@ -1509,6 +1523,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public NetworkInfo[] getAllNetworkInfo() {
enforceAccessPermission();
+ if (isUidIsolated(Binder.getCallingUid())) {
+ // If a uid is network isolated, do not provide any visibility.
+ return new NetworkInfo[0];
+ }
+
final ArrayList<NetworkInfo> result = Lists.newArrayList();
for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
networkType++) {
@@ -1534,6 +1553,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public Network[] getAllNetworks() {
enforceAccessPermission();
+ if (isUidIsolated(Binder.getCallingUid())) {
+ // If a uid is network isolated, do not provide any visibility.
+ return new Network[0];
+ }
synchronized (mNetworkForNetId) {
final Network[] result = new Network[mNetworkForNetId.size()];
for (int i = 0; i < mNetworkForNetId.size(); i++) {
@@ -2005,6 +2028,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
final int oldRules = mUidRules.get(uid, RULE_NONE);
if (oldRules == newRules) return;
+ final boolean wasIsolated =
+ mPolicyManagerInternal.isNetworkingIsolatedByUidRules(oldRules);
+ final boolean isIsolated =
+ mPolicyManagerInternal.isNetworkingIsolatedByUidRules(newRules);
+ if (isIsolated != wasIsolated) {
+ if (isIsolated) {
+ setUidIsolated(uid);
+ } else {
+ clearUidIsolated(uid);
+ }
+ }
+
maybeNotifyNetworkBlockedForNewUidRules(uid, newRules);
if (newRules == RULE_NONE) {
@@ -2014,6 +2049,110 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void setUidIsolated(int uid) {
+ synchronized (mIsolatedUids) {
+ mIsolatedUids.put(uid, true);
+ }
+ detachNetworkRequestsForUid(uid);
+ }
+
+ private void clearUidIsolated(int uid) {
+ synchronized (mIsolatedUids) {
+ mIsolatedUids.delete(uid);
+ }
+ reattachNetworkRequestsForUid(uid);
+ }
+
+ private boolean isUidIsolated(int uid) {
+ synchronized (mIsolatedUids) {
+ return mIsolatedUids.get(uid);
+ }
+ }
+
+ private void addDetachedRequest(NetworkRequestInfo nri) {
+ mDetachedRequests.put(nri.request, nri);
+ }
+
+ // App has died or callback is being unregistered, clean up.
+ // Match callback by PendingIntent.
+ private boolean removeDetachedNetworkRequests(PendingIntent pendingIntent, int uid) {
+ // Use same logic as findExistingNetworkRequestInfo()
+ Intent intent = pendingIntent.getIntent();
+ for (NetworkRequestInfo nri : mDetachedRequests.values()) {
+ PendingIntent existingPendingIntent = nri.mPendingIntent;
+ if (existingPendingIntent != null &&
+ existingPendingIntent.getIntent().filterEquals(intent)) {
+ return removeDetachedNetworkRequests(nri, uid);
+ }
+ }
+ return false;
+ }
+
+ // App has died or callback is being unregistered, clean up.
+ // Match callback by NetworkRequest.
+ private boolean removeDetachedNetworkRequests(NetworkRequest request, int uid) {
+ return removeDetachedNetworkRequests(mDetachedRequests.get(request), uid);
+ }
+
+ private boolean removeDetachedNetworkRequests(NetworkRequestInfo nri, int uid) {
+ // binderDied() runs as system uid so allow clean up
+ if (nri != null && (nri.mUid == uid || uid == Process.SYSTEM_UID)) {
+ nri.unlinkDeathRecipient();
+ mDetachedRequests.remove(nri.request);
+ return true;
+ }
+ return false;
+ }
+
+ private void detachNetworkRequestsForUid(int uid) {
+ // Collect network requests for this uid
+ final List<NetworkRequestInfo> nriList = new ArrayList<>();
+ for (NetworkRequestInfo nri : mNetworkRequests.values()) {
+ if (nri != null && nri.mUid == uid) {
+ nriList.add(nri);
+ }
+ }
+ for (NetworkRequestInfo nri : nriList) {
+ if (VDBG || DDBG) {
+ Log.d(TAG, "detaching request " + nri);
+ }
+
+ // Trigger onLost callbacks for matching networks
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (nai.isSatisfyingRequest(nri.request.requestId)) {
+ if (VDBG || DDBG) {
+ Log.d(TAG, "sending onLost to " + nri + " for " + nai);
+ }
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
+ }
+ }
+ // Remove the request from normal ConnectivityService machinery.
+ // This prevents receiving any further callbacks.
+ handleRemoveNetworkRequest(nri);
+ // Go through nri constructor to reinitialize things cleaned up
+ // by handleRemoveNetworkRequest(). eg updating per uid
+ // reference counts and setting binder linkToDeath.
+ mDetachedRequests.put(nri.request, new NetworkRequestInfo(nri));
+ }
+ }
+
+ private void reattachNetworkRequestsForUid(int uid) {
+ // Collect network requests for this uid
+ final List<NetworkRequestInfo> nriList = new ArrayList<>();
+ for (NetworkRequestInfo nri : mDetachedRequests.values()) {
+ if (nri != null && nri.mUid == uid) {
+ nriList.add(nri);
+ }
+ }
+ for (NetworkRequestInfo nri : nriList) {
+ if (VDBG || DDBG) {
+ Log.d(TAG, "reattaching request " + nri);
+ }
+ mDetachedRequests.remove(nri.request);
+ handleRegisterNetworkRequest(nri);
+ }
+ }
+
void handleRestrictBackgroundChanged(boolean restrictBackground) {
if (mRestrictBackground == restrictBackground) return;
@@ -3451,12 +3590,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
+ nri.request + " because their intents matched.");
handleReleaseNetworkRequest(existingRequest.request, getCallingUid(),
/* callOnUnavailable */ false);
+ } else {
+ // Remove anything on the detached list
+ removeDetachedNetworkRequests(nri.mPendingIntent, Binder.getCallingUid());
}
handleRegisterNetworkRequest(nri);
}
private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
ensureRunningOnConnectivityServiceThread();
+ if (isUidIsolated(nri.mUid)) {
+ addDetachedRequest(nri);
+ return;
+ }
mNetworkRequests.put(nri.request, nri);
mNetworkRequestInfoLogs.log("REGISTER " + nri);
if (nri.request.isListen()) {
@@ -3475,6 +3621,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void handleReleaseNetworkRequestWithIntent(PendingIntent pendingIntent,
int callingUid) {
+ if (removeDetachedNetworkRequests(pendingIntent, callingUid)) {
+ // Was already released during detach so nothing further to do.
+ return;
+ }
NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent);
if (nri != null) {
handleReleaseNetworkRequest(nri.request, callingUid, /* callOnUnavailable */ false);
@@ -3565,6 +3715,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid,
boolean callOnUnavailable) {
+ if (removeDetachedNetworkRequests(request, callingUid)) {
+ // Was already released during detach so nothing further to do.
+ if (VDBG || DDBG) {
+ Log.d(TAG, "removed detached request = " + request + " uid = " + callingUid);
+ }
+ return;
+ }
+
final NetworkRequestInfo nri =
getNriForAppRequest(request, callingUid, "release NetworkRequest");
if (nri == null) {
@@ -5394,6 +5552,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
this(r, null);
}
+ // Recreate new from a previously detached request.
+ NetworkRequestInfo(NetworkRequestInfo nri) {
+ request = nri.request;
+ messenger = nri.messenger;
+ mBinder = nri.mBinder;
+ mPendingIntent = nri.mPendingIntent;
+ mPid = nri.mPid;
+ mUid = nri.mUid;
+ enforceRequestCountLimit();
+
+ if (mBinder != null) {
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+ }
+
private void enforceRequestCountLimit() {
synchronized (mUidToNetworkRequestCount) {
int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index f40f64d06b15..5362e7a65129 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.INetd.FIREWALL_BLACKLIST;
import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_ISOLATED;
import static android.net.INetd.FIREWALL_CHAIN_NONE;
import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
@@ -29,6 +30,7 @@ import static android.net.INetd.FIREWALL_RULE_ALLOW;
import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.INetd.FIREWALL_WHITELIST;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_ISOLATED;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
@@ -219,6 +221,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
*/
@GuardedBy("mRulesLock")
private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
+ /**
+ * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches
+ * unconditionally at all times.
+ */
+ @GuardedBy("mRulesLock")
+ private SparseIntArray mUidFirewallIsolatedRules = new SparseIntArray();
/** Set of states for the child firewall chains. True if the chain is active. */
@GuardedBy("mRulesLock")
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -714,9 +722,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, "standby ");
syncFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, "dozable ");
syncFirewallChainLocked(FIREWALL_CHAIN_POWERSAVE, "powersave ");
+ syncFirewallChainLocked(FIREWALL_CHAIN_ISOLATED, "isolated ");
final int[] chains =
- {FIREWALL_CHAIN_STANDBY, FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_POWERSAVE};
+ {FIREWALL_CHAIN_STANDBY, FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_ISOLATED};
for (int chain : chains) {
if (getFirewallChainState(chain)) {
setFirewallChainEnabled(chain, true);
@@ -1908,6 +1918,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
return FIREWALL_CHAIN_NAME_DOZABLE;
case FIREWALL_CHAIN_POWERSAVE:
return FIREWALL_CHAIN_NAME_POWERSAVE;
+ case FIREWALL_CHAIN_ISOLATED:
+ return FIREWALL_CHAIN_NAME_ISOLATED;
default:
throw new IllegalArgumentException("Bad child chain: " + chain);
}
@@ -1921,6 +1933,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
return FIREWALL_WHITELIST;
case FIREWALL_CHAIN_POWERSAVE:
return FIREWALL_WHITELIST;
+ case FIREWALL_CHAIN_ISOLATED:
+ return FIREWALL_BLACKLIST;
default:
return isFirewallEnabled() ? FIREWALL_WHITELIST : FIREWALL_BLACKLIST;
}
@@ -1965,6 +1979,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
case FIREWALL_CHAIN_POWERSAVE:
mNetdService.firewallReplaceUidChain("fw_powersave", true, uids);
break;
+ case FIREWALL_CHAIN_ISOLATED:
+ mNetdService.firewallReplaceUidChain("fw_isolated", false, uids);
+ break;
case FIREWALL_CHAIN_NONE:
default:
Slog.d(TAG, "setFirewallUidRules() called on invalid chain: " + chain);
@@ -2049,6 +2066,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
return mUidFirewallDozableRules;
case FIREWALL_CHAIN_POWERSAVE:
return mUidFirewallPowerSaveRules;
+ case FIREWALL_CHAIN_ISOLATED:
+ return mUidFirewallIsolatedRules;
case FIREWALL_CHAIN_NONE:
return mUidFirewallRules;
default:
@@ -2134,6 +2153,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
pw.println("UID firewall powersave chain enabled: " +
getFirewallChainState(FIREWALL_CHAIN_POWERSAVE));
dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
+
+ pw.println("UID firewall isolated chain enabled: " +
+ getFirewallChainState(FIREWALL_CHAIN_ISOLATED));
+ dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_ISOLATED, mUidFirewallIsolatedRules);
}
synchronized (mIdleTimerLock) {
@@ -2312,6 +2335,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
private boolean isNetworkRestrictedInternal(int uid) {
synchronized (mRulesLock) {
+ if (getFirewallChainState(FIREWALL_CHAIN_ISOLATED)
+ && mUidFirewallIsolatedRules.get(uid) == FIREWALL_RULE_DENY) {
+ if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of isolated mode");
+ return true;
+ }
if (getFirewallChainState(FIREWALL_CHAIN_STANDBY)
&& mUidFirewallStandbyRules.get(uid) == FIREWALL_RULE_DENY) {
if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of app standby mode");
@@ -2397,7 +2425,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
final int[] chains = {
FIREWALL_CHAIN_DOZABLE,
FIREWALL_CHAIN_STANDBY,
- FIREWALL_CHAIN_POWERSAVE
+ FIREWALL_CHAIN_POWERSAVE,
+ FIREWALL_CHAIN_ISOLATED
};
for (int chain : chains) {
setFirewallChainState(chain, false);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 3bd18f9a360f..94e62d91495c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -16,11 +16,13 @@
package com.android.server.net;
import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_ISOLATED;
import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
import static android.net.INetd.FIREWALL_RULE_ALLOW;
import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_ISOLATED;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
@@ -76,6 +78,7 @@ public class NetworkPolicyLogger {
static final int NTWK_BLOCKED_BG_RESTRICT = 5;
static final int NTWK_ALLOWED_DEFAULT = 6;
static final int NTWK_ALLOWED_SYSTEM = 7;
+ static final int NTWK_BLOCKED_ISOLATED = 8;
private final LogBuffer mNetworkBlockedBuffer = new LogBuffer(MAX_NETWORK_BLOCKED_LOG_SIZE);
private final LogBuffer mUidStateChangeBuffer = new LogBuffer(MAX_LOG_SIZE);
@@ -279,6 +282,8 @@ public class NetworkPolicyLogger {
return "blocked when background is restricted";
case NTWK_ALLOWED_DEFAULT:
return "allowed by default";
+ case NTWK_BLOCKED_ISOLATED:
+ return "blocked by isolation";
default:
return String.valueOf(reason);
}
@@ -339,6 +344,8 @@ public class NetworkPolicyLogger {
return FIREWALL_CHAIN_NAME_STANDBY;
case FIREWALL_CHAIN_POWERSAVE:
return FIREWALL_CHAIN_NAME_POWERSAVE;
+ case FIREWALL_CHAIN_ISOLATED:
+ return FIREWALL_CHAIN_NAME_ISOLATED;
default:
return String.valueOf(chain);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 48f1ddb023fd..7c05c50a7bcd 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -16,6 +16,7 @@
package com.android.server.net;
+import static com.android.server.net.NetworkPolicyManagerService.isNetworkingIsolatedByUidRulesInternal;
import static com.android.server.net.NetworkPolicyManagerService.isUidNetworkingBlockedInternal;
import android.annotation.NonNull;
@@ -44,6 +45,13 @@ public abstract class NetworkPolicyManagerInternal {
public abstract boolean isUidRestrictedOnMeteredNetworks(int uid);
/**
+ * @return true if the uid rules provided mean that network access should be blocked.
+ */
+ public static boolean isNetworkingIsolatedByUidRules(int uidRules) {
+ return isNetworkingIsolatedByUidRulesInternal(uidRules);
+ };
+
+ /**
* @return true if networking is blocked on the given interface for the given uid according
* to current networking policies.
*/
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index db7643384075..975325b65010 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -43,6 +43,7 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
+import static android.net.INetd.FIREWALL_CHAIN_ISOLATED;
import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
import static android.net.INetd.FIREWALL_RULE_ALLOW;
@@ -58,6 +59,7 @@ import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_ALL;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_REJECT_CELLULAR;
@@ -65,6 +67,7 @@ import static android.net.NetworkPolicyManager.POLICY_REJECT_VPN;
import static android.net.NetworkPolicyManager.POLICY_REJECT_WIFI;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ISOLATED;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -111,6 +114,7 @@ import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_WHITEL
import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_WHITELIST;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BLACKLIST;
+import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_ISOLATED;
import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
@@ -471,6 +475,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
@GuardedBy("mUidRulesFirstLock")
final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
+ @GuardedBy("mUidRulesFirstLock")
+ final SparseIntArray mUidFirewallIsolatedRules = new SparseIntArray();
/** Set of states for the child firewall chains. True if the chain is active. */
@GuardedBy("mUidRulesFirstLock")
@@ -813,6 +819,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
setRestrictBackgroundUL(mLoadedRestrictBackground, "init_service");
updateRulesForGlobalChangeAL(false);
updateNotificationsNL();
+ // Enable the network isolated blacklist chain
+ enableFirewallChainUL(FIREWALL_CHAIN_ISOLATED, true);
}
}
@@ -2587,6 +2595,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (!UserHandle.isApp(uid)) {
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
+
+ if (LOGD) {
+ Log.d(TAG, "setUidPolicy: uid = " + uid + " policy = " + policy);
+ }
+
synchronized (mUidRulesFirstLock) {
final long token = Binder.clearCallingIdentity();
try {
@@ -2609,6 +2622,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
+ if (LOGD) {
+ Log.d(TAG, "addUidPolicy: uid = " + uid + " policy = " + policy);
+ }
+
synchronized (mUidRulesFirstLock) {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
policy |= oldPolicy;
@@ -2627,6 +2644,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
throw new IllegalArgumentException("cannot apply policy to UID " + uid);
}
+ if (LOGD) {
+ Log.d(TAG, "removeUidPolicy: uid = " + uid + " policy = " + policy);
+ }
+
synchronized (mUidRulesFirstLock) {
final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
policy = oldPolicy & ~policy;
@@ -2679,6 +2700,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// uid policy changed, recompute rules and persist policy.
updateRulesForDataUsageRestrictionsUL(uid);
+ updateRulesForIsolatedUL(uid);
if (persist) {
synchronized (mNetworkPoliciesSecondLock) {
writePolicyAL();
@@ -4220,6 +4242,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mUidFirewallStandbyRules.delete(uid);
mUidFirewallDozableRules.delete(uid);
mUidFirewallPowerSaveRules.delete(uid);
+ mUidFirewallIsolatedRules.delete(uid);
mPowerSaveWhitelistExceptIdleAppIds.delete(uid);
mPowerSaveWhitelistAppIds.delete(uid);
mPowerSaveTempWhitelistAppIds.delete(uid);
@@ -4254,6 +4277,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// Update firewall and internal rules for Data Saver Mode.
updateRulesForDataUsageRestrictionsUL(uid);
+ updateRulesForIsolatedUL(uid);
}
/**
@@ -4426,6 +4450,42 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void updateRulesForIsolatedUL(int uid) {
+ final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
+ final int oldUidRules = mUidRules.get(uid, RULE_NONE);
+ final boolean wasIsolated = (oldUidRules & RULE_REJECT_ISOLATED) != 0;
+ final boolean isIsolated = (uidPolicy & POLICY_REJECT_ALL) != 0;
+
+ if (isIsolated == wasIsolated) {
+ // No change
+ return;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ setUidFirewallRule(FIREWALL_CHAIN_ISOLATED, uid,
+ isIsolated ? FIREWALL_RULE_DENY : FIREWALL_RULE_DEFAULT);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ int uidRules = oldUidRules;
+ if (isIsolated) {
+ uidRules |= RULE_REJECT_ISOLATED;
+ } else {
+ uidRules &= ~RULE_REJECT_ISOLATED;
+ }
+
+ if (uidRules == RULE_NONE) {
+ mUidRules.delete(uid);
+ } else {
+ mUidRules.put(uid, uidRules);
+ }
+
+ // Dispatch changed rule to existing listeners.
+ mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
+ }
+
/**
* Updates the power-related part of the {@link #mUidRules} for a given map, and notify external
* listeners in case of change.
@@ -4508,7 +4568,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
newRule = isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL;
}
- final int newUidRules = (oldUidRules & MASK_METERED_NETWORKS) | newRule;
+ // Generate new uid rules, ensuring we persist any existing
+ // metered networks and network isolated rules.
+ final int newUidRules = (oldUidRules
+ & (MASK_METERED_NETWORKS | RULE_REJECT_ISOLATED)) | newRule;
if (LOGV) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
@@ -4984,6 +5047,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mUidFirewallStandbyRules.put(uid, rule);
} else if (chain == FIREWALL_CHAIN_POWERSAVE) {
mUidFirewallPowerSaveRules.put(uid, rule);
+ } else if (chain == FIREWALL_CHAIN_ISOLATED) {
+ mUidFirewallIsolatedRules.put(uid, rule);
}
try {
@@ -5029,6 +5094,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
mNetworkManager
.setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT);
+ mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_ISOLATED, uid, FIREWALL_RULE_DEFAULT);
mNetworkManager.setUidMeteredNetworkWhitelist(uid, false);
mNetworkManager.setUidMeteredNetworkBlacklist(uid, false);
} catch (IllegalStateException e) {
@@ -5209,6 +5275,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return uid < Process.FIRST_APPLICATION_UID;
}
+ static boolean isNetworkingIsolatedByUidRulesInternal(int uidRules) {
+ return hasRule(uidRules, RULE_REJECT_ISOLATED);
+ }
+
static boolean isUidNetworkingBlockedInternal(int uid, int uidRules, boolean isNetworkMetered,
boolean isBackgroundRestricted, @Nullable NetworkPolicyLogger logger) {
final int reason;
@@ -5216,6 +5286,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (isSystem(uid)) {
reason = NTWK_ALLOWED_SYSTEM;
}
+ else if (hasRule(uidRules, RULE_REJECT_ISOLATED)) {
+ reason = NTWK_BLOCKED_ISOLATED;
+ }
else if (hasRule(uidRules, RULE_REJECT_ALL)) {
reason = NTWK_BLOCKED_POWER;
}
@@ -5250,6 +5323,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
case NTWK_BLOCKED_POWER:
case NTWK_BLOCKED_BLACKLIST:
case NTWK_BLOCKED_BG_RESTRICT:
+ case NTWK_BLOCKED_ISOLATED:
blocked = true;
break;
default: