Add API for apps to check if they are the network owner
This CL extends NetworkCapabilities#mEstablishingVpnAppUid to the network owner app UID and introduces a new public API to get this owner app's UID. Bug: 142072839 Test: atest FrameworksNetTests Change-Id: Id83cdea62b89b586aff74e51e3fee60e53d37d4c
This commit is contained in:
@@ -26,6 +26,7 @@ import android.net.ConnectivityManager.NetworkCallback;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.Process;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.proto.ProtoOutputStream;
|
import android.util.proto.ProtoOutputStream;
|
||||||
|
|
||||||
@@ -58,7 +59,6 @@ import java.util.StringJoiner;
|
|||||||
*/
|
*/
|
||||||
public final class NetworkCapabilities implements Parcelable {
|
public final class NetworkCapabilities implements Parcelable {
|
||||||
private static final String TAG = "NetworkCapabilities";
|
private static final String TAG = "NetworkCapabilities";
|
||||||
private static final int INVALID_UID = -1;
|
|
||||||
|
|
||||||
// Set to true when private DNS is broken.
|
// Set to true when private DNS is broken.
|
||||||
private boolean mPrivateDnsBroken;
|
private boolean mPrivateDnsBroken;
|
||||||
@@ -85,8 +85,8 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
mTransportInfo = null;
|
mTransportInfo = null;
|
||||||
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
|
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
|
||||||
mUids = null;
|
mUids = null;
|
||||||
mEstablishingVpnAppUid = INVALID_UID;
|
|
||||||
mAdministratorUids.clear();
|
mAdministratorUids.clear();
|
||||||
|
mOwnerUid = Process.INVALID_UID;
|
||||||
mSSID = null;
|
mSSID = null;
|
||||||
mPrivateDnsBroken = false;
|
mPrivateDnsBroken = false;
|
||||||
}
|
}
|
||||||
@@ -104,8 +104,8 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
mTransportInfo = nc.mTransportInfo;
|
mTransportInfo = nc.mTransportInfo;
|
||||||
mSignalStrength = nc.mSignalStrength;
|
mSignalStrength = nc.mSignalStrength;
|
||||||
setUids(nc.mUids); // Will make the defensive copy
|
setUids(nc.mUids); // Will make the defensive copy
|
||||||
mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
|
|
||||||
setAdministratorUids(nc.mAdministratorUids);
|
setAdministratorUids(nc.mAdministratorUids);
|
||||||
|
mOwnerUid = nc.mOwnerUid;
|
||||||
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
|
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
|
||||||
mSSID = nc.mSSID;
|
mSSID = nc.mSSID;
|
||||||
mPrivateDnsBroken = nc.mPrivateDnsBroken;
|
mPrivateDnsBroken = nc.mPrivateDnsBroken;
|
||||||
@@ -810,31 +810,26 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UID of the app that manages this network, or INVALID_UID if none/unknown.
|
* UID of the app that owns this network, or INVALID_UID if none/unknown.
|
||||||
*
|
*
|
||||||
* This field keeps track of the UID of the app that created this network and is in charge
|
* <p>This field keeps track of the UID of the app that created this network and is in charge of
|
||||||
* of managing it. In the practice, it is used to store the UID of VPN apps so it is named
|
* its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
|
||||||
* accordingly, but it may be renamed if other mechanisms are offered for third party apps
|
* VPN, or Carrier Service app managing a cellular data connection.
|
||||||
* to create networks.
|
|
||||||
*
|
|
||||||
* Because this field is only used in the services side (and to avoid apps being able to
|
|
||||||
* set this to whatever they want), this field is not parcelled and will not be conserved
|
|
||||||
* across the IPC boundary.
|
|
||||||
* @hide
|
|
||||||
*/
|
*/
|
||||||
private int mEstablishingVpnAppUid = INVALID_UID;
|
private int mOwnerUid = Process.INVALID_UID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the UID of the managing app.
|
* Set the UID of the owner app.
|
||||||
* @hide
|
|
||||||
*/
|
*/
|
||||||
public void setEstablishingVpnAppUid(final int uid) {
|
public void setOwnerUid(final int uid) {
|
||||||
mEstablishingVpnAppUid = uid;
|
mOwnerUid = uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @hide */
|
/**
|
||||||
public int getEstablishingVpnAppUid() {
|
* Retrieves the UID of the owner app.
|
||||||
return mEstablishingVpnAppUid;
|
*/
|
||||||
|
public int getOwnerUid() {
|
||||||
|
return mOwnerUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1157,7 +1152,7 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
* member is null, then the network is not restricted by app UID. If it's an empty list, then
|
* member is null, then the network is not restricted by app UID. If it's an empty list, then
|
||||||
* it means nobody can use it.
|
* it means nobody can use it.
|
||||||
* As a special exception, the app managing this network (as identified by its UID stored in
|
* As a special exception, the app managing this network (as identified by its UID stored in
|
||||||
* mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in
|
* mOwnerUid) can always see this network. This is embodied by a special check in
|
||||||
* satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
|
* satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
|
||||||
* to the app that manages it as determined by #appliesToUid.
|
* to the app that manages it as determined by #appliesToUid.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -1264,7 +1259,7 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
* in the passed nc (representing the UIDs that this network is available to).
|
* in the passed nc (representing the UIDs that this network is available to).
|
||||||
* <p>
|
* <p>
|
||||||
* As a special exception, the UID that created the passed network (as represented by its
|
* As a special exception, the UID that created the passed network (as represented by its
|
||||||
* mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN
|
* mOwnerUid field) always satisfies a NetworkRequest requiring it (of LISTEN
|
||||||
* or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
|
* or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
|
||||||
* can see its own network when it listens for it.
|
* can see its own network when it listens for it.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -1275,7 +1270,7 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) {
|
public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) {
|
||||||
if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
|
if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
|
||||||
for (UidRange requiredRange : mUids) {
|
for (UidRange requiredRange : mUids) {
|
||||||
if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
|
if (requiredRange.contains(nc.mOwnerUid)) return true;
|
||||||
if (!nc.appliesToUidRange(requiredRange)) {
|
if (!nc.appliesToUidRange(requiredRange)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1541,6 +1536,7 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
dest.writeString(mSSID);
|
dest.writeString(mSSID);
|
||||||
dest.writeBoolean(mPrivateDnsBroken);
|
dest.writeBoolean(mPrivateDnsBroken);
|
||||||
dest.writeList(mAdministratorUids);
|
dest.writeList(mAdministratorUids);
|
||||||
|
dest.writeInt(mOwnerUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
|
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
|
||||||
@@ -1562,6 +1558,7 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
netCap.mSSID = in.readString();
|
netCap.mSSID = in.readString();
|
||||||
netCap.mPrivateDnsBroken = in.readBoolean();
|
netCap.mPrivateDnsBroken = in.readBoolean();
|
||||||
netCap.setAdministratorUids(in.readArrayList(null));
|
netCap.setAdministratorUids(in.readArrayList(null));
|
||||||
|
netCap.mOwnerUid = in.readInt();
|
||||||
return netCap;
|
return netCap;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
@@ -1611,8 +1608,8 @@ public final class NetworkCapabilities implements Parcelable {
|
|||||||
sb.append(" Uids: <").append(mUids).append(">");
|
sb.append(" Uids: <").append(mUids).append(">");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mEstablishingVpnAppUid != INVALID_UID) {
|
if (mOwnerUid != Process.INVALID_UID) {
|
||||||
sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
|
sb.append(" OwnerUid: ").append(mOwnerUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mAdministratorUids.isEmpty()) {
|
if (!mAdministratorUids.isEmpty()) {
|
||||||
|
|||||||
@@ -1625,7 +1625,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
|
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
|
||||||
}
|
}
|
||||||
|
|
||||||
private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
|
@VisibleForTesting
|
||||||
|
NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
|
||||||
NetworkCapabilities nc, int callerPid, int callerUid) {
|
NetworkCapabilities nc, int callerPid, int callerUid) {
|
||||||
final NetworkCapabilities newNc = new NetworkCapabilities(nc);
|
final NetworkCapabilities newNc = new NetworkCapabilities(nc);
|
||||||
if (!checkSettingsPermission(callerPid, callerUid)) {
|
if (!checkSettingsPermission(callerPid, callerUid)) {
|
||||||
@@ -1636,9 +1637,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
|
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
|
||||||
}
|
}
|
||||||
newNc.setAdministratorUids(Collections.EMPTY_LIST);
|
newNc.setAdministratorUids(Collections.EMPTY_LIST);
|
||||||
|
|
||||||
|
maybeSanitizeLocationInfoForCaller(newNc, callerUid);
|
||||||
|
|
||||||
return newNc;
|
return newNc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void maybeSanitizeLocationInfoForCaller(
|
||||||
|
NetworkCapabilities nc, int callerUid) {
|
||||||
|
// TODO(b/142072839): Conditionally reset the owner UID if the following
|
||||||
|
// conditions are not met:
|
||||||
|
// 1. The destination app is the network owner
|
||||||
|
// 2. The destination app has the ACCESS_COARSE_LOCATION permission granted
|
||||||
|
// if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted
|
||||||
|
// 3. The user's location toggle is on
|
||||||
|
nc.setOwnerUid(INVALID_UID);
|
||||||
|
}
|
||||||
|
|
||||||
private LinkProperties linkPropertiesRestrictedForCallerPermissions(
|
private LinkProperties linkPropertiesRestrictedForCallerPermissions(
|
||||||
LinkProperties lp, int callerPid, int callerUid) {
|
LinkProperties lp, int callerPid, int callerUid) {
|
||||||
if (lp == null) return new LinkProperties();
|
if (lp == null) return new LinkProperties();
|
||||||
@@ -1667,6 +1682,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
nc.setSingleUid(Binder.getCallingUid());
|
nc.setSingleUid(Binder.getCallingUid());
|
||||||
}
|
}
|
||||||
nc.setAdministratorUids(Collections.EMPTY_LIST);
|
nc.setAdministratorUids(Collections.EMPTY_LIST);
|
||||||
|
|
||||||
|
// Clear owner UID; this can never come from an app.
|
||||||
|
nc.setOwnerUid(INVALID_UID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
|
private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
|
||||||
@@ -5794,7 +5812,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Set<UidRange> ranges = nai.networkCapabilities.getUids();
|
final Set<UidRange> ranges = nai.networkCapabilities.getUids();
|
||||||
final int vpnAppUid = nai.networkCapabilities.getEstablishingVpnAppUid();
|
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,
|
||||||
// make eBPF support two whitelisted interfaces so here new rules can be added before the
|
// make eBPF support two whitelisted interfaces so here new rules can be added before the
|
||||||
@@ -5993,7 +6011,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (nc == null || lp == null) return false;
|
if (nc == null || lp == null) return false;
|
||||||
return nai.isVPN()
|
return nai.isVPN()
|
||||||
&& !nai.networkAgentConfig.allowBypass
|
&& !nai.networkAgentConfig.allowBypass
|
||||||
&& nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID
|
&& nc.getOwnerUid() != Process.SYSTEM_UID
|
||||||
&& lp.getInterfaceName() != null
|
&& lp.getInterfaceName() != null
|
||||||
&& (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
|
&& (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
|
||||||
}
|
}
|
||||||
@@ -6041,12 +6059,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
// TODO Fix this window by computing an accurate diff on Set<UidRange>, so the old range
|
// TODO Fix this window by computing an accurate diff on Set<UidRange>, so the old range
|
||||||
// to be removed will never overlap with the new range to be added.
|
// to be removed will never overlap with the new range to be added.
|
||||||
if (wasFiltering && !prevRanges.isEmpty()) {
|
if (wasFiltering && !prevRanges.isEmpty()) {
|
||||||
mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges,
|
mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, prevNc.getOwnerUid());
|
||||||
prevNc.getEstablishingVpnAppUid());
|
|
||||||
}
|
}
|
||||||
if (shouldFilter && !newRanges.isEmpty()) {
|
if (shouldFilter && !newRanges.isEmpty()) {
|
||||||
mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges,
|
mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, newNc.getOwnerUid());
|
||||||
newNc.getEstablishingVpnAppUid());
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Never crash!
|
// Never crash!
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ public class NetworkCapabilitiesTest {
|
|||||||
.setUids(uids)
|
.setUids(uids)
|
||||||
.addCapability(NET_CAPABILITY_EIMS)
|
.addCapability(NET_CAPABILITY_EIMS)
|
||||||
.addCapability(NET_CAPABILITY_NOT_METERED);
|
.addCapability(NET_CAPABILITY_NOT_METERED);
|
||||||
|
netCap.setOwnerUid(123);
|
||||||
assertParcelingIsLossless(netCap);
|
assertParcelingIsLossless(netCap);
|
||||||
netCap.setSSID(TEST_SSID);
|
netCap.setSSID(TEST_SSID);
|
||||||
assertParcelSane(netCap, 13);
|
assertParcelSane(netCap, 13);
|
||||||
|
|||||||
@@ -6313,12 +6313,24 @@ public class ConnectivityServiceTest {
|
|||||||
assertEquals(wifiLp, mService.getActiveLinkProperties());
|
assertEquals(wifiLp, mService.getActiveLinkProperties());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkCapabilitiesRestrictedForCallerPermissions() {
|
||||||
|
int callerUid = Process.myUid();
|
||||||
|
final NetworkCapabilities originalNc = new NetworkCapabilities();
|
||||||
|
originalNc.setOwnerUid(callerUid);
|
||||||
|
|
||||||
private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
|
final NetworkCapabilities newNc =
|
||||||
Set<UidRange> vpnRange) throws Exception {
|
mService.networkCapabilitiesRestrictedForCallerPermissions(
|
||||||
|
originalNc, Process.myPid(), callerUid);
|
||||||
|
|
||||||
|
assertEquals(Process.INVALID_UID, newNc.getOwnerUid());
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestNetworkAgentWrapper establishVpn(
|
||||||
|
LinkProperties lp, int ownerUid, Set<UidRange> vpnRange) throws Exception {
|
||||||
final TestNetworkAgentWrapper
|
final TestNetworkAgentWrapper
|
||||||
vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp);
|
vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp);
|
||||||
vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid);
|
vpnNetworkAgent.getNetworkCapabilities().setOwnerUid(ownerUid);
|
||||||
mMockVpn.setNetworkAgent(vpnNetworkAgent);
|
mMockVpn.setNetworkAgent(vpnNetworkAgent);
|
||||||
mMockVpn.connect();
|
mMockVpn.connect();
|
||||||
mMockVpn.setUids(vpnRange);
|
mMockVpn.setUids(vpnRange);
|
||||||
|
|||||||
Reference in New Issue
Block a user