diff options
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: |
