Replace the usage of UidRange

UidRange is used in a shared way between ConnectivityService
and VPN through the use of NetworkCapabilities. UidRange will
be part of the ConnectivityService mainline but Vpn.java will
stay in the framework. We need a way to replace the APIs using
UidRange, or to make UidRange system API. The only really
relevant surface here is NetworkCapabilities#{setUids, getUids}.
The need for UidRange could be replaced by an integer Range, so
replace the usage of UidRange by a integer Range in
NetworkCapabilities#{setUids, getUids} and update the relevant
callers.

Bug: 172183305
Test: atest FrameworksNetTests CtsNetTestCasesLatestSdk
Change-Id: I4e5aec6ef1ea02e038fcd7ed117a3b67b69c5cb9
This commit is contained in:
Chiachang Wang
2021-02-22 18:36:38 +08:00
parent f134ef3656
commit 265f23d65d
9 changed files with 319 additions and 220 deletions

View File

@@ -32,6 +32,7 @@ import android.os.Parcelable;
import android.os.Process; import android.os.Process;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Range;
import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
@@ -153,7 +154,7 @@ public final class NetworkCapabilities implements Parcelable {
setTransportInfo(null); setTransportInfo(null);
} }
mSignalStrength = nc.mSignalStrength; mSignalStrength = nc.mSignalStrength;
setUids(nc.mUids); // Will make the defensive copy mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids);
setAdministratorUids(nc.getAdministratorUids()); setAdministratorUids(nc.getAdministratorUids());
mOwnerUid = nc.mOwnerUid; mOwnerUid = nc.mOwnerUid;
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities; mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
@@ -1458,9 +1459,8 @@ public final class NetworkCapabilities implements Parcelable {
* @hide * @hide
*/ */
public @NonNull NetworkCapabilities setSingleUid(int uid) { public @NonNull NetworkCapabilities setSingleUid(int uid) {
final ArraySet<UidRange> identity = new ArraySet<>(1); mUids = new ArraySet<>(1);
identity.add(new UidRange(uid, uid)); mUids.add(new UidRange(uid, uid));
setUids(identity);
return this; return this;
} }
@@ -1469,12 +1469,8 @@ public final class NetworkCapabilities implements Parcelable {
* This makes a copy of the set so that callers can't modify it after the call. * This makes a copy of the set so that callers can't modify it after the call.
* @hide * @hide
*/ */
public @NonNull NetworkCapabilities setUids(Set<UidRange> uids) { public @NonNull NetworkCapabilities setUids(@Nullable Set<Range<Integer>> uids) {
if (null == uids) { mUids = UidRange.fromIntRanges(uids);
mUids = null;
} else {
mUids = new ArraySet<>(uids);
}
return this; return this;
} }
@@ -1483,8 +1479,19 @@ public final class NetworkCapabilities implements Parcelable {
* This returns a copy of the set so that callers can't modify the original object. * This returns a copy of the set so that callers can't modify the original object.
* @hide * @hide
*/ */
public @Nullable Set<UidRange> getUids() { public @Nullable Set<Range<Integer>> getUids() {
return null == mUids ? null : new ArraySet<>(mUids); return UidRange.toIntRanges(mUids);
}
/**
* Get the list of UIDs this network applies to.
* This returns a copy of the set so that callers can't modify the original object.
* @hide
*/
public @Nullable Set<UidRange> getUidRanges() {
if (mUids == null) return null;
return new ArraySet<>(mUids);
} }
/** /**

View File

@@ -45,6 +45,7 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.Process; import android.os.Process;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Range;
import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream;
import java.util.Arrays; import java.util.Arrays;
@@ -277,11 +278,11 @@ public class NetworkRequest implements Parcelable {
* Set the watched UIDs for this request. This will be reset and wiped out unless * Set the watched UIDs for this request. This will be reset and wiped out unless
* the calling app holds the CHANGE_NETWORK_STATE permission. * the calling app holds the CHANGE_NETWORK_STATE permission.
* *
* @param uids The watched UIDs as a set of UidRanges, or null for everything. * @param uids The watched UIDs as a set of {@code Range<Integer>}, or null for everything.
* @return The builder to facilitate chaining. * @return The builder to facilitate chaining.
* @hide * @hide
*/ */
public Builder setUids(Set<UidRange> uids) { public Builder setUids(@Nullable Set<Range<Integer>> uids) {
mNetworkCapabilities.setUids(uids); mNetworkCapabilities.setUids(uids);
return this; return this;
} }

View File

@@ -20,8 +20,11 @@ import android.annotation.Nullable;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Range;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
/** /**
* An inclusive range of UIDs. * An inclusive range of UIDs.
@@ -149,4 +152,32 @@ public final class UidRange implements Parcelable {
} }
return false; return false;
} }
/**
* Convert a set of {@code Range<Integer>} to a set of {@link UidRange}.
*/
@Nullable
public static ArraySet<UidRange> fromIntRanges(@Nullable Set<Range<Integer>> ranges) {
if (null == ranges) return null;
final ArraySet<UidRange> uids = new ArraySet<>();
for (Range<Integer> range : ranges) {
uids.add(new UidRange(range.getLower(), range.getUpper()));
}
return uids;
}
/**
* Convert a set of {@link UidRange} to a set of {@code Range<Integer>}.
*/
@Nullable
public static ArraySet<Range<Integer>> toIntRanges(@Nullable Set<UidRange> ranges) {
if (null == ranges) return null;
final ArraySet<Range<Integer>> uids = new ArraySet<>();
for (UidRange range : ranges) {
uids.add(new Range<Integer>(range.start, range.stop));
}
return uids;
}
} }

View File

@@ -1340,7 +1340,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN); netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
netCap.setUids(Collections.singleton(uids)); netCap.setUids(UidRange.toIntRanges(Collections.singleton(uids)));
return netCap; return netCap;
} }
@@ -2873,7 +2873,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (0 == defaultRequest.mRequests.size()) { if (0 == defaultRequest.mRequests.size()) {
pw.println("none, this should never occur."); pw.println("none, this should never occur.");
} else { } else {
pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids()); pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUidRanges());
} }
pw.decreaseIndent(); pw.decreaseIndent();
pw.decreaseIndent(); pw.decreaseIndent();
@@ -5294,9 +5294,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private Set<UidRange> getUids() { private Set<UidRange> getUids() {
// networkCapabilities.getUids() returns a defensive copy. // networkCapabilities.getUids() returns a defensive copy.
// multilayer requests will all have the same uids so return the first one. // multilayer requests will all have the same uids so return the first one.
final Set<UidRange> uids = null == mRequests.get(0).networkCapabilities.getUids() final Set<UidRange> uids = mRequests.get(0).networkCapabilities.getUidRanges();
? new ArraySet<>() : mRequests.get(0).networkCapabilities.getUids(); return (null == uids) ? new ArraySet<>() : uids;
return uids;
} }
NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi, NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
@@ -6102,7 +6101,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (final NetworkRequestInfo nri : mDefaultNetworkRequests) { for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
// Currently, all network requests will have the same uids therefore checking the first // Currently, all network requests will have the same uids therefore checking the first
// one is sufficient. If/when uids are tracked at the nri level, this can change. // one is sufficient. If/when uids are tracked at the nri level, this can change.
final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUids(); final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUidRanges();
if (null == uids) { if (null == uids) {
continue; continue;
} }
@@ -6543,7 +6542,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return; return;
} }
final Set<UidRange> ranges = nai.networkCapabilities.getUids(); final Set<UidRange> ranges = nai.networkCapabilities.getUidRanges();
final int vpnAppUid = nai.networkCapabilities.getOwnerUid(); final int vpnAppUid = nai.networkCapabilities.getOwnerUid();
// TODO: this create a window of opportunity for apps to receive traffic between the time // TODO: this create a window of opportunity for apps to receive traffic between the time
// when the old rules are removed and the time when new rules are added. To fix this, // when the old rules are removed and the time when new rules are added. To fix this,
@@ -6908,8 +6907,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc, private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
NetworkCapabilities newNc) { NetworkCapabilities newNc) {
Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids(); Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUidRanges();
Set<UidRange> newRanges = null == newNc ? null : newNc.getUids(); Set<UidRange> newRanges = null == newNc ? null : newNc.getUidRanges();
if (null == prevRanges) prevRanges = new ArraySet<>(); if (null == prevRanges) prevRanges = new ArraySet<>();
if (null == newRanges) newRanges = new ArraySet<>(); if (null == newRanges) newRanges = new ArraySet<>();
final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges); final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges);
@@ -9240,7 +9239,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final ArrayList<NetworkRequest> nrs = new ArrayList<>(); final ArrayList<NetworkRequest> nrs = new ArrayList<>();
nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities)); nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
nrs.add(createDefaultRequest()); nrs.add(createDefaultRequest());
setNetworkRequestUids(nrs, pref.capabilities.getUids()); setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
final NetworkRequestInfo nri = new NetworkRequestInfo(nrs); final NetworkRequestInfo nri = new NetworkRequestInfo(nrs);
result.add(nri); result.add(nri);
} }
@@ -9456,9 +9455,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests, private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
@NonNull final Set<UidRange> uids) { @NonNull final Set<UidRange> uids) {
final Set<UidRange> ranges = new ArraySet<>(uids);
for (final NetworkRequest req : requests) { for (final NetworkRequest req : requests) {
req.networkCapabilities.setUids(ranges); req.networkCapabilities.setUids(UidRange.toIntRanges(uids));
} }
} }

View File

@@ -19,6 +19,7 @@ package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE; import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.os.UserHandle.PER_USER_RANGE;
import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN; import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
@@ -70,7 +71,6 @@ import android.net.NetworkInfo.DetailedState;
import android.net.NetworkProvider; import android.net.NetworkProvider;
import android.net.NetworkRequest; import android.net.NetworkRequest;
import android.net.RouteInfo; import android.net.RouteInfo;
import android.net.UidRange;
import android.net.UidRangeParcel; import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo; import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager; import android.net.VpnManager;
@@ -1348,7 +1348,7 @@ public class Vpn {
String oldInterface = mInterface; String oldInterface = mInterface;
Connection oldConnection = mConnection; Connection oldConnection = mConnection;
NetworkAgent oldNetworkAgent = mNetworkAgent; NetworkAgent oldNetworkAgent = mNetworkAgent;
Set<UidRange> oldUsers = mNetworkCapabilities.getUids(); Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids();
// Configure the interface. Abort if any of these steps fails. // Configure the interface. Abort if any of these steps fails.
ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
@@ -1454,7 +1454,7 @@ public class Vpn {
} }
/** /**
* Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs * Creates a {@link Set} of non-intersecting {@code Range<Integer>} objects including all UIDs
* associated with one user, and any restricted profiles attached to that user. * associated with one user, and any restricted profiles attached to that user.
* *
* <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
@@ -1467,10 +1467,10 @@ public class Vpn {
* @param disallowedApplications (optional) List of applications to deny. * @param disallowedApplications (optional) List of applications to deny.
*/ */
@VisibleForTesting @VisibleForTesting
Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userId, Set<Range<Integer>> createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
@Nullable List<String> allowedApplications, @Nullable List<String> allowedApplications,
@Nullable List<String> disallowedApplications) { @Nullable List<String> disallowedApplications) {
final Set<UidRange> ranges = new ArraySet<>(); final Set<Range<Integer>> ranges = new ArraySet<>();
// Assign the top-level user to the set of ranges // Assign the top-level user to the set of ranges
addUserToRanges(ranges, userId, allowedApplications, disallowedApplications); addUserToRanges(ranges, userId, allowedApplications, disallowedApplications);
@@ -1494,20 +1494,20 @@ public class Vpn {
} }
/** /**
* Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs * Updates a {@link Set} of non-intersecting {@code Range<Integer>} objects to include all UIDs
* associated with one user. * associated with one user.
* *
* <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided,
* the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs * the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs
* in the user will be included. * in the user will be included.
* *
* @param ranges {@link Set} of {@link UidRange}s to which to add. * @param ranges {@link Set} of {@code Range<Integer>}s to which to add.
* @param userId The userId to add to {@param ranges}. * @param userId The userId to add to {@param ranges}.
* @param allowedApplications (optional) allowlist of applications to include. * @param allowedApplications (optional) allowlist of applications to include.
* @param disallowedApplications (optional) denylist of applications to exclude. * @param disallowedApplications (optional) denylist of applications to exclude.
*/ */
@VisibleForTesting @VisibleForTesting
void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userId, void addUserToRanges(@NonNull Set<Range<Integer>> ranges, @UserIdInt int userId,
@Nullable List<String> allowedApplications, @Nullable List<String> allowedApplications,
@Nullable List<String> disallowedApplications) { @Nullable List<String> disallowedApplications) {
if (allowedApplications != null) { if (allowedApplications != null) {
@@ -1517,40 +1517,41 @@ public class Vpn {
if (start == -1) { if (start == -1) {
start = uid; start = uid;
} else if (uid != stop + 1) { } else if (uid != stop + 1) {
ranges.add(new UidRange(start, stop)); ranges.add(new Range<Integer>(start, stop));
start = uid; start = uid;
} }
stop = uid; stop = uid;
} }
if (start != -1) ranges.add(new UidRange(start, stop)); if (start != -1) ranges.add(new Range<Integer>(start, stop));
} else if (disallowedApplications != null) { } else if (disallowedApplications != null) {
// Add all ranges for user skipping UIDs for disallowedApplications. // Add all ranges for user skipping UIDs for disallowedApplications.
final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); final Range<Integer> userRange = createUidRangeForUser(userId);
int start = userRange.start; int start = userRange.getLower();
for (int uid : getAppsUids(disallowedApplications, userId)) { for (int uid : getAppsUids(disallowedApplications, userId)) {
if (uid == start) { if (uid == start) {
start++; start++;
} else { } else {
ranges.add(new UidRange(start, uid - 1)); ranges.add(new Range<Integer>(start, uid - 1));
start = uid + 1; start = uid + 1;
} }
} }
if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop)); if (start <= userRange.getUpper()) {
ranges.add(new Range<Integer>(start, userRange.getUpper()));
}
} else { } else {
// Add all UIDs for the user. // Add all UIDs for the user.
ranges.add(UidRange.createForUser(UserHandle.of(userId))); ranges.add(createUidRangeForUser(userId));
} }
} }
// Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
// apply to userId. // apply to userId.
private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) { private static List<Range<Integer>> uidRangesForUser(int userId,
// UidRange#createForUser returns the entire range of UIDs available to a macro-user. Set<Range<Integer>> existingRanges) {
// This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE} final Range<Integer> userRange = createUidRangeForUser(userId);
final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); final List<Range<Integer>> ranges = new ArrayList<>();
final List<UidRange> ranges = new ArrayList<>(); for (Range<Integer> range : existingRanges) {
for (UidRange range : existingRanges) { if (userRange.contains(range)) {
if (userRange.containsRange(range)) {
ranges.add(range); ranges.add(range);
} }
} }
@@ -1567,7 +1568,7 @@ public class Vpn {
UserInfo user = mUserManager.getUserInfo(userId); UserInfo user = mUserManager.getUserInfo(userId);
if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
synchronized(Vpn.this) { synchronized(Vpn.this) {
final Set<UidRange> existingRanges = mNetworkCapabilities.getUids(); final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) { if (existingRanges != null) {
try { try {
addUserToRanges(existingRanges, userId, mConfig.allowedApplications, addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
@@ -1595,10 +1596,10 @@ public class Vpn {
UserInfo user = mUserManager.getUserInfo(userId); UserInfo user = mUserManager.getUserInfo(userId);
if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
synchronized(Vpn.this) { synchronized(Vpn.this) {
final Set<UidRange> existingRanges = mNetworkCapabilities.getUids(); final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) { if (existingRanges != null) {
try { try {
final List<UidRange> removedRanges = final List<Range<Integer>> removedRanges =
uidRangesForUser(userId, existingRanges); uidRangesForUser(userId, existingRanges);
existingRanges.removeAll(removedRanges); existingRanges.removeAll(removedRanges);
mNetworkCapabilities.setUids(existingRanges); mNetworkCapabilities.setUids(existingRanges);
@@ -1659,7 +1660,7 @@ public class Vpn {
final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity); final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity);
final Set<UidRangeParcel> rangesToAdd; final Set<UidRangeParcel> rangesToAdd;
if (enforce) { if (enforce) {
final Set<UidRange> restrictedProfilesRanges = final Set<Range<Integer>> restrictedProfilesRanges =
createUserAndRestrictedProfilesRanges(mUserId, createUserAndRestrictedProfilesRanges(mUserId,
/* allowedApplications */ null, /* allowedApplications */ null,
/* disallowedApplications */ exemptedPackages); /* disallowedApplications */ exemptedPackages);
@@ -1668,11 +1669,12 @@ public class Vpn {
// The UID range of the first user (0-99999) would block the IPSec traffic, which comes // The UID range of the first user (0-99999) would block the IPSec traffic, which comes
// directly from the kernel and is marked as uid=0. So we adjust the range to allow // directly from the kernel and is marked as uid=0. So we adjust the range to allow
// it through (b/69873852). // it through (b/69873852).
for (UidRange range : restrictedProfilesRanges) { for (Range<Integer> range : restrictedProfilesRanges) {
if (range.start == 0 && range.stop != 0) { if (range.getLower() == 0 && range.getUpper() != 0) {
rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.stop)); rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.getUpper()));
} else if (range.start != 0) { } else if (range.getLower() != 0) {
rangesThatShouldBeBlocked.add(new UidRangeParcel(range.start, range.stop)); rangesThatShouldBeBlocked.add(
new UidRangeParcel(range.getLower(), range.getUpper()));
} }
} }
@@ -1694,12 +1696,12 @@ public class Vpn {
} }
/** /**
* Tell ConnectivityService to add or remove a list of {@link UidRange}s to the list of UIDs * Tell ConnectivityService to add or remove a list of {@link UidRangeParcel}s to the list of
* that are only allowed to make connections through sockets that have had {@code protect()} * UIDs that are only allowed to make connections through sockets that have had
* called on them. * {@code protect()} called on them.
* *
* @param enforce {@code true} to add to the denylist, {@code false} to remove. * @param enforce {@code true} to add to the denylist, {@code false} to remove.
* @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is * @param ranges {@link Collection} of {@link UidRangeParcel}s to add (if {@param enforce} is
* {@code true}) or to remove. * {@code true}) or to remove.
* @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise, * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise,
* including added ranges that already existed or removed ones that didn't. * including added ranges that already existed or removed ones that didn't.
@@ -3340,4 +3342,12 @@ public class Vpn {
firstChildSessionCallback); firstChildSessionCallback);
} }
} }
/**
* Returns the entire range of UIDs available to a macro-user. This is something like 0-99999.
*/
@VisibleForTesting
static Range<Integer> createUidRangeForUser(int userId) {
return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
}
} }

View File

@@ -69,6 +69,7 @@ import android.net.wifi.aware.WifiAwareNetworkSpecifier;
import android.os.Build; import android.os.Build;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Range;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
@@ -240,9 +241,21 @@ public class NetworkCapabilitiesTest {
@Test @Test
public void testSetUids() { public void testSetUids() {
final NetworkCapabilities netCap = new NetworkCapabilities(); final NetworkCapabilities netCap = new NetworkCapabilities();
final Set<UidRange> uids = new ArraySet<>(); // Null uids match all UIDs
uids.add(new UidRange(50, 100)); netCap.setUids(null);
uids.add(new UidRange(3000, 4000)); assertTrue(netCap.appliesToUid(10));
assertTrue(netCap.appliesToUid(200));
assertTrue(netCap.appliesToUid(3000));
assertTrue(netCap.appliesToUid(10010));
assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
if (isAtLeastS()) {
final Set<Range<Integer>> uids = new ArraySet<>();
uids.add(uidRange(50, 100));
uids.add(uidRange(3000, 4000));
netCap.setUids(uids); netCap.setUids(uids);
assertTrue(netCap.appliesToUid(50)); assertTrue(netCap.appliesToUid(50));
assertTrue(netCap.appliesToUid(80)); assertTrue(netCap.appliesToUid(80));
@@ -275,7 +288,7 @@ public class NetworkCapabilitiesTest {
assertTrue(netCap.equalsUids(netCap2)); assertTrue(netCap.equalsUids(netCap2));
assertTrue(netCap2.equalsUids(netCap)); assertTrue(netCap2.equalsUids(netCap));
uids.add(new UidRange(600, 700)); uids.add(uidRange(600, 700));
netCap2.setUids(uids); netCap2.setUids(uids);
assertFalse(netCap2.satisfiedByUids(netCap)); assertFalse(netCap2.satisfiedByUids(netCap));
assertFalse(netCap.appliesToUid(650)); assertFalse(netCap.appliesToUid(650));
@@ -292,20 +305,29 @@ public class NetworkCapabilitiesTest {
assertFalse(netCap2.appliesToUid(500)); assertFalse(netCap2.appliesToUid(500));
assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000))); assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
assertTrue(new NetworkCapabilities().satisfiedByUids(netCap)); assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
// Null uids satisfies everything.
netCap.setUids(null);
assertTrue(netCap2.satisfiedByUids(netCap));
assertTrue(netCap.satisfiedByUids(netCap2));
netCap2.setUids(null);
assertTrue(netCap2.satisfiedByUids(netCap));
assertTrue(netCap.satisfiedByUids(netCap2));
}
} }
@Test @Test
public void testParcelNetworkCapabilities() { public void testParcelNetworkCapabilities() {
final Set<UidRange> uids = new ArraySet<>(); final Set<Range<Integer>> uids = new ArraySet<>();
uids.add(new UidRange(50, 100)); uids.add(uidRange(50, 100));
uids.add(new UidRange(3000, 4000)); uids.add(uidRange(3000, 4000));
final NetworkCapabilities netCap = new NetworkCapabilities() final NetworkCapabilities netCap = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET) .addCapability(NET_CAPABILITY_INTERNET)
.setUids(uids)
.addCapability(NET_CAPABILITY_EIMS) .addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED); .addCapability(NET_CAPABILITY_NOT_METERED);
if (isAtLeastS()) { if (isAtLeastS()) {
netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)); netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
netCap.setUids(uids);
} else if (isAtLeastR()) { } else if (isAtLeastR()) {
netCap.setOwnerUid(123); netCap.setOwnerUid(123);
netCap.setAdministratorUids(new int[] {5, 11}); netCap.setAdministratorUids(new int[] {5, 11});
@@ -540,12 +562,16 @@ public class NetworkCapabilitiesTest {
assertFalse(nc1.satisfiedByNetworkCapabilities(nc2)); assertFalse(nc1.satisfiedByNetworkCapabilities(nc2));
} }
private ArraySet<UidRange> uidRange(int from, int to) { private ArraySet<Range<Integer>> uidRanges(int from, int to) {
final ArraySet<UidRange> range = new ArraySet<>(1); final ArraySet<Range<Integer>> range = new ArraySet<>(1);
range.add(new UidRange(from, to)); range.add(uidRange(from, to));
return range; return range;
} }
private Range<Integer> uidRange(int from, int to) {
return new Range<Integer>(from, to);
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q) @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testSetAdministratorUids() { public void testSetAdministratorUids() {
NetworkCapabilities nc = NetworkCapabilities nc =
@@ -601,14 +627,15 @@ public class NetworkCapabilitiesTest {
} catch (IllegalStateException expected) {} } catch (IllegalStateException expected) {}
nc1.setSSID(TEST_SSID); nc1.setSSID(TEST_SSID);
nc1.setUids(uidRange(10, 13)); if (isAtLeastS()) {
nc1.setUids(uidRanges(10, 13));
assertNotEquals(nc1, nc2); assertNotEquals(nc1, nc2);
nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything. nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything.
assertNotEquals(nc1, nc2); assertNotEquals(nc1, nc2);
nc1.combineCapabilities(nc2); // 10~13 + everything is everything. nc1.combineCapabilities(nc2); // 10~13 + everything is everything.
assertEquals(nc1, nc2); assertEquals(nc1, nc2);
nc1.setUids(uidRange(10, 13)); nc1.setUids(uidRanges(10, 13));
nc2.setUids(uidRange(20, 23)); nc2.setUids(uidRanges(20, 23));
assertNotEquals(nc1, nc2); assertNotEquals(nc1, nc2);
nc1.combineCapabilities(nc2); nc1.combineCapabilities(nc2);
assertTrue(nc1.appliesToUid(12)); assertTrue(nc1.appliesToUid(12));
@@ -617,7 +644,6 @@ public class NetworkCapabilitiesTest {
assertTrue(nc2.appliesToUid(22)); assertTrue(nc2.appliesToUid(22));
// Verify the subscription id list can be combined only when they are equal. // Verify the subscription id list can be combined only when they are equal.
if (isAtLeastS()) {
nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)); nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
nc2.setSubIds(Set.of(TEST_SUBID2)); nc2.setSubIds(Set.of(TEST_SUBID2));
assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1)); assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
@@ -773,8 +799,11 @@ public class NetworkCapabilitiesTest {
if (isAtLeastR()) { if (isAtLeastR()) {
assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid())); assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
} }
if (isAtLeastS()) {
nc1.setUids(uidRange(10, 13)); nc1.setUids(uidRanges(10, 13));
} else {
nc1.setUids(null);
}
nc2.set(nc1); // Overwrites, as opposed to combineCapabilities nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
assertEquals(nc1, nc2); assertEquals(nc1, nc2);

View File

@@ -44,11 +44,11 @@ import android.net.NetworkProvider;
import android.net.NetworkSpecifier; import android.net.NetworkSpecifier;
import android.net.QosFilter; import android.net.QosFilter;
import android.net.SocketKeepalive; import android.net.SocketKeepalive;
import android.net.UidRange;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Message; import android.os.Message;
import android.util.Log; import android.util.Log;
import android.util.Range;
import com.android.net.module.util.ArrayTrackRecord; import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.connectivity.ConnectivityConstants; import com.android.server.connectivity.ConnectivityConstants;
@@ -222,7 +222,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
} }
public void setUids(Set<UidRange> uids) { public void setUids(Set<Range<Integer>> uids) {
mNetworkCapabilities.setUids(uids); mNetworkCapabilities.setUids(uids);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
} }

View File

@@ -268,6 +268,7 @@ import android.text.TextUtils;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.util.Range;
import android.util.SparseArray; import android.util.SparseArray;
import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry;
@@ -1158,7 +1159,7 @@ public class ConnectivityServiceTest {
} }
public void setUids(Set<UidRange> uids) { public void setUids(Set<UidRange> uids) {
mNetworkCapabilities.setUids(uids); mNetworkCapabilities.setUids(UidRange.toIntRanges(uids));
if (mAgentRegistered) { if (mAgentRegistered) {
mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true); mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
} }
@@ -1448,6 +1449,8 @@ public class ConnectivityServiceTest {
} }
private static final int PRIMARY_USER = 0; private static final int PRIMARY_USER = 0;
private static final UidRange PRIMARY_UIDRANGE =
UidRange.createForUser(UserHandle.of(PRIMARY_USER));
private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100); private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101); private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043); private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
@@ -6940,7 +6943,7 @@ public class ConnectivityServiceTest {
final int uid = Process.myUid(); final int uid = Process.myUid();
NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork()); NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertNotNull("nc=" + nc, nc.getUids()); assertNotNull("nc=" + nc, nc.getUids());
assertEquals(nc.getUids(), uidRangesForUids(uid)); assertEquals(nc.getUids(), UidRange.toIntRanges(uidRangesForUids(uid)));
assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE); assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
// Set an underlying network and expect to see the VPN transports change. // Set an underlying network and expect to see the VPN transports change.
@@ -6965,10 +6968,13 @@ public class ConnectivityServiceTest {
// Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
// restricted user. // restricted user.
final UidRange rRange = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
final Range<Integer> restrictUidRange = new Range<Integer>(rRange.start, rRange.stop);
final Range<Integer> singleUidRange = new Range<Integer>(uid, uid);
callback.expectCapabilitiesThat(mMockVpn, (caps) callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2 -> caps.getUids().size() == 2
&& caps.getUids().contains(new UidRange(uid, uid)) && caps.getUids().contains(singleUidRange)
&& caps.getUids().contains(createUidRange(RESTRICTED_USER)) && caps.getUids().contains(restrictUidRange)
&& caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_WIFI)); && caps.hasTransport(TRANSPORT_WIFI));
@@ -6977,8 +6983,8 @@ public class ConnectivityServiceTest {
callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
callback.expectCapabilitiesThat(mMockVpn, (caps) callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 2 -> caps.getUids().size() == 2
&& caps.getUids().contains(new UidRange(uid, uid)) && caps.getUids().contains(singleUidRange)
&& caps.getUids().contains(createUidRange(RESTRICTED_USER)) && caps.getUids().contains(restrictUidRange)
&& caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI)); && !caps.hasTransport(TRANSPORT_WIFI));
@@ -6992,7 +6998,7 @@ public class ConnectivityServiceTest {
// change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved. // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
callback.expectCapabilitiesThat(mMockVpn, (caps) callback.expectCapabilitiesThat(mMockVpn, (caps)
-> caps.getUids().size() == 1 -> caps.getUids().size() == 1
&& caps.getUids().contains(new UidRange(uid, uid)) && caps.getUids().contains(singleUidRange)
&& caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_WIFI)); && !caps.hasTransport(TRANSPORT_WIFI));
} }
@@ -7650,7 +7656,7 @@ public class ConnectivityServiceTest {
assertNotNull(underlying); assertNotNull(underlying);
mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY); mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
// The legacy lockdown VPN only supports userId 0. // The legacy lockdown VPN only supports userId 0.
final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER)); final Set<UidRange> ranges = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.registerAgent(ranges); mMockVpn.registerAgent(ranges);
mMockVpn.setUnderlyingNetworks(new Network[]{underlying}); mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
mMockVpn.connect(true); mMockVpn.connect(true);
@@ -8612,7 +8618,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it. // The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, VPN_UID, vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -8640,7 +8646,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it. // The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -8656,7 +8662,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0")); lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it. // The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
@@ -8671,7 +8677,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it. // The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.establish(lp, VPN_UID, vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
@@ -8723,7 +8729,7 @@ public class ConnectivityServiceTest {
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it. // The uid range needs to cover the test app so the network is visible to it.
final UidRange vpnRange = createUidRange(PRIMARY_USER); final UidRange vpnRange = PRIMARY_UIDRANGE;
final Set<UidRange> vpnRanges = Collections.singleton(vpnRange); final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges); mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -9004,7 +9010,7 @@ public class ConnectivityServiceTest {
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
throws Exception { throws Exception {
final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
mMockVpn.setVpnType(vpnType); mMockVpn.setVpnType(vpnType);
mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange); mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid); assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
@@ -9564,7 +9570,7 @@ public class ConnectivityServiceTest {
lp.setInterfaceName("tun0"); lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
final UidRange vpnRange = createUidRange(PRIMARY_USER); final UidRange vpnRange = PRIMARY_UIDRANGE;
Set<UidRange> vpnRanges = Collections.singleton(vpnRange); Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
mMockVpn.establish(lp, VPN_UID, vpnRanges); mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
@@ -9762,7 +9768,7 @@ public class ConnectivityServiceTest {
.thenReturn(hasFeature); .thenReturn(hasFeature);
} }
private UidRange getNriFirstUidRange( private Range<Integer> getNriFirstUidRange(
@NonNull final ConnectivityService.NetworkRequestInfo nri) { @NonNull final ConnectivityService.NetworkRequestInfo nri) {
return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next(); return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next();
} }
@@ -9945,11 +9951,11 @@ public class ConnectivityServiceTest {
pref)); pref));
// Sort by uid to access nris by index // Sort by uid to access nris by index
nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).start)); nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).getLower()));
assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).start); assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getLower());
assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).stop); assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getUpper());
assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).start); assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getLower());
assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).stop); assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getUpper());
} }
@Test @Test
@@ -9979,17 +9985,17 @@ public class ConnectivityServiceTest {
// UIDs for all users and all managed packages should be present. // UIDs for all users and all managed packages should be present.
// Two users each with two packages. // Two users each with two packages.
final int expectedUidSize = 2; final int expectedUidSize = 2;
final List<UidRange> uids = final List<Range<Integer>> uids =
new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids()); new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
assertEquals(expectedUidSize, uids.size()); assertEquals(expectedUidSize, uids.size());
// Sort by uid to access nris by index // Sort by uid to access nris by index
uids.sort(Comparator.comparingInt(uid -> uid.start)); uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID); final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
assertEquals(TEST_PACKAGE_UID, uids.get(0).start); assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower());
assertEquals(TEST_PACKAGE_UID, uids.get(0).stop); assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper());
assertEquals(secondUserTestPackageUid, uids.get(1).start); assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower());
assertEquals(secondUserTestPackageUid, uids.get(1).stop); assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
} }
@Test @Test

View File

@@ -23,6 +23,7 @@ import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static android.net.ConnectivityManager.NetworkCallback; import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_DOWN;
import static android.net.INetd.IF_STATE_UP; import static android.net.INetd.IF_STATE_UP;
import static android.os.UserHandle.PER_USER_RANGE;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -74,7 +75,6 @@ import android.net.Network;
import android.net.NetworkCapabilities; import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.DetailedState;
import android.net.RouteInfo; import android.net.RouteInfo;
import android.net.UidRange;
import android.net.UidRangeParcel; import android.net.UidRangeParcel;
import android.net.VpnManager; import android.net.VpnManager;
import android.net.VpnService; import android.net.VpnService;
@@ -181,8 +181,7 @@ public class VpnTest {
mPackages.put(PKGS[i], PKG_UIDS[i]); mPackages.put(PKGS[i], PKG_UIDS[i]);
} }
} }
private static final UidRange PRI_USER_RANGE = private static final Range<Integer> PRI_USER_RANGE = uidRangeForUser(primaryUser.id);
UidRange.createForUser(UserHandle.of(primaryUser.id));
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
@Mock private UserManager mUserManager; @Mock private UserManager mUserManager;
@@ -260,6 +259,21 @@ public class VpnTest {
.thenReturn(tunnelResp); .thenReturn(tunnelResp);
} }
private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
final Set<Range<Integer>> range = new ArraySet<>();
for (Range<Integer> r : ranges) range.add(r);
return range;
}
private static Range<Integer> uidRangeForUser(int userId) {
return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
}
private Range<Integer> uidRange(int start, int stop) {
return new Range<Integer>(start, stop);
}
@Test @Test
public void testRestrictedProfilesAreAddedToVpn() { public void testRestrictedProfilesAreAddedToVpn() {
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB); setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
@@ -268,12 +282,10 @@ public class VpnTest {
// Assume the user can have restricted profiles. // Assume the user can have restricted profiles.
doReturn(true).when(mUserManager).canHaveRestrictedProfile(); doReturn(true).when(mUserManager).canHaveRestrictedProfile();
final Set<UidRange> ranges = final Set<Range<Integer>> ranges =
vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { assertEquals(rangeSet(PRI_USER_RANGE, uidRangeForUser(restrictedProfileA.id)), ranges);
PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id))
})), ranges);
} }
@Test @Test
@@ -281,10 +293,10 @@ public class VpnTest {
setMockedUsers(primaryUser, managedProfileA); setMockedUsers(primaryUser, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null); null, null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges); assertEquals(rangeSet(PRI_USER_RANGE), ranges);
} }
@Test @Test
@@ -292,35 +304,38 @@ public class VpnTest {
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA); setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
final Vpn vpn = createVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final Set<UidRange> ranges = new ArraySet<>(); final Set<Range<Integer>> ranges = new ArraySet<>();
vpn.addUserToRanges(ranges, primaryUser.id, null, null); vpn.addUserToRanges(ranges, primaryUser.id, null, null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges); assertEquals(rangeSet(PRI_USER_RANGE), ranges);
} }
@Test @Test
public void testUidAllowAndDenylist() throws Exception { public void testUidAllowAndDenylist() throws Exception {
final Vpn vpn = createVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = PRI_USER_RANGE; final Range<Integer> user = PRI_USER_RANGE;
final int userStart = user.getLower();
final int userStop = user.getUpper();
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
// Allowed list // Allowed list
final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
Arrays.asList(packages), null); Arrays.asList(packages), null /* disallowedApplications */);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { assertEquals(rangeSet(
new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]), uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]),
new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]) uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2])),
})), allow); allow);
// Denied list // Denied list
final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, final Set<Range<Integer>> disallow =
null, Arrays.asList(packages)); vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { null /* allowedApplications */, Arrays.asList(packages));
new UidRange(user.start, user.start + PKG_UIDS[0] - 1), assertEquals(rangeSet(
new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), uidRange(userStart, userStart + PKG_UIDS[0] - 1),
uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
/* Empty range between UIDS[1] and UIDS[2], should be excluded, */ /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) uidRange(userStart + PKG_UIDS[2] + 1, userStop)),
})), disallow); disallow);
} }
@Test @Test
@@ -350,84 +365,86 @@ public class VpnTest {
@Test @Test
public void testLockdownChangingPackage() throws Exception { public void testLockdownChangingPackage() throws Exception {
final Vpn vpn = createVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = PRI_USER_RANGE; final Range<Integer> user = PRI_USER_RANGE;
final int userStart = user.getLower();
final int userStop = user.getUpper();
// Set always-on without lockdown. // Set always-on without lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null)); assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
// Set always-on with lockdown. // Set always-on with lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null)); assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
})); }));
// Switch to another app. // Switch to another app.
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null)); assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
})); }));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1), new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1),
new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
})); }));
} }
@Test @Test
public void testLockdownAllowlist() throws Exception { public void testLockdownAllowlist() throws Exception {
final Vpn vpn = createVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final UidRange user = PRI_USER_RANGE; final Range<Integer> user = PRI_USER_RANGE;
final int userStart = user.getLower();
final int userStop = user.getUpper();
// Set always-on with lockdown and allow app PKGS[2] from lockdown. // Set always-on with lockdown and allow app PKGS[2] from lockdown.
assertTrue(vpn.setAlwaysOnPackage( assertTrue(vpn.setAlwaysOnPackage(
PKGS[1], true, Collections.singletonList(PKGS[2]))); PKGS[1], true, Collections.singletonList(PKGS[2])));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
})); }));
// Change allowed app list to PKGS[3]. // Change allowed app list to PKGS[3].
assertTrue(vpn.setAlwaysOnPackage( assertTrue(vpn.setAlwaysOnPackage(
PKGS[1], true, Collections.singletonList(PKGS[3]))); PKGS[1], true, Collections.singletonList(PKGS[3])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
})); }));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1), new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
})); }));
// Change the VPN app. // Change the VPN app.
assertTrue(vpn.setAlwaysOnPackage( assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Collections.singletonList(PKGS[3]))); PKGS[0], true, Collections.singletonList(PKGS[3])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1) new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1)
})); }));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1), new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1),
new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1) new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1)
})); }));
// Remove the list of allowed packages. // Remove the list of allowed packages.
assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null)); assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
})); }));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop), new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop),
})); }));
// Add the list of allowed packages. // Add the list of allowed packages.
assertTrue(vpn.setAlwaysOnPackage( assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Collections.singletonList(PKGS[1]))); PKGS[0], true, Collections.singletonList(PKGS[1])));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop)
})); }));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
})); }));
// Try allowing a package with a comma, should be rejected. // Try allowing a package with a comma, should be rejected.
@@ -439,12 +456,12 @@ public class VpnTest {
assertTrue(vpn.setAlwaysOnPackage( assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"))); PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
})); }));
verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1), new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1),
new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
})); }));
} }
@@ -452,7 +469,7 @@ public class VpnTest {
public void testLockdownRuleRepeatability() throws Exception { public void testLockdownRuleRepeatability() throws Exception {
final Vpn vpn = createVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] { final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)}; new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())};
// Given legacy lockdown is already enabled, // Given legacy lockdown is already enabled,
vpn.setLockdown(true); vpn.setLockdown(true);
verify(mConnectivityManager, times(1)).setRequireVpnForUids(true, verify(mConnectivityManager, times(1)).setRequireVpnForUids(true,
@@ -484,7 +501,7 @@ public class VpnTest {
public void testLockdownRuleReversibility() throws Exception { public void testLockdownRuleReversibility() throws Exception {
final Vpn vpn = createVpn(primaryUser.id); final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] entireUser = { final UidRangeParcel[] entireUser = {
new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop) new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())
}; };
final UidRangeParcel[] exceptPkg0 = { final UidRangeParcel[] exceptPkg0 = {
new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1), new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),