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

Commit 846ae25b authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Android (Google) Code Review
Browse files

Merge "Allow unprivileged NetworkCallbacks to see other UIDs' networks." into sc-dev

parents 05555262 dc17b3fb
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ package android.net {
    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
    method @Deprecated public boolean getBackgroundDataSetting();
    method @Nullable public android.net.Network getBoundNetworkForProcess();
    method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
@@ -406,6 +406,7 @@ package android.net {
    method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
    method public android.net.NetworkRequest.Builder removeCapability(int);
    method public android.net.NetworkRequest.Builder removeTransportType(int);
    method @NonNull public android.net.NetworkRequest.Builder setIncludeOtherUidNetworks(boolean);
    method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
    method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
  }
+8 −0
Original line number Diff line number Diff line
@@ -1433,10 +1433,18 @@ public class ConnectivityManager {
     * Returns an array of all {@link Network} currently tracked by the
     * framework.
     *
     * @deprecated This method does not provide any notification of network state changes, forcing
     *             apps to call it repeatedly. This is inefficient and prone to race conditions.
     *             Apps should use methods such as
     *             {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} instead.
     *             Apps that desire to obtain information about networks that do not apply to them
     *             can use {@link NetworkRequest.Builder#setIncludeOtherUidNetworks}.
     *
     * @return an array of {@link Network} objects.
     */
    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
    @NonNull
    @Deprecated
    public Network[] getAllNetworks() {
        try {
            return mService.getAllNetworks();
+32 −3
Original line number Diff line number Diff line
@@ -287,10 +287,15 @@ public class NetworkRequest implements Parcelable {
        }

        /**
         * Set the watched UIDs for this request. This will be reset and wiped out unless
         * the calling app holds the CHANGE_NETWORK_STATE permission.
         * Sets this request to match only networks that apply to the specified UIDs.
         *
         * @param uids The watched UIDs as a set of {@code Range<Integer>}, or null for everything.
         * By default, the set of UIDs is the UID of the calling app, and this request will match
         * any network that applies to the app. Setting it to {@code null} will observe any
         * network on the system, even if it does not apply to this app. In this case, any
         * {@link NetworkSpecifier} set on this request will be redacted or removed to prevent the
         * application deducing restricted information such as location.
         *
         * @param uids The UIDs as a set of {@code Range<Integer>}, or null for everything.
         * @return The builder to facilitate chaining.
         * @hide
         */
@@ -517,6 +522,30 @@ public class NetworkRequest implements Parcelable {
            mNetworkCapabilities.setSubscriptionIds(subIds);
            return this;
        }

        /**
         * Specifies whether the built request should also match networks that do not apply to the
         * calling UID.
         *
         * By default, the built request will only match networks that apply to the calling UID.
         * If this method is called with {@code true}, the built request will match any network on
         * the system that matches the other parameters of the request. In this case, any
         * information in the built request that is subject to redaction for security or privacy
         * purposes, such as a {@link NetworkSpecifier}, will be redacted or removed to prevent the
         * application deducing sensitive information.
         *
         * @param include Whether to match networks that do not apply to the calling UID.
         * @return The builder to facilitate chaining.
         */
        @NonNull
        public Builder setIncludeOtherUidNetworks(boolean include) {
            if (include) {
                mNetworkCapabilities.setUids(null);
            } else {
                mNetworkCapabilities.setSingleUid(Process.myUid());
            }
            return this;
        }
    }

    // implement the Parcelable interface
+15 −3
Original line number Diff line number Diff line
@@ -2156,11 +2156,23 @@ public class ConnectivityService extends IConnectivityManager.Stub

    private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc,
            int callerUid, String callerPackageName) {
        // There is no need to track the effective UID of the request here. If the caller
        // lacks the settings permission, the effective UID is the same as the calling ID.
        if (!checkSettingsPermission()) {
            // There is no need to track the effective UID of the request here. If the caller lacks
            // the settings permission, the effective UID is the same as the calling ID.
            // Unprivileged apps can only pass in null or their own UID.
            if (nc.getUids() == null) {
                // If the caller passes in null, the callback will also match networks that do not
                // apply to its UID, similarly to what it would see if it called getAllNetworks.
                // In this case, redact everything in the request immediately. This ensures that the
                // app is not able to get any redacted information by filing an unredacted request
                // and observing whether the request matches something.
                if (nc.getNetworkSpecifier() != null) {
                    nc.setNetworkSpecifier(nc.getNetworkSpecifier().redact());
                }
            } else {
                nc.setSingleUid(callerUid);
            }
        }
        nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
        nc.setAdministratorUids(new int[0]);

+118 −0
Original line number Diff line number Diff line
@@ -4277,6 +4277,124 @@ public class ConnectivityServiceTest {
        mCm.unregisterNetworkCallback(callback);
    }
    @Test
    public void testNetworkCallbackWithNullUids() throws Exception {
        final NetworkRequest request = new NetworkRequest.Builder()
                .removeCapability(NET_CAPABILITY_NOT_VPN)
                .build();
        final TestNetworkCallback callback = new TestNetworkCallback();
        mCm.registerNetworkCallback(request, callback);
        // Attempt to file a callback for networks applying to another UID. This does not actually
        // work, because this code does not currently have permission to do so. The callback behaves
        // exactly the same as the one registered just above.
        final int otherUid = UserHandle.getUid(RESTRICTED_USER, VPN_UID);
        final NetworkRequest otherUidRequest = new NetworkRequest.Builder()
                .removeCapability(NET_CAPABILITY_NOT_VPN)
                .setUids(UidRange.toIntRanges(uidRangesForUids(otherUid)))
                .build();
        final TestNetworkCallback otherUidCallback = new TestNetworkCallback();
        mCm.registerNetworkCallback(otherUidRequest, otherUidCallback);
        final NetworkRequest includeOtherUidsRequest = new NetworkRequest.Builder()
                .removeCapability(NET_CAPABILITY_NOT_VPN)
                .setIncludeOtherUidNetworks(true)
                .build();
        final TestNetworkCallback includeOtherUidsCallback = new TestNetworkCallback();
        mCm.registerNetworkCallback(includeOtherUidsRequest, includeOtherUidsCallback);
        // Both callbacks see a network with no specifier that applies to their UID.
        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
        mWiFiNetworkAgent.connect(false /* validated */);
        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
        otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
        includeOtherUidsCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
        mWiFiNetworkAgent.disconnect();
        callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
        otherUidCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
        includeOtherUidsCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
        // Only the includeOtherUidsCallback sees a VPN that does not apply to its UID.
        final UidRange range = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
        final Set<UidRange> vpnRanges = Collections.singleton(range);
        mMockVpn.establish(new LinkProperties(), VPN_UID, vpnRanges);
        includeOtherUidsCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
        callback.assertNoCallback();
        otherUidCallback.assertNoCallback();
        mMockVpn.disconnect();
        includeOtherUidsCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
        callback.assertNoCallback();
        otherUidCallback.assertNoCallback();
    }
    private static class RedactableNetworkSpecifier extends NetworkSpecifier {
        public static final int ID_INVALID = -1;
        public final int networkId;
        RedactableNetworkSpecifier(int networkId) {
            this.networkId = networkId;
        }
        @Override
        public boolean canBeSatisfiedBy(NetworkSpecifier other) {
            return other instanceof RedactableNetworkSpecifier
                    && this.networkId == ((RedactableNetworkSpecifier) other).networkId;
        }
        @Override
        public NetworkSpecifier redact() {
            return new RedactableNetworkSpecifier(ID_INVALID);
        }
    }
    @Test
    public void testNetworkCallbackWithNullUidsRedactsSpecifier() throws Exception {
        final RedactableNetworkSpecifier specifier = new RedactableNetworkSpecifier(42);
        final NetworkRequest request = new NetworkRequest.Builder()
                .addCapability(NET_CAPABILITY_INTERNET)
                .addTransportType(TRANSPORT_WIFI)
                .setNetworkSpecifier(specifier)
                .build();
        final TestNetworkCallback callback = new TestNetworkCallback();
        mCm.registerNetworkCallback(request, callback);
        // Attempt to file a callback for networks applying to another UID. This does not actually
        // work, because this code does not currently have permission to do so. The callback behaves
        // exactly the same as the one registered just above.
        final int otherUid = UserHandle.getUid(RESTRICTED_USER, VPN_UID);
        final NetworkRequest otherUidRequest = new NetworkRequest.Builder()
                .addCapability(NET_CAPABILITY_INTERNET)
                .addTransportType(TRANSPORT_WIFI)
                .setNetworkSpecifier(specifier)
                .setUids(UidRange.toIntRanges(uidRangesForUids(otherUid)))
                .build();
        final TestNetworkCallback otherUidCallback = new TestNetworkCallback();
        mCm.registerNetworkCallback(otherUidRequest, otherUidCallback);
        final NetworkRequest includeOtherUidsRequest = new NetworkRequest.Builder()
                .addCapability(NET_CAPABILITY_INTERNET)
                .addTransportType(TRANSPORT_WIFI)
                .setNetworkSpecifier(specifier)
                .setIncludeOtherUidNetworks(true)
                .build();
        final TestNetworkCallback includeOtherUidsCallback = new TestNetworkCallback();
        mCm.registerNetworkCallback(includeOtherUidsRequest, callback);
        // Only the regular callback sees the network, because callbacks filed with no UID have
        // their specifiers redacted.
        final LinkProperties emptyLp = new LinkProperties();
        final NetworkCapabilities ncTemplate = new NetworkCapabilities()
                .addTransportType(TRANSPORT_WIFI)
                .setNetworkSpecifier(specifier);
        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, emptyLp, ncTemplate);
        mWiFiNetworkAgent.connect(false /* validated */);
        callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
        otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
        includeOtherUidsCallback.assertNoCallback();
    }
    private void setCaptivePortalMode(int mode) {
        ContentResolver cr = mServiceContext.getContentResolver();
        Settings.Global.putInt(cr, ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, mode);