Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fbe9b1ad authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

Restrict access to background networks to CHANGE_NETWORK_STATE.

When a network goes into the background, tell netd to set the
network's permission to NETWORK. Also, close all TCP sockets on
that network, to prevent long-lived TCP connections from staying
on it and possibly continuing to use metered data.

Bug: 23113288
Change-Id: Ie89c1940b6739160e25c6e9022b8b977afb3e16e
parent 488ca21f
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1825,6 +1825,16 @@ public class ConnectivityManager {
        return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    /* TODO: These permissions checks don't belong in client-side code. Move them to
     * services.jar, possibly in com.android.server.net. */

    /** {@hide} */
    public static final boolean checkChangePermission(Context context) {
        int uid = Binder.getCallingUid();
        return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings
                .getPackageNameForUid(context, uid), false /* throwException */);
    }

    /** {@hide} */
    public static final void enforceChangePermission(Context context) {
        int uid = Binder.getCallingUid();
+27 −10
Original line number Diff line number Diff line
@@ -4330,8 +4330,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
            enforceAccessPermission();
        }

        NetworkRequest networkRequest = new NetworkRequest(
                new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
        NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
        if (!ConnectivityManager.checkChangePermission(mContext)) {
            // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
            // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
            // onLost and onAvailable callbacks when networks move in and out of the background.
            // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
            // can't request networks.
            nc.addCapability(NET_CAPABILITY_FOREGROUND);
        }

        NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                NetworkRequest.Type.LISTEN);
        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);
        if (VDBG) log("listenForNetwork for " + nri);
@@ -4646,6 +4655,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
        mNumDnsEntries = last;
    }

    private String getNetworkPermission(NetworkCapabilities nc) {
        // TODO: make these permission strings AIDL constants instead.
        if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
            return NetworkManagementService.PERMISSION_SYSTEM;
        }
        if (!nc.hasCapability(NET_CAPABILITY_FOREGROUND)) {
            return NetworkManagementService.PERMISSION_NETWORK;
        }
        return null;
    }

    /**
     * Update the NetworkCapabilities for {@code networkAgent} to {@code networkCapabilities}
     * augmented with any stateful capabilities implied from {@code networkAgent}
@@ -4684,12 +4704,11 @@ public class ConnectivityService extends IConnectivityManager.Stub

        if (Objects.equals(nai.networkCapabilities, networkCapabilities)) return;

        if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) !=
                networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
        final String oldPermission = getNetworkPermission(nai.networkCapabilities);
        final String newPermission = getNetworkPermission(networkCapabilities);
        if (!Objects.equals(oldPermission, newPermission) && nai.created && !nai.isVPN()) {
            try {
                mNetd.setNetworkPermission(nai.network.netId,
                        networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) ?
                                null : NetworkManagementService.PERMISSION_SYSTEM);
                mNetd.setNetworkPermission(nai.network.netId, newPermission);
            } catch (RemoteException e) {
                loge("Exception in setNetworkPermission: " + e);
            }
@@ -5259,9 +5278,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
                                !networkAgent.networkMisc.allowBypass));
                } else {
                    mNetd.createPhysicalNetwork(networkAgent.network.netId,
                            networkAgent.networkCapabilities.hasCapability(
                                    NET_CAPABILITY_NOT_RESTRICTED) ?
                                    null : NetworkManagementService.PERMISSION_SYSTEM);
                            getNetworkPermission(networkAgent.networkCapabilities));
                }
            } catch (Exception e) {
                loge("Error creating network " + networkAgent.network.netId + ": "